* [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
@ 2026-09-19 4:41 Prashant Singh
2026-09-19 4:50 ` sashiko-bot
2026-09-19 14:51 ` Ard Biesheuvel
0 siblings, 2 replies; 3+ messages in thread
From: Prashant Singh @ 2026-09-19 4:41 UTC (permalink / raw)
To: Ard Biesheuvel, Jeremy Kerr
Cc: linux-efi, linux-kernel, Jonathan Corbet, linux-doc,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
linux-rt-devel, Prashant Singh
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
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
2026-09-19 4:41 [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo() Prashant Singh
@ 2026-09-19 4:50 ` sashiko-bot
2026-09-19 14:51 ` Ard Biesheuvel
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-09-19 4:50 UTC (permalink / raw)
To: Prashant Singh; +Cc: linux-rt-devel, linux-kernel
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] efivarfs: cannot disable nostatfs on PREEMPT_RT kernels
--
commit d9f40eeab38e7ccb1227aacdbea972e4b143d97c
Author: Prashant Singh <singhpra@juniper.net>
Subject: efivarfs: add nostatfs mount option to skip QueryVariableInfo()
This commit introduces a "nostatfs" mount option to efivarfs to skip calling
the slow QueryVariableInfo() EFI runtime service during statfs(). On kernels
built with CONFIG_PREEMPT_RT, this option is enabled by default to avoid
stalling the CPU.
Link: https://lore.kernel.org/all/20260917071600.5587-1-singhpra@juniper.net/
> diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
> index 8d33f11db2a1b..fbdaa4915d303 100644
> --- a/fs/efivarfs/super.c
> +++ b/fs/efivarfs/super.c
[ ... ]
> @@ -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),
> {},
> };
[Severity: Medium]
Does this omit the ability to specify the inverse of the option?
Only the positive flag is registered with the parser here in
efivarfs_parameters, which means there is no way to explicitly pass a
negated option during mount.
[ ... ]
> @@ -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;
> }
[Severity: Medium]
Is there a way for users to explicitly request statfs to be enabled?
There is no corresponding case in efivarfs_parse_param() to set
opts->nostatfs = false (for example, via a "statfs" option).
[ ... ]
> @@ -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;
[Severity: Medium]
Since the flag is enabled by default in efivarfs_init_fs_context() on
PREEMPT_RT kernels, and the parser has no mechanism to clear it, does this
permanently lock administrators out of checking EFI variable capacity
via statfs() on those systems?
Would it make sense to define a negative flag using fsparam_flag_no() so
administrators can override the CONFIG_PREEMPT_RT default if they need to
monitor the capacity and are willing to accept the stall?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260919044124.8268-1-singhpra@juniper.net?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
2026-09-19 4:41 [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo() Prashant Singh
2026-09-19 4:50 ` sashiko-bot
@ 2026-09-19 14:51 ` Ard Biesheuvel
1 sibling, 0 replies; 3+ messages in thread
From: Ard Biesheuvel @ 2026-09-19 14:51 UTC (permalink / raw)
To: Prashant Singh, Jeremy Kerr
Cc: linux-efi, linux-kernel, Jonathan Corbet, linux-doc,
Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
linux-rt-devel
On Sat, 19 Sep 2026, at 06:41, Prashant Singh wrote:
> 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;
>
This looks good to me but I'll leave some time for other folks to comment.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-19 14:52 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-19 4:41 [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo() Prashant Singh
2026-09-19 4:50 ` sashiko-bot
2026-09-19 14:51 ` Ard Biesheuvel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®