From: Prashant Singh <singhpra@juniper.net>
To: Ard Biesheuvel <ardb@kernel.org>, Jeremy Kerr <jk@ozlabs.org>
Cc: <linux-efi@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
"Jonathan Corbet" <corbet@lwn.net>, <linux-doc@vger.kernel.org>,
"Sebastian Andrzej Siewior" <bigeasy@linutronix.de>,
Clark Williams <clrkwllms@kernel.org>,
Steven Rostedt <rostedt@goodmis.org>,
<linux-rt-devel@lists.linux.dev>,
Prashant Singh <singhpra@juniper.net>
Subject: [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
Date: Fri, 18 Sep 2026 21:41:24 -0700 [thread overview]
Message-ID: <20260919044124.8268-1-singhpra@juniper.net> (raw)
QueryVariableInfo() is an EFI runtime service that, on some firmware,
takes tens of milliseconds and runs with preemption disabled, stalling
the CPU that services it. efivarfs_statfs() calls it (rate-limited since
commit b2326338dc68 ("efivarfs: Rate limit statfs() handler")) to report
the variable-store used/available capacity, so any statfs(2) -- e.g.
every "df" -- can inject that stall into unrelated latency-sensitive
workloads on the same CPU.
Add a "nostatfs" mount option: when set, statfs(2) skips
QueryVariableInfo() entirely and reports zero used/available. It is set
by default on CONFIG_PREEMPT_RT so real-time kernels do not take the
stall out of the box.
Tested on an Intel Xeon E5-2628L v4, 6.12 kernel with CONFIG_PREEMPT_RT
not set (so reporting defaults to enabled and nostatfs must be passed
explicitly), via "strace -T -e trace=statfs df" on the efivarfs mount.
Default mount: statfs() calls QueryVariableInfo() and returns the real
store capacity, ~66-129 ms per call:
statfs("/sys/firmware/efi/efivars", {f_type=EFIVARFS_MAGIC,
f_bsize=1, f_blocks=90024, f_bfree=33387, f_bavail=28267, ...})
= 0 <0.129124>
With -o nostatfs: no firmware call, capacity reported as zero, ~11 us per
call:
statfs("/sys/firmware/efi/efivars", {f_type=EFIVARFS_MAGIC,
f_bsize=1, f_blocks=0, f_bfree=0, f_bavail=0, ...}) = 0 <0.000011>
Signed-off-by: Prashant Singh <singhpra@juniper.net>
---
Changes since v1:
- Per review, dropped the fs.efivarfs sysctl / cached-capacity approach
entirely; instead add a simple "nostatfs" mount option that skips
QueryVariableInfo() in statfs() and reports zero, set by default on
CONFIG_PREEMPT_RT.
v1: https://lore.kernel.org/all/20260917071600.5587-1-singhpra@juniper.net/
Documentation/filesystems/efivarfs.rst | 10 ++++++++++
fs/efivarfs/internal.h | 1 +
fs/efivarfs/super.c | 20 +++++++++++++++++---
3 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/Documentation/filesystems/efivarfs.rst b/Documentation/filesystems/efivarfs.rst
index f646c3f0980f..3ead638c796a 100644
--- a/Documentation/filesystems/efivarfs.rst
+++ b/Documentation/filesystems/efivarfs.rst
@@ -37,6 +37,16 @@ accidentally.
|4_bytes_of_attributes + efivar_data|
+-----------------------------------+
+Mount options
+=============
+
+nostatfs
+ Do not report the variable-store used/available capacity in
+ ``statfs(2)``; report zero instead. Obtaining the capacity requires the
+ ``QueryVariableInfo()`` EFI runtime service, which on some firmware takes
+ tens of milliseconds and runs with preemption disabled, stalling the
+ calling CPU. This option is set by default on ``CONFIG_PREEMPT_RT``.
+
*See also:*
- Documentation/admin-guide/acpi/ssdt-overlays.rst
diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h
index f913b6824289..0cb053884b4b 100644
--- a/fs/efivarfs/internal.h
+++ b/fs/efivarfs/internal.h
@@ -11,6 +11,7 @@
struct efivarfs_mount_opts {
kuid_t uid;
kgid_t gid;
+ bool nostatfs; /* skip QueryVariableInfo() in statfs() */
};
struct efivarfs_fs_info {
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index 8d33f11db2a1..fbdaa4915d30 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -74,6 +74,8 @@ static int efivarfs_show_options(struct seq_file *m, struct dentry *root)
if (!gid_eq(opts->gid, GLOBAL_ROOT_GID))
seq_printf(m, ",gid=%u",
from_kgid_munged(&init_user_ns, opts->gid));
+ if (opts->nostatfs)
+ seq_puts(m, ",nostatfs");
return 0;
}
@@ -82,13 +84,19 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
const u32 attr = EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS;
+ struct efivarfs_fs_info *sfi = dentry->d_sb->s_fs_info;
u64 storage_space, remaining_space, max_variable_size;
u64 id = huge_encode_dev(dentry->d_sb->s_dev);
efi_status_t status;
- /* Some UEFI firmware does not implement QueryVariableInfo() */
+ /*
+ * Some UEFI firmware does not implement QueryVariableInfo(); the
+ * nostatfs mount option also disables this (preempt-disabled,
+ * potentially slow) call entirely, reporting zero used/available.
+ */
storage_space = remaining_space = 0;
- if (efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO)) {
+ if (!sfi->mount_opts.nostatfs &&
+ efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO)) {
static DEFINE_RATELIMIT_STATE(_rs, 2 * HZ, 5);
static u64 storage, remaining;
static DEFINE_SPINLOCK(lock);
@@ -323,12 +331,13 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
}
enum {
- Opt_uid, Opt_gid,
+ Opt_uid, Opt_gid, Opt_nostatfs,
};
static const struct fs_parameter_spec efivarfs_parameters[] = {
fsparam_uid("uid", Opt_uid),
fsparam_gid("gid", Opt_gid),
+ fsparam_flag("nostatfs", Opt_nostatfs),
{},
};
@@ -350,6 +359,9 @@ static int efivarfs_parse_param(struct fs_context *fc, struct fs_parameter *para
case Opt_gid:
opts->gid = result.gid;
break;
+ case Opt_nostatfs:
+ opts->nostatfs = true;
+ break;
default:
return -EINVAL;
}
@@ -526,6 +538,8 @@ static int efivarfs_init_fs_context(struct fs_context *fc)
sfi->mount_opts.uid = GLOBAL_ROOT_UID;
sfi->mount_opts.gid = GLOBAL_ROOT_GID;
+ /* QueryVariableInfo() stalls the CPU; default nostatfs on PREEMPT_RT. */
+ sfi->mount_opts.nostatfs = IS_ENABLED(CONFIG_PREEMPT_RT);
fc->s_fs_info = sfi;
fc->ops = &efivarfs_context_ops;
base-commit: 9b87fdc9af2fbfcdb5c24a64139685ef80f6573f
--
2.34.1
next reply other threads:[~2026-09-19 4:41 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-19 4:41 Prashant Singh [this message]
2026-09-19 4:50 ` [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo() sashiko-bot
2026-09-19 14:51 ` Ard Biesheuvel
2026-09-24 10:56 ` Ard Biesheuvel
2026-09-24 11:05 ` Luis Claudio R. Goncalves
2026-09-24 11:12 ` Ard Biesheuvel
2026-09-24 11:19 ` Steve McIntyre
2026-09-24 11:36 ` Luis Claudio R. Goncalves
2026-09-24 11:59 ` Ard Biesheuvel
2026-09-25 1:45 ` Prashant Singh
2026-09-25 6:14 ` Sebastian Andrzej Siewior
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260919044124.8268-1-singhpra@juniper.net \
--to=singhpra@juniper.net \
--cc=ardb@kernel.org \
--cc=bigeasy@linutronix.de \
--cc=clrkwllms@kernel.org \
--cc=corbet@lwn.net \
--cc=jk@ozlabs.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.