* [PATCH v5] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
@ 2026-10-05 23:22 Prashant Singh
2026-10-06 7:09 ` Ard Biesheuvel
0 siblings, 1 reply; 3+ messages in thread
From: Prashant Singh @ 2026-10-05 23:22 UTC (permalink / raw)
To: Jeremy Kerr, Ard Biesheuvel, Sebastian Andrzej Siewior
Cc: Clark Williams, Steven Rostedt, Jonathan Corbet, Shuah Khan,
Randy Dunlap, Luis Claudio R . Goncalves, Steve McIntyre,
joaoanandalima, linux-efi, linux-kernel, linux-doc,
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 (and, on firmware that services it via SMM, all
CPUs). 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.
Add a negatable "nostatfs" mount option: with nostatfs, statfs(2) skips
QueryVariableInfo() and reports zero used/available; with statfs it
reports the capacity as before. It defaults to nostatfs on
CONFIG_PREEMPT_RT so real-time kernels do not take the stall out of the
box, but statfs can be passed there to force reporting back on -- e.g.
for tools such as fwupd that need the efivars free space to update Secure
Boot key databases.
The option can also be toggled on a live mount via remount, so reporting
can be enabled only for the duration of a firmware update without
unmounting the boot-time efivarfs mount:
mount -o remount,statfs /sys/firmware/efi/efivars # reporting on
mount -o remount,nostatfs /sys/firmware/efi/efivars # reporting off
A remount that does not specify statfs/nostatfs keeps the current setting.
Tested on an Intel Xeon E5-2628L v4, 6.12 kernel: a default statfs(2)
takes ~66 ms (the firmware call), versus ~11 us with nostatfs.
Suggested-by: Ard Biesheuvel <ardb@kernel.org>
Suggested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Prashant Singh <singhpra@juniper.net>
---
Changes since v4:
- Trim the commit message: drop the per-call strace dumps, keep the
preemption-disabled rationale (Ard, Sebastian).
- Replace the inconsistent READ_ONCE/WRITE_ONCE on nostatfs with a single
data_race() on the reconfigure write; the lockless reads stay plain
(Ard, Sebastian).
- Minor doc/comment cleanups.
Changes since v3:
- Drop the show_options "statfs" branch; the absence of "nostatfs" now
indicates reporting is on (Ard Biesheuvel).
- Drop the uid/gid copies on the remount path; efivarfs_reconfigure()
applies only nostatfs, so they were dead code (Ard Biesheuvel).
Changes since v2:
- Make the flag negatable (fsparam_flag_no): "statfs" forces reporting
back on, "nostatfs" skips QueryVariableInfo(). Default stays nostatfs
on PREEMPT_RT. This lets fwupd get the efivars free space it needs for
Secure Boot key (KEK/DB/DBX) updates on an RT kernel by mounting with
-o statfs (Luis Claudio R. Goncalves, Steve McIntyre).
- Support toggling the option on a live mount via remount, so reporting
can be enabled just for a firmware update without unmounting efivarfs
(Sebastian Andrzej Siewior). Options not respecified on remount are
preserved.
- Add PREEMPT_RT + remount test data to the commit message.
Changes since v1:
- Replace the sysctl with a mount option named "nostatfs", per review
(Ard Biesheuvel).
v1: https://lore.kernel.org/all/20260917071600.5587-1-singhpra@juniper.net/
v2: https://lore.kernel.org/all/20260919044124.8268-1-singhpra@juniper.net/
v3: https://lore.kernel.org/all/20260925113145.7396-1-singhpra@juniper.net/
v4: https://lore.kernel.org/all/20260928203445.72318-1-singhpra@juniper.net/
Documentation/filesystems/efivarfs.rst | 12 +++++++++
fs/efivarfs/internal.h | 1 +
fs/efivarfs/super.c | 36 ++++++++++++++++++++++----
3 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/Documentation/filesystems/efivarfs.rst b/Documentation/filesystems/efivarfs.rst
index f646c3f0980f..23164464ca2b 100644
--- a/Documentation/filesystems/efivarfs.rst
+++ b/Documentation/filesystems/efivarfs.rst
@@ -37,6 +37,18 @@ accidentally.
|4_bytes_of_attributes + efivar_data|
+-----------------------------------+
+Mount options
+=============
+
+========== ==================================================================
+(no)statfs Control whether ``statfs(2)`` reports the variable-store
+ used/available. Disabling it skips the ``QueryVariableInfo()``
+ EFI runtime service call, which might block all CPUs for a few
+ milliseconds, and reports 0/0 for used/available instead.
+ Defaults to ``statfs``, except on ``CONFIG_PREEMPT_RT`` where
+ it defaults to ``nostatfs``.
+========== ==================================================================
+
*See also:*
- Documentation/admin-guide/acpi/ssdt-overlays.rst
diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h
index f913b6824289..f5c1a25be996 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;
};
struct efivarfs_fs_info {
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index 8d33f11db2a1..12746ced6dc6 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,18 @@ 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() */
+ /*
+ * With nostatfs, or on firmware that does not implement
+ * QueryVariableInfo(), report 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 +330,13 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
}
enum {
- Opt_uid, Opt_gid,
+ Opt_uid, Opt_gid, Opt_statfs,
};
static const struct fs_parameter_spec efivarfs_parameters[] = {
fsparam_uid("uid", Opt_uid),
fsparam_gid("gid", Opt_gid),
+ fsparam_flag_no("statfs", Opt_statfs),
{},
};
@@ -350,6 +358,9 @@ static int efivarfs_parse_param(struct fs_context *fc, struct fs_parameter *para
case Opt_gid:
opts->gid = result.gid;
break;
+ case Opt_statfs:
+ opts->nostatfs = result.negated;
+ break;
default:
return -EINVAL;
}
@@ -402,11 +413,17 @@ static int efivarfs_get_tree(struct fs_context *fc)
static int efivarfs_reconfigure(struct fs_context *fc)
{
+ struct efivarfs_fs_info *sfi = fc->root->d_sb->s_fs_info;
+ struct efivarfs_fs_info *new_sfi = fc->s_fs_info;
+
if (!efivar_supports_writes() && !(fc->sb_flags & SB_RDONLY)) {
pr_err("Firmware does not support SetVariableRT. Can not remount with rw\n");
return -EINVAL;
}
+ /* statfs()/show_options() read nostatfs locklessly; benign race. */
+ data_race(sfi->mount_opts.nostatfs = new_sfi->mount_opts.nostatfs);
+
return 0;
}
@@ -524,8 +541,17 @@ static int efivarfs_init_fs_context(struct fs_context *fc)
if (!sfi)
return -ENOMEM;
- sfi->mount_opts.uid = GLOBAL_ROOT_UID;
- sfi->mount_opts.gid = GLOBAL_ROOT_GID;
+ if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
+ /* nostatfs is writable via remount; keep it if not respecified. */
+ struct efivarfs_fs_info *old = fc->root->d_sb->s_fs_info;
+
+ sfi->mount_opts.nostatfs = old->mount_opts.nostatfs;
+ } else {
+ 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;
--
2.34.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v5] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
2026-10-05 23:22 [PATCH v5] efivarfs: add nostatfs mount option to skip QueryVariableInfo() Prashant Singh
@ 2026-10-06 7:09 ` Ard Biesheuvel
2026-10-06 8:41 ` Prashant Singh
0 siblings, 1 reply; 3+ messages in thread
From: Ard Biesheuvel @ 2026-10-06 7:09 UTC (permalink / raw)
To: Prashant Singh, Jeremy Kerr, Sebastian Andrzej Siewior
Cc: Clark Williams, Steven Rostedt, Jonathan Corbet, Shuah Khan,
Randy Dunlap, Luis Claudio R. Goncalves, Steve McIntyre,
joaoanandalima, linux-efi, linux-kernel, linux-doc,
linux-rt-devel
Hello Prashant,
Thanks for respinning this.
On Tue, 6 Oct 2026, at 01:22, 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 (and, on firmware that services it via SMM, all
> CPUs). 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.
>
> Add a negatable "nostatfs" mount option: with nostatfs, statfs(2) skips
> QueryVariableInfo() and reports zero used/available; with statfs it
> reports the capacity as before. It defaults to nostatfs on
> CONFIG_PREEMPT_RT so real-time kernels do not take the stall out of the
> box, but statfs can be passed there to force reporting back on -- e.g.
> for tools such as fwupd that need the efivars free space to update Secure
> Boot key databases.
>
> The option can also be toggled on a live mount via remount, so reporting
> can be enabled only for the duration of a firmware update without
> unmounting the boot-time efivarfs mount:
>
> mount -o remount,statfs /sys/firmware/efi/efivars # reporting on
> mount -o remount,nostatfs /sys/firmware/efi/efivars # reporting off
>
> A remount that does not specify statfs/nostatfs keeps the current setting.
>
So what happens with uid= /gid= in this case. Do they get reset to the
default or not? And before this patch?
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v5] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
2026-10-06 7:09 ` Ard Biesheuvel
@ 2026-10-06 8:41 ` Prashant Singh
0 siblings, 0 replies; 3+ messages in thread
From: Prashant Singh @ 2026-10-06 8:41 UTC (permalink / raw)
To: Ard Biesheuvel, Jeremy Kerr, Sebastian Andrzej Siewior
Cc: Prashant Singh, Clark Williams, Steven Rostedt, Jonathan Corbet,
Shuah Khan, Randy Dunlap, Luis Claudio R. Goncalves,
Steve McIntyre, joaoanandalima, linux-efi, linux-kernel,
linux-doc, linux-rt-devel
On Tue, 06 Oct 2026 09:09:33 +0200, Ard Biesheuvel wrote:
> So what happens with uid=/gid= in this case. Do they get reset to the
> default or not? And before this patch?
Preserved, not reset to the GLOBAL_ROOT default -- and unchanged from
before this patch.
efivarfs_reconfigure() applies only nostatfs to the live superblock; it
never touches uid/gid. uid/gid are parsed in efivarfs_parse_param() and
stamped onto inodes at creation in efivarfs_get_inode() (inode->i_uid/i_gid
= opts->uid/gid); reconfigure() has never re-applied them, so they are
effectively mount-time-only. A uid=/gid= given on remount lands in the
throwaway reconfigure fs_context and is ignored -- the live inodes and
show_options keep the original mount values.
Before this patch efivarfs_reconfigure() only had the ro/rw guard
(efivar_supports_writes()) and never applied uid/gid, so there is no
behavioural change; the patch only adds the nostatfs line.
Verified on 6.12 (Xeon), identical on a stock 6.12 without the patch:
mount -o uid=1000,gid=1000 -> uid=1000,gid=1000 (opts + inode owner)
mount -o remount -> still 1000:1000 (preserved)
mount -o remount,uid=2000 -> still 1000:1000 (ignored)
Thanks,
Prashant
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-06 8:43 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-05 23:22 [PATCH v5] efivarfs: add nostatfs mount option to skip QueryVariableInfo() Prashant Singh
2026-10-06 7:09 ` Ard Biesheuvel
2026-10-06 8:41 ` Prashant Singh
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®