Re: [RFC PATCH 3/3] efivarfs: replace iterate_dir with libfs function simple_iterate_call

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 18 Mar 2025 at 20:46, James Bottomley
<James.Bottomley@xxxxxxxxxxxxxxxxxxxxx> wrote:
>
> This relieves us of the requirement to have a struct path and use file
> operations, which greatly simplifies the code.  The superblock is now
> pinned by the blocking notifier (which is why deregistration moves
> above kill_litter_super).
>
> Signed-off-by: James Bottomley <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx>
> ---
>  fs/efivarfs/super.c | 103 +++-----------------------------------------
>  1 file changed, 7 insertions(+), 96 deletions(-)
>

I like this a lot. Assuming it gets blessed by the VFS maintainers,

Reviewed-by: Ard Biesheuvel <ardb@xxxxxxxxxx>

> diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
> index 81b3c6b7e100..135b0bb9b4b5 100644
> --- a/fs/efivarfs/super.c
> +++ b/fs/efivarfs/super.c
> @@ -393,29 +393,13 @@ static const struct fs_context_operations efivarfs_context_ops = {
>         .reconfigure    = efivarfs_reconfigure,
>  };
>
> -struct efivarfs_ctx {
> -       struct dir_context ctx;
> -       struct super_block *sb;
> -       struct dentry *dentry;
> -};
> -
> -static bool efivarfs_actor(struct dir_context *ctx, const char *name, int len,
> -                          loff_t offset, u64 ino, unsigned mode)
> +static bool efivarfs_iterate_callback(void *data, struct dentry *dentry)
>  {
>         unsigned long size;
> -       struct efivarfs_ctx *ectx = container_of(ctx, struct efivarfs_ctx, ctx);
> -       struct qstr qstr = { .name = name, .len = len };
> -       struct dentry *dentry = d_hash_and_lookup(ectx->sb->s_root, &qstr);
> -       struct inode *inode;
> -       struct efivar_entry *entry;
> +       struct inode *inode = d_inode(dentry);
> +       struct efivar_entry *entry = efivar_entry(inode);
>         int err;
>
> -       if (IS_ERR_OR_NULL(dentry))
> -               return true;
> -
> -       inode = d_inode(dentry);
> -       entry = efivar_entry(inode);
> -
>         err = efivar_entry_size(entry, &size);
>         size += sizeof(__u32);  /* attributes */
>         if (err)
> @@ -426,12 +410,10 @@ static bool efivarfs_actor(struct dir_context *ctx, const char *name, int len,
>         inode_unlock(inode);
>
>         if (!size) {
> -               ectx->dentry = dentry;
> -               return false;
> +               pr_info("efivarfs: removing variable %pd\n", dentry);
> +               simple_recursive_removal(dentry, NULL);
>         }
>
> -       dput(dentry);
> -
>         return true;
>  }
>
> @@ -474,33 +456,11 @@ static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
>         return err;
>  }
>
> -static void efivarfs_deactivate_super_work(struct work_struct *work)
> -{
> -       struct super_block *s = container_of(work, struct super_block,
> -                                            destroy_work);
> -       /*
> -        * note: here s->destroy_work is free for reuse (which
> -        * will happen in deactivate_super)
> -        */
> -       deactivate_super(s);
> -}
> -
> -static struct file_system_type efivarfs_type;
> -
>  static int efivarfs_pm_notify(struct notifier_block *nb, unsigned long action,
>                               void *ptr)
>  {
>         struct efivarfs_fs_info *sfi = container_of(nb, struct efivarfs_fs_info,
>                                                     pm_nb);
> -       struct path path;
> -       struct efivarfs_ctx ectx = {
> -               .ctx = {
> -                       .actor  = efivarfs_actor,
> -               },
> -               .sb = sfi->sb,
> -       };
> -       struct file *file;
> -       struct super_block *s = sfi->sb;
>         static bool rescan_done = true;
>
>         if (action == PM_HIBERNATION_PREPARE) {
> @@ -513,64 +473,15 @@ static int efivarfs_pm_notify(struct notifier_block *nb, unsigned long action,
>         if (rescan_done)
>                 return NOTIFY_DONE;
>
> -       /* ensure single superblock is alive and pin it */
> -       if (!atomic_inc_not_zero(&s->s_active))
> -               return NOTIFY_DONE;
> -
>         pr_info("efivarfs: resyncing variable state\n");
>
> -       path.dentry = sfi->sb->s_root;
> -
> -       /*
> -        * do not add SB_KERNMOUNT which a single superblock could
> -        * expose to userspace and which also causes MNT_INTERNAL, see
> -        * below
> -        */
> -       path.mnt = vfs_kern_mount(&efivarfs_type, 0,
> -                                 efivarfs_type.name, NULL);
> -       if (IS_ERR(path.mnt)) {
> -               pr_err("efivarfs: internal mount failed\n");
> -               /*
> -                * We may be the last pinner of the superblock but
> -                * calling efivarfs_kill_sb from within the notifier
> -                * here would deadlock trying to unregister it
> -                */
> -               INIT_WORK(&s->destroy_work, efivarfs_deactivate_super_work);
> -               schedule_work(&s->destroy_work);
> -               return PTR_ERR(path.mnt);
> -       }
> -
> -       /* path.mnt now has pin on superblock, so this must be above one */
> -       atomic_dec(&s->s_active);
> -
> -       file = kernel_file_open(&path, O_RDONLY | O_DIRECTORY | O_NOATIME,
> -                               current_cred());
> -       /*
> -        * safe even if last put because no MNT_INTERNAL means this
> -        * will do delayed deactivate_super and not deadlock
> -        */
> -       mntput(path.mnt);
> -       if (IS_ERR(file))
> -               return NOTIFY_DONE;
> -
>         rescan_done = true;
>
>         /*
>          * First loop over the directory and verify each entry exists,
>          * removing it if it doesn't
>          */
> -       file->f_pos = 2;        /* skip . and .. */
> -       do {
> -               ectx.dentry = NULL;
> -               iterate_dir(file, &ectx.ctx);
> -               if (ectx.dentry) {
> -                       pr_info("efivarfs: removing variable %pd\n",
> -                               ectx.dentry);
> -                       simple_recursive_removal(ectx.dentry, NULL);
> -                       dput(ectx.dentry);
> -               }
> -       } while (ectx.dentry);
> -       fput(file);
> +       simple_iterate_call(sfi->sb->s_root, NULL, efivarfs_iterate_callback);
>
>         /*
>          * then loop over variables, creating them if there's no matching
> @@ -609,8 +520,8 @@ static void efivarfs_kill_sb(struct super_block *sb)
>         struct efivarfs_fs_info *sfi = sb->s_fs_info;
>
>         blocking_notifier_chain_unregister(&efivar_ops_nh, &sfi->nb);
> -       kill_litter_super(sb);
>         unregister_pm_notifier(&sfi->pm_nb);
> +       kill_litter_super(sb);
>
>         kfree(sfi);
>  }
> --
> 2.43.0
>
>




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux