lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAOQ4uxgeZQYEY8WsthebjV9f4qZd+nWJnCGWog6D1=wu+MFpSQ@mail.gmail.com>
Date: Thu, 6 Nov 2025 19:50:15 +0100
From: Amir Goldstein <amir73il@...il.com>
To: "Darrick J. Wong" <djwong@...nel.org>
Cc: miklos@...redi.hu, joannelkoong@...il.com, bernd@...ernd.com, 
	neal@...pa.dev, linux-ext4@...r.kernel.org, linux-fsdevel@...r.kernel.org
Subject: Re: [PATCH 04/31] fuse: adapt FUSE_DEV_IOC_BACKING_{OPEN,CLOSE} to
 add new iomap devices

On Wed, Oct 29, 2025 at 1:56 AM Darrick J. Wong <djwong@...nel.org> wrote:
>
> From: Darrick J. Wong <djwong@...nel.org>
>
> Enable the use of the backing file open/close ioctls so that fuse
> servers can register block devices for use with iomap.
>
> Signed-off-by: "Darrick J. Wong" <djwong@...nel.org>
> ---

Reviewed-by: Amir Goldstein <amir73il@...il.com>

>  fs/fuse/fuse_i.h          |    5 ++
>  include/uapi/linux/fuse.h |    3 +
>  fs/fuse/Kconfig           |    1
>  fs/fuse/backing.c         |   12 +++++
>  fs/fuse/file_iomap.c      |  101 +++++++++++++++++++++++++++++++++++++++++----
>  fs/fuse/trace.c           |    1
>  6 files changed, 113 insertions(+), 10 deletions(-)
>
>
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index 61fb65f3604d61..274de907257d94 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -97,12 +97,14 @@ struct fuse_submount_lookup {
>  };
>
>  struct fuse_conn;
> +struct fuse_backing;
>
>  /** Operations for subsystems that want to use a backing file */
>  struct fuse_backing_ops {
>         int (*may_admin)(struct fuse_conn *fc, uint32_t flags);
>         int (*may_open)(struct fuse_conn *fc, struct file *file);
>         int (*may_close)(struct fuse_conn *fc, struct file *file);
> +       int (*post_open)(struct fuse_conn *fc, struct fuse_backing *fb);
>         unsigned int type;
>         int id_start;
>         int id_end;
> @@ -112,6 +114,7 @@ struct fuse_backing_ops {
>  struct fuse_backing {
>         struct file *file;
>         struct cred *cred;
> +       struct block_device *bdev;
>         const struct fuse_backing_ops *ops;
>
>         /** refcount */
> @@ -1706,6 +1709,8 @@ static inline bool fuse_has_iomap(const struct inode *inode)
>  {
>         return get_fuse_conn(inode)->iomap;
>  }
> +
> +extern const struct fuse_backing_ops fuse_iomap_backing_ops;
>  #else
>  # define fuse_iomap_enabled(...)               (false)
>  # define fuse_has_iomap(...)                   (false)
> diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
> index 7d709cf12b41a7..e571f8ceecbfad 100644
> --- a/include/uapi/linux/fuse.h
> +++ b/include/uapi/linux/fuse.h
> @@ -1136,7 +1136,8 @@ struct fuse_notify_prune_out {
>
>  #define FUSE_BACKING_TYPE_MASK         (0xFF)
>  #define FUSE_BACKING_TYPE_PASSTHROUGH  (0)
> -#define FUSE_BACKING_MAX_TYPE          (FUSE_BACKING_TYPE_PASSTHROUGH)
> +#define FUSE_BACKING_TYPE_IOMAP                (1)
> +#define FUSE_BACKING_MAX_TYPE          (FUSE_BACKING_TYPE_IOMAP)
>
>  #define FUSE_BACKING_FLAGS_ALL         (FUSE_BACKING_TYPE_MASK)
>
> diff --git a/fs/fuse/Kconfig b/fs/fuse/Kconfig
> index bb867afe6e867c..52803c533f47f9 100644
> --- a/fs/fuse/Kconfig
> +++ b/fs/fuse/Kconfig
> @@ -75,6 +75,7 @@ config FUSE_IOMAP
>         depends on FUSE_FS
>         depends on BLOCK
>         select FS_IOMAP
> +       select FUSE_BACKING
>         help
>           Enable fuse servers to operate the regular file I/O path through
>           the fs-iomap library in the kernel.  This enables higher performance
> diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
> index b83a3c1b2dff7a..7786f6e5fd02f2 100644
> --- a/fs/fuse/backing.c
> +++ b/fs/fuse/backing.c
> @@ -90,6 +90,10 @@ fuse_backing_ops_from_map(const struct fuse_backing_map *map)
>  #ifdef CONFIG_FUSE_PASSTHROUGH
>         case FUSE_BACKING_TYPE_PASSTHROUGH:
>                 return &fuse_passthrough_backing_ops;
> +#endif
> +#ifdef CONFIG_FUSE_IOMAP
> +       case FUSE_BACKING_TYPE_IOMAP:
> +               return &fuse_iomap_backing_ops;
>  #endif
>         default:
>                 break;
> @@ -138,8 +142,16 @@ int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map)
>         fb->file = file;
>         fb->cred = prepare_creds();
>         fb->ops = ops;
> +       fb->bdev = NULL;
>         refcount_set(&fb->count, 1);
>
> +       res = ops->post_open ? ops->post_open(fc, fb) : 0;
> +       if (res) {
> +               fuse_backing_free(fb);
> +               fb = NULL;
> +               goto out;
> +       }
> +
>         res = fuse_backing_id_alloc(fc, fb);
>         if (res < 0) {
>                 fuse_backing_free(fb);
> diff --git a/fs/fuse/file_iomap.c b/fs/fuse/file_iomap.c
> index b6fc70068c5542..e4fea3bdc0c2ce 100644
> --- a/fs/fuse/file_iomap.c
> +++ b/fs/fuse/file_iomap.c
> @@ -319,10 +319,6 @@ static inline bool fuse_iomap_check_mapping(const struct inode *inode,
>                 return false;
>         }
>
> -       /* XXX: we don't support devices yet */
> -       if (BAD_DATA(map->dev != FUSE_IOMAP_DEV_NULL))
> -               return false;
> -
>         /* No overflows in the device range, if supplied */
>         if (map->addr != FUSE_IOMAP_NULL_ADDR &&
>             BAD_DATA(check_add_overflow(map->addr, map->length, &end)))
> @@ -334,6 +330,7 @@ static inline bool fuse_iomap_check_mapping(const struct inode *inode,
>  /* Convert a mapping from the server into something the kernel can use */
>  static inline void fuse_iomap_from_server(struct inode *inode,
>                                           struct iomap *iomap,
> +                                         const struct fuse_backing *fb,
>                                           const struct fuse_iomap_io *fmap)
>  {
>         iomap->addr = fmap->addr;
> @@ -341,7 +338,9 @@ static inline void fuse_iomap_from_server(struct inode *inode,
>         iomap->length = fmap->length;
>         iomap->type = fuse_iomap_type_from_server(fmap->type);
>         iomap->flags = fuse_iomap_flags_from_server(fmap->flags);
> -       iomap->bdev = inode->i_sb->s_bdev; /* XXX */
> +
> +       iomap->bdev = fb ? fb->bdev : NULL;
> +       iomap->dax_dev = NULL;
>  }
>
>  /* Convert a mapping from the kernel into something the server can use */
> @@ -392,6 +391,27 @@ static inline bool fuse_is_iomap_file_write(unsigned int opflags)
>         return opflags & (IOMAP_WRITE | IOMAP_ZERO | IOMAP_UNSHARE);
>  }
>
> +static inline struct fuse_backing *
> +fuse_iomap_find_dev(struct fuse_conn *fc, const struct fuse_iomap_io *map)
> +{
> +       struct fuse_backing *ret = NULL;
> +
> +       if (map->dev != FUSE_IOMAP_DEV_NULL && map->dev < INT_MAX)
> +               ret = fuse_backing_lookup(fc, &fuse_iomap_backing_ops,
> +                                         map->dev);
> +
> +       switch (map->type) {
> +       case FUSE_IOMAP_TYPE_MAPPED:
> +       case FUSE_IOMAP_TYPE_UNWRITTEN:
> +               /* Mappings backed by space must have a device/addr */
> +               if (BAD_DATA(ret == NULL))
> +                       return ERR_PTR(-EFSCORRUPTED);
> +               break;
> +       }
> +
> +       return ret;
> +}
> +
>  static int fuse_iomap_begin(struct inode *inode, loff_t pos, loff_t count,
>                             unsigned opflags, struct iomap *iomap,
>                             struct iomap *srcmap)
> @@ -405,6 +425,8 @@ static int fuse_iomap_begin(struct inode *inode, loff_t pos, loff_t count,
>         };
>         struct fuse_iomap_begin_out outarg = { };
>         struct fuse_mount *fm = get_fuse_mount(inode);
> +       struct fuse_backing *read_dev = NULL;
> +       struct fuse_backing *write_dev = NULL;
>         FUSE_ARGS(args);
>         int err;
>
> @@ -431,24 +453,44 @@ static int fuse_iomap_begin(struct inode *inode, loff_t pos, loff_t count,
>         if (err)
>                 return err;
>
> +       read_dev = fuse_iomap_find_dev(fm->fc, &outarg.read);
> +       if (IS_ERR(read_dev))
> +               return PTR_ERR(read_dev);
> +
>         if (fuse_is_iomap_file_write(opflags) &&
>             outarg.write.type != FUSE_IOMAP_TYPE_PURE_OVERWRITE) {
> +               /* open the write device */
> +               write_dev = fuse_iomap_find_dev(fm->fc, &outarg.write);
> +               if (IS_ERR(write_dev)) {
> +                       err = PTR_ERR(write_dev);
> +                       goto out_read_dev;
> +               }
> +
>                 /*
>                  * For an out of place write, we must supply the write mapping
>                  * via @iomap, and the read mapping via @srcmap.
>                  */
> -               fuse_iomap_from_server(inode, iomap, &outarg.write);
> -               fuse_iomap_from_server(inode, srcmap, &outarg.read);
> +               fuse_iomap_from_server(inode, iomap, write_dev, &outarg.write);
> +               fuse_iomap_from_server(inode, srcmap, read_dev, &outarg.read);
>         } else {
>                 /*
>                  * For everything else (reads, reporting, and pure overwrites),
>                  * we can return the sole mapping through @iomap and leave
>                  * @srcmap unchanged from its default (HOLE).
>                  */
> -               fuse_iomap_from_server(inode, iomap, &outarg.read);
> +               fuse_iomap_from_server(inode, iomap, read_dev, &outarg.read);
>         }
>
> -       return 0;
> +       /*
> +        * XXX: if we ever want to support closing devices, we need a way to
> +        * track the fuse_backing refcount all the way through bio endios.
> +        * For now we put the refcount here because you can't remove an iomap
> +        * device until unmount time.
> +        */
> +       fuse_backing_put(write_dev);
> +out_read_dev:
> +       fuse_backing_put(read_dev);
> +       return err;
>  }
>
>  /* Decide if we send FUSE_IOMAP_END to the fuse server */
> @@ -523,3 +565,44 @@ const struct iomap_ops fuse_iomap_ops = {
>         .iomap_begin            = fuse_iomap_begin,
>         .iomap_end              = fuse_iomap_end,
>  };
> +
> +static int fuse_iomap_may_admin(struct fuse_conn *fc, unsigned int flags)
> +{
> +       if (!fc->iomap)
> +               return -EPERM;
> +
> +       if (flags)
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static int fuse_iomap_may_open(struct fuse_conn *fc, struct file *file)
> +{
> +       if (!S_ISBLK(file_inode(file)->i_mode))
> +               return -ENODEV;
> +
> +       return 0;
> +}
> +
> +static int fuse_iomap_post_open(struct fuse_conn *fc, struct fuse_backing *fb)
> +{
> +       fb->bdev = I_BDEV(fb->file->f_mapping->host);
> +       return 0;
> +}
> +
> +static int fuse_iomap_may_close(struct fuse_conn *fc, struct file *file)
> +{
> +       /* We only support closing iomap block devices at unmount */
> +       return -EBUSY;
> +}
> +
> +const struct fuse_backing_ops fuse_iomap_backing_ops = {
> +       .type = FUSE_BACKING_TYPE_IOMAP,
> +       .id_start = 1,
> +       .id_end = 1025,         /* maximum 1024 block devices */
> +       .may_admin = fuse_iomap_may_admin,
> +       .may_open = fuse_iomap_may_open,
> +       .may_close = fuse_iomap_may_close,
> +       .post_open = fuse_iomap_post_open,
> +};
> diff --git a/fs/fuse/trace.c b/fs/fuse/trace.c
> index 93bd72efc98cd0..68d2eecb8559a5 100644
> --- a/fs/fuse/trace.c
> +++ b/fs/fuse/trace.c
> @@ -6,6 +6,7 @@
>  #include "dev_uring_i.h"
>  #include "fuse_i.h"
>  #include "fuse_dev_i.h"
> +#include "iomap_i.h"
>
>  #include <linux/pagemap.h>
>
>
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ