On Thu, Oct 1, 2026 at 5:09 PM Miklos Szeredi <[email protected]> wrote:
>
> Add backing_id_64 field to fuse_open_out to allow opening files with
> 64-bit server-allocated backing IDs.
>
> When the server sets FUSE_BACKING_ID_64 in open_out.open_flags, the
> kernel reads the backing ID from open_out.backing_id_64 instead of
> open_out.backing_id.
>
> The open reply is now variable-length for backward compatibility with
> servers that don't send the new backing_id_64 field.
>
> Signed-off-by: Miklos Szeredi <[email protected]>

Reviewed-by: Amir Goldstein <[email protected]>

> ---
>  fs/fuse/dir.c             |  3 ++-
>  fs/fuse/file.c            |  6 +++++-
>  fs/fuse/fuse_i.h          |  2 +-
>  fs/fuse/iomode.c          | 34 ++++++++++++++++++++++++++++------
>  fs/fuse/passthrough.c     | 28 ++++++----------------------
>  include/uapi/linux/fuse.h |  2 ++
>  6 files changed, 44 insertions(+), 31 deletions(-)
>
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index f48fafccce4b..874ec7cfffb1 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -876,6 +876,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, 
> struct inode *dir,
>         args.out_args[0].value = &outentry;
>         /* Store outarg for fuse_finish_open() */
>         outopenp = &ff->args->open_outarg;
> +       args.out_argvar = true; /* compat */
>         args.out_args[1].size = sizeof(*outopenp);
>         args.out_args[1].value = outopenp;
>
> @@ -885,7 +886,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, 
> struct inode *dir,
>
>         err = fuse_simple_idmap_request(idmap, fm, &args);
>         free_ext_value(&args);
> -       if (err)
> +       if (err < 0)
>                 goto out_free_ff;
>
>         err = -EIO;
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 92976906ab05..1036c06fe35a 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -28,6 +28,7 @@ static int fuse_send_open(struct fuse_mount *fm, u64 nodeid,
>  {
>         struct fuse_open_in inarg;
>         FUSE_ARGS(args);
> +       int res;
>
>         memset(&inarg, 0, sizeof(inarg));
>         inarg.flags = open_flags & ~(O_CREAT | O_EXCL | O_NOCTTY);
> @@ -45,10 +46,13 @@ static int fuse_send_open(struct fuse_mount *fm, u64 
> nodeid,
>         args.in_args[0].size = sizeof(inarg);
>         args.in_args[0].value = &inarg;
>         args.out_numargs = 1;
> +       args.out_argvar = true; /* compat */
>         args.out_args[0].size = sizeof(*outargp);
>         args.out_args[0].value = outargp;
>
> -       return fuse_simple_request(fm, &args);
> +       res = fuse_simple_request(fm, &args);
> +
> +       return res < 0 ? res : 0;
>  }
>
>  struct fuse_file *fuse_file_alloc(struct fuse_mount *fm, bool release)
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index 003ef3c35d7a..59afebc3dd2b 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -1314,7 +1314,7 @@ static inline struct fuse_backing 
> *fuse_inode_backing_set(struct fuse_inode *fi,
>  #endif
>  }
>
> -struct fuse_backing *fuse_passthrough_open(struct file *file, int 
> backing_id);
> +int fuse_passthrough_open(struct file *file, struct fuse_backing *fb);
>  void fuse_passthrough_release(struct fuse_file *ff, struct fuse_backing *fb);
>
>  static inline bool fuse_is_passthrough(struct fuse_file *ff)
> diff --git a/fs/fuse/iomode.c b/fs/fuse/iomode.c
> index 1a10bc65fb31..811ea603b776 100644
> --- a/fs/fuse/iomode.c
> +++ b/fs/fuse/iomode.c
> @@ -160,7 +160,9 @@ static int fuse_file_passthrough_open(struct inode 
> *inode, struct file *file)
>  {
>         struct fuse_file *ff = file->private_data;
>         struct fuse_conn *fc = get_fuse_conn(inode);
> +       struct fuse_open_out *outarg = &ff->args->open_outarg;
>         struct fuse_backing *fb;
> +       u64 backing_id;
>         int err;
>
>         /* Check allowed conditions for file open in passthrough mode */
> @@ -170,18 +172,38 @@ static int fuse_file_passthrough_open(struct inode 
> *inode, struct file *file)
>         if (ff->open_flags & ~FOPEN_PASSTHROUGH_MASK)
>                 return fuse_EIO("conflicting open flags");
>
> -       fb = fuse_passthrough_open(file, ff->args->open_outarg.backing_id);
> -       if (IS_ERR(fb))
> -               return PTR_ERR(fb);
> +       if (!fc->backing_id_64) {
> +               if (outarg->backing_id_64 != 0)
> +                       return fuse_EIO("64 bit backing ID set");
> +
> +               backing_id = outarg->backing_id;
> +               if (backing_id <= 0)
> +                       return fuse_EIO("invalid backing ID");
> +       } else {
> +               if (outarg->backing_id != 0)
> +                       return fuse_EIO("32 bit backing ID set");
> +
> +               backing_id = outarg->backing_id_64;
> +       }
> +       fb = fuse_backing_lookup(fc, backing_id);
> +       if (!fb)
> +               return fuse_EIO("backing not found");
> +
> +       err = fuse_passthrough_open(file, fb);
> +       if (err)
> +               goto backing_put;
>
>         /* First passthrough file open denies caching inode io mode */
>         err = fuse_file_uncached_io_open(inode, ff, fb);
> -       if (!err)
> -               return 0;
> +       if (err)
> +               goto passthrough_release;
> +
> +       return 0;
>
> +passthrough_release:
>         fuse_passthrough_release(ff, fb);
> +backing_put:
>         fuse_backing_put(fb);
> -
>         return err;
>  }
>
> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
> index 313c8d7ffc09..4894842ad6d0 100644
> --- a/fs/fuse/passthrough.c
> +++ b/fs/fuse/passthrough.c
> @@ -150,41 +150,25 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct 
> vm_area_struct *vma)
>
>  /*
>   * Setup passthrough to a backing file.
> - *
> - * Returns an fb object with elevated refcount to be stored in fuse inode.
>   */
> -struct fuse_backing *fuse_passthrough_open(struct file *file, int backing_id)
> +int fuse_passthrough_open(struct file *file, struct fuse_backing *fb)
>  {
>         struct fuse_file *ff = file->private_data;
> -       struct fuse_conn *fc = ff->fm->fc;
> -       struct fuse_backing *fb = NULL;
>         struct file *backing_file;
>
> -       if (fc->backing_id_64)
> -               return ERR_PTR(fuse_EIO("incompatible backing version"));
> -
> -       if (backing_id <= 0)
> -               return ERR_PTR(fuse_EIO("invalid backing_id"));
> -
> -       fb = fuse_backing_lookup(fc, backing_id);
> -       if (!fb)
> -               return ERR_PTR(fuse_EIO("backing not found"));
> -
>         /* Allocate backing file per fuse file to store fuse path */
>         backing_file = backing_file_open(file, file->f_flags,
>                                          &fb->file->f_path, fb->cred);
> -       if (IS_ERR(backing_file)) {
> -               fuse_backing_put(fb);
> -               return ERR_PTR(fuse_EIO("failed to open backing file (%ld)", 
> PTR_ERR(backing_file)));
> -       }
> +       if (IS_ERR(backing_file))
> +               return fuse_EIO("failed to open backing file (%ld)", 
> PTR_ERR(backing_file));
>
>         ff->passthrough = backing_file;
>         ff->cred = get_cred(fb->cred);
>
> -       pr_debug("%s: backing_id=%d, fb=0x%p, backing_file=0x%p\n", __func__,
> -                backing_id, fb, ff->passthrough);
> +       pr_debug("%s: backing_id=%llu, fb=0x%p, backing_file=0x%p\n", 
> __func__,
> +                fb->backing_id, fb, ff->passthrough);
>
> -       return fb;
> +       return 0;
>  }
>
>  void fuse_passthrough_release(struct fuse_file *ff, struct fuse_backing *fb)
> diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
> index c88d7094af44..60fb2add5e12 100644
> --- a/include/uapi/linux/fuse.h
> +++ b/include/uapi/linux/fuse.h
> @@ -254,6 +254,7 @@
>   *  - add FUSE_PASSTHROUGH_V2
>   *  - add FUSE_DEV_IOC_BACKING_CREATE, struct fuse_backing_create_in
>   *  - add FUSE_NOTIFY_BACKING_REMOVE, struct fuse_notify_backing_remove_out
> + *  - add backing_id_64 to fuse_open_out
>   */
>
>  #ifndef _LINUX_FUSE_H
> @@ -841,6 +842,7 @@ struct fuse_open_out {
>         uint64_t        fh;
>         uint32_t        open_flags;
>         int32_t         backing_id;
> +       uint64_t        backing_id_64;
>  };
>
>  struct fuse_release_in {
> --
> 2.54.0
>

Reply via email to