Currently, when setting efi variables through the runtime service, efivarfs cannot sync variable updates properly. Introduce efivarfs refresh remount to support efivarfs information updates from other sources. Signed-off-by: Weizhao Ouyang <o451686892@xxxxxxxxx> --- Documentation/filesystems/efivarfs.rst | 6 ++++ fs/efivarfs/super.c | 40 +++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/Documentation/filesystems/efivarfs.rst b/Documentation/filesystems/efivarfs.rst index f646c3f0980f..58461e02ad01 100644 --- a/Documentation/filesystems/efivarfs.rst +++ b/Documentation/filesystems/efivarfs.rst @@ -18,6 +18,12 @@ efivarfs is typically mounted like this:: mount -t efivarfs none /sys/firmware/efi/efivars +To support efivar updates from other sources (efi_test ioctl, runtime +driver, etc.), set ``efivarfs.refresh=1``. After that, remount will +update the efivar information in efivarfs, like this:: + + mount -t efivarfs none /sys/firmware/efi/efivars -o remount + Due to the presence of numerous firmware bugs where removing non-standard UEFI variables causes the system firmware to fail to POST, efivarfs files that are not well-known standardized variables are created diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index beba15673be8..7ae22ca120e3 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -277,6 +277,44 @@ static const struct fs_parameter_spec efivarfs_parameters[] = { {}, }; +static bool efivarfs_refresh_default __read_mostly; +module_param_named(refresh, efivarfs_refresh_default, bool, 0444); + +static void efivarfs_clean_dentry(struct dentry *dentry) +{ + struct dentry *child; + + if (!dentry) + return; + + if (d_is_dir(dentry)) { + spin_lock(&dentry->d_lock); + hlist_for_each_entry(child, &dentry->d_children, d_sib) { + if (child) + efivarfs_clean_dentry(child); + } + spin_unlock(&dentry->d_lock); + } else { + d_invalidate(dentry); + } +} + +static int efivarfs_refresh(struct fs_context *fc) +{ + struct efivarfs_fs_info *sbi = fc->s_fs_info; + + if (!efivarfs_refresh_default) + return 0; + + if (!fc->root) + return -EINVAL; + + efivarfs_clean_dentry(fc->root); + efivar_init(efivarfs_callback, fc->root->d_sb, &sbi->efivarfs_list); + + return 0; +} + static int efivarfs_parse_param(struct fs_context *fc, struct fs_parameter *param) { struct efivarfs_fs_info *sbi = fc->s_fs_info; @@ -351,7 +389,7 @@ static int efivarfs_reconfigure(struct fs_context *fc) return -EINVAL; } - return 0; + return efivarfs_refresh(fc); } static const struct fs_context_operations efivarfs_context_ops = { -- 2.45.2