[Virtio-fs] [PATCH][v2] fuse, virtiofs: Do not alloc/install fuse device in fuse_fill_super_common()

Miklos Szeredi miklos at szeredi.hu
Mon May 4 13:30:39 UTC 2020


On Thu, Apr 30, 2020 at 7:18 PM Vivek Goyal <vgoyal at redhat.com> wrote:
>
> As of now fuse_fill_super_common() allocates and installs one fuse device.
> Filesystems like virtiofs can have more than one filesystem queues and
> can have one fuse device per queue. Give, fuse_fill_super_common() only
> handles one device, virtiofs allocates and installes fuse devices for
> all queues except one.
>
> This makes logic little twisted and hard to understand. It probably
> is better to not do any device allocation/installation in
> fuse_fill_super_common() and let caller take care of it instead.

Taking a closer look...

>
> v2: Removed fuse_dev_alloc_install() call from fuse_fill_super_common().
>
> Signed-off-by: Vivek Goyal <vgoyal at redhat.com>
> ---
>  fs/fuse/fuse_i.h    |  3 ---
>  fs/fuse/inode.c     | 30 ++++++++++++++----------------
>  fs/fuse/virtio_fs.c |  9 +--------
>  3 files changed, 15 insertions(+), 27 deletions(-)
>
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index ca344bf71404..df0a62f963a8 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -485,9 +485,6 @@ struct fuse_fs_context {
>         unsigned int max_read;
>         unsigned int blksize;
>         const char *subtype;
> -
> -       /* fuse_dev pointer to fill in, should contain NULL on entry */
> -       void **fudptr;
>  };
>
>  /**
> diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
> index 95d712d44ca1..6b38e0391c96 100644
> --- a/fs/fuse/inode.c
> +++ b/fs/fuse/inode.c
> @@ -1113,7 +1113,6 @@ EXPORT_SYMBOL_GPL(fuse_dev_free);
>
>  int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
>  {
> -       struct fuse_dev *fud;
>         struct fuse_conn *fc = get_fuse_conn_super(sb);
>         struct inode *root;
>         struct dentry *root_dentry;
> @@ -1155,15 +1154,11 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
>         if (sb->s_user_ns != &init_user_ns)
>                 sb->s_xattr = fuse_no_acl_xattr_handlers;
>
> -       fud = fuse_dev_alloc_install(fc);
> -       if (!fud)
> -               goto err;
> -
>         fc->dev = sb->s_dev;
>         fc->sb = sb;
>         err = fuse_bdi_init(fc, sb);
>         if (err)
> -               goto err_dev_free;
> +               goto err;
>
>         /* Handle umasking inside the fuse code */
>         if (sb->s_flags & SB_POSIXACL)
> @@ -1185,30 +1180,24 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
>         sb->s_d_op = &fuse_root_dentry_operations;
>         root_dentry = d_make_root(root);
>         if (!root_dentry)
> -               goto err_dev_free;
> +               goto err;
>         /* Root dentry doesn't have .d_revalidate */
>         sb->s_d_op = &fuse_dentry_operations;
>
>         mutex_lock(&fuse_mutex);
>         err = -EINVAL;
> -       if (*ctx->fudptr)
> -               goto err_unlock;
> -
>         err = fuse_ctl_add_conn(fc);
>         if (err)
>                 goto err_unlock;
>
>         list_add_tail(&fc->entry, &fuse_conn_list);
>         sb->s_root = root_dentry;
> -       *ctx->fudptr = fud;
>         mutex_unlock(&fuse_mutex);
>         return 0;
>
>   err_unlock:
>         mutex_unlock(&fuse_mutex);
>         dput(root_dentry);
> - err_dev_free:
> -       fuse_dev_free(fud);
>   err:
>         return err;
>  }
> @@ -1220,6 +1209,7 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
>         struct file *file;
>         int err;
>         struct fuse_conn *fc;
> +       struct fuse_dev *fud;
>
>         err = -EINVAL;
>         file = fget(ctx->fd);
> @@ -1233,13 +1223,16 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
>         if ((file->f_op != &fuse_dev_operations) ||
>             (file->f_cred->user_ns != sb->s_user_ns))
>                 goto err_fput;
> -       ctx->fudptr = &file->private_data;
>
> -       fc = kmalloc(sizeof(*fc), GFP_KERNEL);
>         err = -ENOMEM;
> -       if (!fc)
> +       fud = fuse_dev_alloc();
> +       if (!fud)
>                 goto err_fput;
>
> +       fc = kmalloc(sizeof(*fc), GFP_KERNEL);
> +       if (!fc)
> +               goto err_free_dev;
> +
>         fuse_conn_init(fc, sb->s_user_ns, &fuse_dev_fiq_ops, NULL);
>         fc->release = fuse_free_conn;
>         sb->s_fs_info = fc;
> @@ -1247,6 +1240,9 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
>         err = fuse_fill_super_common(sb, ctx);
>         if (err)
>                 goto err_put_conn;
> +
> +       fuse_dev_install(fud, fc);
> +       file->private_data = fud;

We've lost the check for non-null file->private_data; i.e. a fuse fd
already bound to a super block.  That needs to be restored, together
with protection against two such instances racing with each other.

Maybe we are better off moving the whole fuse_mutex protected block
from the end of fuse_fill_super_common() into the callers.

Thanks,
Miklos





More information about the Virtio-fs mailing list