Re: [PATCH 04/23] fuse: move the backing file idr and code into a new source file

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

 



On Thu, Aug 21, 2025 at 2:53 AM Darrick J. Wong <djwong@xxxxxxxxxx> wrote:
>
> From: Darrick J. Wong <djwong@xxxxxxxxxx>
>
> iomap support for fuse is also going to want the ability to attach
> backing files to a fuse filesystem.  Move the fuse_backing code into a
> separate file so that both can use it.
>
> Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx>
Reviewed-by: Amir Goldstein <amir73il@xxxxxxxxx>

Are you going to make FUSE_IOMAP depend on FUSE_PASSTHROUGH later on?
I can't think of a reason why not.

Thanks,
Amir.

> ---
>  fs/fuse/fuse_i.h      |   47 ++++++++-----
>  fs/fuse/Makefile      |    2 -
>  fs/fuse/backing.c     |  174 +++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/fuse/passthrough.c |  158 --------------------------------------------
>  4 files changed, 203 insertions(+), 178 deletions(-)
>  create mode 100644 fs/fuse/backing.c
>
>
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index 2cd9f4cdc6a7ef..2be2cbdf060536 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -1535,29 +1535,11 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid,
>  void fuse_file_release(struct inode *inode, struct fuse_file *ff,
>                        unsigned int open_flags, fl_owner_t id, bool isdir);
>
> -/* passthrough.c */
> -static inline struct fuse_backing *fuse_inode_backing(struct fuse_inode *fi)
> -{
> -#ifdef CONFIG_FUSE_PASSTHROUGH
> -       return READ_ONCE(fi->fb);
> -#else
> -       return NULL;
> -#endif
> -}
> -
> -static inline struct fuse_backing *fuse_inode_backing_set(struct fuse_inode *fi,
> -                                                         struct fuse_backing *fb)
> -{
> -#ifdef CONFIG_FUSE_PASSTHROUGH
> -       return xchg(&fi->fb, fb);
> -#else
> -       return NULL;
> -#endif
> -}
> -
> +/* backing.c */
>  #ifdef CONFIG_FUSE_PASSTHROUGH
>  struct fuse_backing *fuse_backing_get(struct fuse_backing *fb);
>  void fuse_backing_put(struct fuse_backing *fb);
> +struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, int backing_id);
>  #else
>
>  static inline struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
> @@ -1568,6 +1550,11 @@ static inline struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
>  static inline void fuse_backing_put(struct fuse_backing *fb)
>  {
>  }
> +static inline struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc,
> +                                                      int backing_id)
> +{
> +       return NULL;
> +}
>  #endif
>
>  void fuse_backing_files_init(struct fuse_conn *fc);
> @@ -1575,6 +1562,26 @@ void fuse_backing_files_free(struct fuse_conn *fc);
>  int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map);
>  int fuse_backing_close(struct fuse_conn *fc, int backing_id);
>
> +/* passthrough.c */
> +static inline struct fuse_backing *fuse_inode_backing(struct fuse_inode *fi)
> +{
> +#ifdef CONFIG_FUSE_PASSTHROUGH
> +       return READ_ONCE(fi->fb);
> +#else
> +       return NULL;
> +#endif
> +}
> +
> +static inline struct fuse_backing *fuse_inode_backing_set(struct fuse_inode *fi,
> +                                                         struct fuse_backing *fb)
> +{
> +#ifdef CONFIG_FUSE_PASSTHROUGH
> +       return xchg(&fi->fb, fb);
> +#else
> +       return NULL;
> +#endif
> +}
> +
>  struct fuse_backing *fuse_passthrough_open(struct file *file,
>                                            struct inode *inode,
>                                            int backing_id);
> diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile
> index 70709a7a3f9523..c79f786d0c90c3 100644
> --- a/fs/fuse/Makefile
> +++ b/fs/fuse/Makefile
> @@ -14,7 +14,7 @@ fuse-y := trace.o     # put trace.o first so we see ftrace errors sooner
>  fuse-y += dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o
>  fuse-y += iomode.o
>  fuse-$(CONFIG_FUSE_DAX) += dax.o
> -fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o
> +fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o backing.o
>  fuse-$(CONFIG_SYSCTL) += sysctl.o
>  fuse-$(CONFIG_FUSE_IO_URING) += dev_uring.o
>  fuse-$(CONFIG_FUSE_IOMAP) += file_iomap.o
> diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
> new file mode 100644
> index 00000000000000..ddb23b7400fc72
> --- /dev/null
> +++ b/fs/fuse/backing.c
> @@ -0,0 +1,174 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * FUSE passthrough to backing file.
> + *
> + * Copyright (c) 2023 CTERA Networks.
> + */
> +
> +#include "fuse_i.h"
> +
> +#include <linux/file.h>
> +
> +struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
> +{
> +       if (fb && refcount_inc_not_zero(&fb->count))
> +               return fb;
> +       return NULL;
> +}
> +
> +static void fuse_backing_free(struct fuse_backing *fb)
> +{
> +       pr_debug("%s: fb=0x%p\n", __func__, fb);
> +
> +       if (fb->file)
> +               fput(fb->file);
> +       put_cred(fb->cred);
> +       kfree_rcu(fb, rcu);
> +}
> +
> +void fuse_backing_put(struct fuse_backing *fb)
> +{
> +       if (fb && refcount_dec_and_test(&fb->count))
> +               fuse_backing_free(fb);
> +}
> +
> +void fuse_backing_files_init(struct fuse_conn *fc)
> +{
> +       idr_init(&fc->backing_files_map);
> +}
> +
> +static int fuse_backing_id_alloc(struct fuse_conn *fc, struct fuse_backing *fb)
> +{
> +       int id;
> +
> +       idr_preload(GFP_KERNEL);
> +       spin_lock(&fc->lock);
> +       /* FIXME: xarray might be space inefficient */
> +       id = idr_alloc_cyclic(&fc->backing_files_map, fb, 1, 0, GFP_ATOMIC);
> +       spin_unlock(&fc->lock);
> +       idr_preload_end();
> +
> +       WARN_ON_ONCE(id == 0);
> +       return id;
> +}
> +
> +static struct fuse_backing *fuse_backing_id_remove(struct fuse_conn *fc,
> +                                                  int id)
> +{
> +       struct fuse_backing *fb;
> +
> +       spin_lock(&fc->lock);
> +       fb = idr_remove(&fc->backing_files_map, id);
> +       spin_unlock(&fc->lock);
> +
> +       return fb;
> +}
> +
> +static int fuse_backing_id_free(int id, void *p, void *data)
> +{
> +       struct fuse_backing *fb = p;
> +
> +       WARN_ON_ONCE(refcount_read(&fb->count) != 1);
> +       fuse_backing_free(fb);
> +       return 0;
> +}
> +
> +void fuse_backing_files_free(struct fuse_conn *fc)
> +{
> +       idr_for_each(&fc->backing_files_map, fuse_backing_id_free, NULL);
> +       idr_destroy(&fc->backing_files_map);
> +}
> +
> +int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map)
> +{
> +       struct file *file;
> +       struct super_block *backing_sb;
> +       struct fuse_backing *fb = NULL;
> +       int res;
> +
> +       pr_debug("%s: fd=%d flags=0x%x\n", __func__, map->fd, map->flags);
> +
> +       /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
> +       res = -EPERM;
> +       if (!fc->passthrough || !capable(CAP_SYS_ADMIN))
> +               goto out;
> +
> +       res = -EINVAL;
> +       if (map->flags || map->padding)
> +               goto out;
> +
> +       file = fget_raw(map->fd);
> +       res = -EBADF;
> +       if (!file)
> +               goto out;
> +
> +       backing_sb = file_inode(file)->i_sb;
> +       res = -ELOOP;
> +       if (backing_sb->s_stack_depth >= fc->max_stack_depth)
> +               goto out_fput;
> +
> +       fb = kmalloc(sizeof(struct fuse_backing), GFP_KERNEL);
> +       res = -ENOMEM;
> +       if (!fb)
> +               goto out_fput;
> +
> +       fb->file = file;
> +       fb->cred = prepare_creds();
> +       refcount_set(&fb->count, 1);
> +
> +       res = fuse_backing_id_alloc(fc, fb);
> +       if (res < 0) {
> +               fuse_backing_free(fb);
> +               fb = NULL;
> +       }
> +
> +out:
> +       pr_debug("%s: fb=0x%p, ret=%i\n", __func__, fb, res);
> +
> +       return res;
> +
> +out_fput:
> +       fput(file);
> +       goto out;
> +}
> +
> +int fuse_backing_close(struct fuse_conn *fc, int backing_id)
> +{
> +       struct fuse_backing *fb = NULL;
> +       int err;
> +
> +       pr_debug("%s: backing_id=%d\n", __func__, backing_id);
> +
> +       /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
> +       err = -EPERM;
> +       if (!fc->passthrough || !capable(CAP_SYS_ADMIN))
> +               goto out;
> +
> +       err = -EINVAL;
> +       if (backing_id <= 0)
> +               goto out;
> +
> +       err = -ENOENT;
> +       fb = fuse_backing_id_remove(fc, backing_id);
> +       if (!fb)
> +               goto out;
> +
> +       fuse_backing_put(fb);
> +       err = 0;
> +out:
> +       pr_debug("%s: fb=0x%p, err=%i\n", __func__, fb, err);
> +
> +       return err;
> +}
> +
> +struct fuse_backing *fuse_backing_lookup(struct fuse_conn *fc, int backing_id)
> +{
> +       struct fuse_backing *fb;
> +
> +       rcu_read_lock();
> +       fb = idr_find(&fc->backing_files_map, backing_id);
> +       fb = fuse_backing_get(fb);
> +       rcu_read_unlock();
> +
> +       return fb;
> +}
> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
> index 607ef735ad4ab3..e0b8d885bc81f3 100644
> --- a/fs/fuse/passthrough.c
> +++ b/fs/fuse/passthrough.c
> @@ -144,158 +144,6 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
>         return backing_file_mmap(backing_file, vma, &ctx);
>  }
>
> -struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
> -{
> -       if (fb && refcount_inc_not_zero(&fb->count))
> -               return fb;
> -       return NULL;
> -}
> -
> -static void fuse_backing_free(struct fuse_backing *fb)
> -{
> -       pr_debug("%s: fb=0x%p\n", __func__, fb);
> -
> -       if (fb->file)
> -               fput(fb->file);
> -       put_cred(fb->cred);
> -       kfree_rcu(fb, rcu);
> -}
> -
> -void fuse_backing_put(struct fuse_backing *fb)
> -{
> -       if (fb && refcount_dec_and_test(&fb->count))
> -               fuse_backing_free(fb);
> -}
> -
> -void fuse_backing_files_init(struct fuse_conn *fc)
> -{
> -       idr_init(&fc->backing_files_map);
> -}
> -
> -static int fuse_backing_id_alloc(struct fuse_conn *fc, struct fuse_backing *fb)
> -{
> -       int id;
> -
> -       idr_preload(GFP_KERNEL);
> -       spin_lock(&fc->lock);
> -       /* FIXME: xarray might be space inefficient */
> -       id = idr_alloc_cyclic(&fc->backing_files_map, fb, 1, 0, GFP_ATOMIC);
> -       spin_unlock(&fc->lock);
> -       idr_preload_end();
> -
> -       WARN_ON_ONCE(id == 0);
> -       return id;
> -}
> -
> -static struct fuse_backing *fuse_backing_id_remove(struct fuse_conn *fc,
> -                                                  int id)
> -{
> -       struct fuse_backing *fb;
> -
> -       spin_lock(&fc->lock);
> -       fb = idr_remove(&fc->backing_files_map, id);
> -       spin_unlock(&fc->lock);
> -
> -       return fb;
> -}
> -
> -static int fuse_backing_id_free(int id, void *p, void *data)
> -{
> -       struct fuse_backing *fb = p;
> -
> -       WARN_ON_ONCE(refcount_read(&fb->count) != 1);
> -       fuse_backing_free(fb);
> -       return 0;
> -}
> -
> -void fuse_backing_files_free(struct fuse_conn *fc)
> -{
> -       idr_for_each(&fc->backing_files_map, fuse_backing_id_free, NULL);
> -       idr_destroy(&fc->backing_files_map);
> -}
> -
> -int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map)
> -{
> -       struct file *file;
> -       struct super_block *backing_sb;
> -       struct fuse_backing *fb = NULL;
> -       int res;
> -
> -       pr_debug("%s: fd=%d flags=0x%x\n", __func__, map->fd, map->flags);
> -
> -       /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
> -       res = -EPERM;
> -       if (!fc->passthrough || !capable(CAP_SYS_ADMIN))
> -               goto out;
> -
> -       res = -EINVAL;
> -       if (map->flags || map->padding)
> -               goto out;
> -
> -       file = fget_raw(map->fd);
> -       res = -EBADF;
> -       if (!file)
> -               goto out;
> -
> -       backing_sb = file_inode(file)->i_sb;
> -       res = -ELOOP;
> -       if (backing_sb->s_stack_depth >= fc->max_stack_depth)
> -               goto out_fput;
> -
> -       fb = kmalloc(sizeof(struct fuse_backing), GFP_KERNEL);
> -       res = -ENOMEM;
> -       if (!fb)
> -               goto out_fput;
> -
> -       fb->file = file;
> -       fb->cred = prepare_creds();
> -       refcount_set(&fb->count, 1);
> -
> -       res = fuse_backing_id_alloc(fc, fb);
> -       if (res < 0) {
> -               fuse_backing_free(fb);
> -               fb = NULL;
> -       }
> -
> -out:
> -       pr_debug("%s: fb=0x%p, ret=%i\n", __func__, fb, res);
> -
> -       return res;
> -
> -out_fput:
> -       fput(file);
> -       goto out;
> -}
> -
> -int fuse_backing_close(struct fuse_conn *fc, int backing_id)
> -{
> -       struct fuse_backing *fb = NULL;
> -       int err;
> -
> -       pr_debug("%s: backing_id=%d\n", __func__, backing_id);
> -
> -       /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
> -       err = -EPERM;
> -       if (!fc->passthrough || !capable(CAP_SYS_ADMIN))
> -               goto out;
> -
> -       err = -EINVAL;
> -       if (backing_id <= 0)
> -               goto out;
> -
> -       err = -ENOENT;
> -       fb = fuse_backing_id_remove(fc, backing_id);
> -       if (!fb)
> -               goto out;
> -
> -       fuse_backing_put(fb);
> -       err = 0;
> -out:
> -       pr_debug("%s: fb=0x%p, err=%i\n", __func__, fb, err);
> -
> -       return err;
> -}
> -
>  /*
>   * Setup passthrough to a backing file.
>   *
> @@ -315,12 +163,8 @@ struct fuse_backing *fuse_passthrough_open(struct file *file,
>         if (backing_id <= 0)
>                 goto out;
>
> -       rcu_read_lock();
> -       fb = idr_find(&fc->backing_files_map, backing_id);
> -       fb = fuse_backing_get(fb);
> -       rcu_read_unlock();
> -
>         err = -ENOENT;
> +       fb = fuse_backing_lookup(fc, backing_id);
>         if (!fb)
>                 goto out;
>
>
>





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux