Linux EFI development
 help / color / mirror / Atom feed
From: Anisse Astier <anisse@astier.eu>
To: Ard Biesheuvel <ardb@kernel.org>
Cc: linux-efi@vger.kernel.org, x86@kernel.org,
	stable@vger.kernel.org, Ravi Bangoria <ravi.bangoria@amd.com>
Subject: Re: [PATCH] efivarfs: Cache occupied and available space
Date: Mon, 17 Aug 2026 15:26:47 +0200	[thread overview]
Message-ID: <aoMMF_P6cdSII-8e@kanto> (raw)
In-Reply-To: <38e0e561-3b51-4c14-8e01-b8b7137199dc@app.fastmail.com>

Hi,

On Mon, Aug 17, 2026 at 03:11:40PM +0300, Ard Biesheuvel wrote:
> Hi,
> 
> Thanks for the review.
> 
> On Tue, 4 Aug 2026, at 19:01, Anisse Astier wrote:
> > Hi Ard,
> >
> > Please find a few comments below,
> >
> > On Sat, Aug 01, 2026 at 04:42:59PM +0200, Ard Biesheuvel wrote:
[snip]
> >> diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
> >> index 733c19571f1c..3691a2a087a0 100644
> >> --- a/fs/efivarfs/super.c
> >> +++ b/fs/efivarfs/super.c
> >> @@ -23,6 +23,8 @@
> >>  #include "internal.h"
> >>  #include "../internal.h"
> >>  
> >> +u64 efivar_storage_space, efivar_remaining_space;
> >> +
> > Since those are globals (before they were only local to the function),
> > I'd put them behind a lock now, probably efivar_lock, because we need
> > something that's globally available.
> >
> > statfs could be raced from userspace vs the rest of the code; and
> > efivar_invalidate_cached_storage_space is only called outside the lock.
> >
> 
> Right. So we might inadvertently report zero size and zero available
> space even though QueryVariableInfo() is supported and working correctly.
> Not the end of the world imo, but better avoided if we can.

Yes, I don't think it's that performance sensitive (famous last words),
so putting it all behind a lock is a cheap way to avoid this type of
issue (unless you have a better idea?).

> 
> 
> >>  static int efivarfs_ops_notifier(struct notifier_block *nb, unsigned long event,
> >>  				 void *data)
> >>  {
> >> @@ -82,15 +84,16 @@ 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;
> >> -	u64 storage_space, remaining_space, max_variable_size;
> >>  	u64 id = huge_encode_dev(dentry->d_sb->s_dev);
> >> +	u64 max_variable_size;
> >>  	efi_status_t status;
> >>  
> >>  	/* Some UEFI firmware does not implement QueryVariableInfo() */
> >> -	storage_space = remaining_space = 0;
> >> -	if (efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO)) {
> >> -		status = efivar_query_variable_info(attr, &storage_space,
> >> -						    &remaining_space,
> >> +	if (efivar_storage_space == 0 &&
> >> +	    efivar_remaining_space == 0 &&
> >> +	    efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO)) {
> >> +		status = efivar_query_variable_info(attr, &efivar_storage_space,
> >> +						    &efivar_remaining_space,
> >>  						    &max_variable_size);
> >>  		if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED)
> >>  			pr_warn_ratelimited("query_variable_info() failed: 0x%lx\n",
> >
> > We've had issues with firmware in the past, shouldn't we be a bit more
> > defensive here in case of errors? I'd reset both variables on error in
> > case an incomplete write to one of the variables gives us an invalid state.
> >
> 
> This is a pre-existing issue, right? The only difference being the fact that
> the variables are now globals?

Yes and no. Before, a bad value might be returned once. Now, it might
get inadvertently cached and returned until the next variable
modification.

Yes, this is an edge case, but I think it can be worked around very
easily by either implementing the suggestion above, or simply writing
the values to other temporary variables, and updating the global ones on
success.

> >> @@ -480,6 +486,8 @@ int efivar_entry_delete(struct efivar_entry *entry)
> >>  					    &entry->var.VendorGuid,
> >>  					    0, 0, NULL, false);
> >>  	efivar_unlock();
> >> +	efivar_invalidate_cached_storage_space();
> >> +
> >>  	if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND))
> >>  		return efi_status_to_err(status);
> >>  
> >> @@ -620,6 +628,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
> >>  				    NULL, size, NULL);
> >>  
> >>  	efivar_unlock();
> >> +	efivar_invalidate_cached_storage_space();
> >
> > In this function, the error path for efi_set_variable_locked (that could
> > have triggered an EFI_OUT_OF_RESOURCES) is not covered by the
> > invalidation.
> >
> 
> Right. So under the assumption that the state of the EFI variable store
> might change even after a failed SetVariable(), the cached values may
> have become inaccurate. Is that what you are saying?

Yes, the actual free space might change but failed to be updated.

> 
> >>  
> >>  	if (status && status != EFI_BUFFER_TOO_SMALL)
> >>  		return efi_status_to_err(status);
> >> -- 
> >
> > Couldn't the variables be written outside of efivarfs as well?
> > efivar_set_variable can be called from other code? pstore could maybe be
> > ignored if it's only used during crashes (I'm not sure), but I see at
> > least one other driver calling it as well. Wouldn't that change the
> > available/free size?
> >
> 
> Yeah, that is a very good point.
> 

FYI, since this patch was initially merged, it helped us catch errors in
production *twice* thanks to existing monitoring on filesystem free
space: bad configurations or logic that wrote too many variables.

I can also see why this type of regular monitoring triggering SMM
rendez-vous of all CPUs might be bad for performance.

Regards,

Anisse

      reply	other threads:[~2026-08-17 13:26 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-01 14:42 [PATCH] efivarfs: Cache occupied and available space Ard Biesheuvel
2026-08-04 10:02 ` Ard Biesheuvel
2026-08-04 16:01 ` Anisse Astier
2026-08-17 12:11   ` Ard Biesheuvel
2026-08-17 13:26     ` Anisse Astier [this message]

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=aoMMF_P6cdSII-8e@kanto \
    --to=anisse@astier.eu \
    --cc=ardb@kernel.org \
    --cc=linux-efi@vger.kernel.org \
    --cc=ravi.bangoria@amd.com \
    --cc=stable@vger.kernel.org \
    --cc=x86@kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox