mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
@ 2026-09-19  4:41 Prashant Singh
  2026-09-19  4:50 ` sashiko-bot
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ 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] 9+ 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
  2026-09-24 11:05 ` Luis Claudio R. Goncalves
  2 siblings, 0 replies; 9+ 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] 9+ 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
  2026-09-24 10:56   ` Ard Biesheuvel
  2026-09-24 11:05 ` Luis Claudio R. Goncalves
  2 siblings, 1 reply; 9+ 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] 9+ messages in thread

* Re: [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
  2026-09-19 14:51 ` Ard Biesheuvel
@ 2026-09-24 10:56   ` Ard Biesheuvel
  0 siblings, 0 replies; 9+ messages in thread
From: Ard Biesheuvel @ 2026-09-24 10:56 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 16:51, Ard Biesheuvel wrote:
> 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.

Queued up in efi/next now -- thanks.

^ permalink raw reply	[flat|nested] 9+ 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
@ 2026-09-24 11:05 ` Luis Claudio R. Goncalves
  2026-09-24 11:12   ` Ard Biesheuvel
  2026-09-24 11:19   ` Steve McIntyre
  2 siblings, 2 replies; 9+ messages in thread
From: Luis Claudio R. Goncalves @ 2026-09-24 11:05 UTC (permalink / raw)
  To: Prashant Singh
  Cc: Ard Biesheuvel, Jeremy Kerr, linux-efi, linux-kernel,
	Jonathan Corbet, linux-doc, Sebastian Andrzej Siewior,
	Clark Williams, Steven Rostedt, linux-rt-devel

On Fri, Sep 18, 2026 at 09:41:24PM -0700, 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.

I tested the patch and was quite satisfied with the results, but upon a
comment from colleagues I ran a few more tests and noticed (confirmed their
hunch) that fwupd complains about not being able to get the free space in
efivars:

  # fwupdmgr get-devices | grep efivars
  │     Update Error:       getting efivars free space is not supported
  │ │   Update Error:       getting efivars free space is not supported
  ...

I was not able to establish whether that would prevent specific operations
due to the HW I had available for such test.

One idea that I have been musing over is whether or not it would be interesting
to create a static view of the efivars statfs data when first mounting it
and updating this data whenever efivars is modified (create/write/delete).
Does that sound reasonable?

Luis
 
> 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
> 
> 
---end quoted text---


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
  2026-09-24 11:05 ` Luis Claudio R. Goncalves
@ 2026-09-24 11:12   ` Ard Biesheuvel
  2026-09-24 11:19   ` Steve McIntyre
  1 sibling, 0 replies; 9+ messages in thread
From: Ard Biesheuvel @ 2026-09-24 11:12 UTC (permalink / raw)
  To: Luis Claudio R. Goncalves, Prashant Singh
  Cc: Jeremy Kerr, linux-efi, linux-kernel, Jonathan Corbet, linux-doc,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	linux-rt-devel



On Thu, 24 Sep 2026, at 13:05, Luis Claudio R. Goncalves wrote:
> On Fri, Sep 18, 2026 at 09:41:24PM -0700, 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.
>
> I tested the patch and was quite satisfied with the results, but upon a
> comment from colleagues I ran a few more tests and noticed (confirmed their
> hunch) that fwupd complains about not being able to get the free space in
> efivars:
>
>   # fwupdmgr get-devices | grep efivars
>   │     Update Error:       getting efivars free space is not supported
>   │ │   Update Error:       getting efivars free space is not supported
>   ...
>
> I was not able to establish whether that would prevent specific operations
> due to the HW I had available for such test.
>

We might have to teach fwupdmgr to check the efivarfs mount flags and remount
it if it requires this information. We should check whether that is possible
with the current version of the patch.

> One idea that I have been musing over is whether or not it would be interesting
> to create a static view of the efivars statfs data when first mounting it
> and updating this data whenever efivars is modified (create/write/delete).
> Does that sound reasonable?
>

efivarfs is not the only component setting EFI variables. You would also have to
hook every caller of efivar_set_variable() as well as efi.set_variable().


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
  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
  1 sibling, 1 reply; 9+ messages in thread
From: Steve McIntyre @ 2026-09-24 11:19 UTC (permalink / raw)
  To: Luis Claudio R. Goncalves
  Cc: Prashant Singh, Ard Biesheuvel, Jeremy Kerr, linux-efi,
	linux-kernel, Jonathan Corbet, linux-doc,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	linux-rt-devel

Hey all,

On Thu, Sep 24, 2026 at 08:05:34AM -0300, Luis Claudio R. Goncalves wrote:
>On Fri, Sep 18, 2026 at 09:41:24PM -0700, Prashant Singh wrote:
>
>I tested the patch and was quite satisfied with the results, but upon a
>comment from colleagues I ran a few more tests and noticed (confirmed their
>hunch) that fwupd complains about not being able to get the free space in
>efivars:
>
>  # fwupdmgr get-devices | grep efivars
>  │     Update Error:       getting efivars free space is not supported
>  │ │   Update Error:       getting efivars free space is not supported
>  ...
>
>I was not able to establish whether that would prevent specific operations
>due to the HW I had available for such test.

fwupd will refuse to do some of its updates if it can't read the
efivars free space, in particular updates of the secure boot keyrings
like KEK/DB/DBX.

-- 
Steve McIntyre, Cambridge, UK.                                93sam@debian.org


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
  2026-09-24 11:19   ` Steve McIntyre
@ 2026-09-24 11:36     ` Luis Claudio R. Goncalves
  2026-09-24 11:59       ` Ard Biesheuvel
  0 siblings, 1 reply; 9+ messages in thread
From: Luis Claudio R. Goncalves @ 2026-09-24 11:36 UTC (permalink / raw)
  To: Steve McIntyre
  Cc: Prashant Singh, Ard Biesheuvel, Jeremy Kerr, linux-efi,
	linux-kernel, Jonathan Corbet, linux-doc,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	linux-rt-devel

On Thu, Sep 24, 2026 at 12:19:23PM +0100, Steve McIntyre wrote:
> Hey all,
> 
> On Thu, Sep 24, 2026 at 08:05:34AM -0300, Luis Claudio R. Goncalves wrote:
> >On Fri, Sep 18, 2026 at 09:41:24PM -0700, Prashant Singh wrote:
> >
> >I tested the patch and was quite satisfied with the results, but upon a
> >comment from colleagues I ran a few more tests and noticed (confirmed their
> >hunch) that fwupd complains about not being able to get the free space in
> >efivars:
> >
> >  # fwupdmgr get-devices | grep efivars
> >  │     Update Error:       getting efivars free space is not supported
> >  │ │   Update Error:       getting efivars free space is not supported
> >  ...
> >
> >I was not able to establish whether that would prevent specific operations
> >due to the HW I had available for such test.
> 
> fwupd will refuse to do some of its updates if it can't read the
> efivars free space, in particular updates of the secure boot keyrings
> like KEK/DB/DBX.

In this case, corroborating with Sashiko findings, it is necessary to have
a way to override that default in kernels with PREEMPT_RT enabled. To be used
where this is required for firmware updates.

Luis

> -- 
> Steve McIntyre, Cambridge, UK.                                93sam@debian.org
> 
> 
---end quoted text---


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v2] efivarfs: add nostatfs mount option to skip QueryVariableInfo()
  2026-09-24 11:36     ` Luis Claudio R. Goncalves
@ 2026-09-24 11:59       ` Ard Biesheuvel
  0 siblings, 0 replies; 9+ messages in thread
From: Ard Biesheuvel @ 2026-09-24 11:59 UTC (permalink / raw)
  To: Luis Claudio R. Goncalves, Steve McIntyre
  Cc: Prashant Singh, Jeremy Kerr, linux-efi, linux-kernel,
	Jonathan Corbet, linux-doc, Sebastian Andrzej Siewior,
	Clark Williams, Steven Rostedt, linux-rt-devel



On Thu, 24 Sep 2026, at 13:36, Luis Claudio R. Goncalves wrote:
> On Thu, Sep 24, 2026 at 12:19:23PM +0100, Steve McIntyre wrote:
>> Hey all,
>> 
>> On Thu, Sep 24, 2026 at 08:05:34AM -0300, Luis Claudio R. Goncalves wrote:
>> >On Fri, Sep 18, 2026 at 09:41:24PM -0700, Prashant Singh wrote:
>> >
>> >I tested the patch and was quite satisfied with the results, but upon a
>> >comment from colleagues I ran a few more tests and noticed (confirmed their
>> >hunch) that fwupd complains about not being able to get the free space in
>> >efivars:
>> >
>> >  # fwupdmgr get-devices | grep efivars
>> >  │     Update Error:       getting efivars free space is not supported
>> >  │ │   Update Error:       getting efivars free space is not supported
>> >  ...
>> >
>> >I was not able to establish whether that would prevent specific operations
>> >due to the HW I had available for such test.
>> 
>> fwupd will refuse to do some of its updates if it can't read the
>> efivars free space, in particular updates of the secure boot keyrings
>> like KEK/DB/DBX.
>
> In this case, corroborating with Sashiko findings, it is necessary to have
> a way to override that default in kernels with PREEMPT_RT enabled. To be used
> where this is required for firmware updates.
>

Indeed.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-09-24 11:59 UTC | newest]

Thread overview: 9+ 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
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

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®