Re: [PATCH v2 19/21] fuse: add passthrough setattr

Amir Goldstein <[email protected]> Sun, 17 May 2026 00:29:09 +0200
Newsgroups org.kernel.vger.linux-unionfs,dev.linux.lists.fuse-devel
Message-ID <CAOQ4uxgxXMYjptBMggikrEfnhKmdGKxEauD4waT8JotKtgYs-A@mail.gmail.com>
On Sat, May 16, 2026 at 2:53 AM Joanne Koong <[email protected]> wrote:
>
> Add passthrough setattr which sets attributes directly on the backing
> inode through backing_inode_setattr() instead of sending FUSE_SETATTR to
> the server.
>
> Passthrough setattr is checked before the
> handle_killpriv/handle_killpriv_v2 suid/sgid stripping because the
> stripping is handled natively by notify_change() on the backing inode.
>
> Signed-off-by: Joanne Koong <[email protected]>

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

> ---
>  fs/fuse/dir.c             |  3 +++
>  fs/fuse/fuse_i.h          |  3 ++-
>  fs/fuse/passthrough.c     | 28 ++++++++++++++++++++++++++++
>  include/uapi/linux/fuse.h |  1 +
>  4 files changed, 34 insertions(+), 1 deletion(-)
>
> diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
> index 4c7e3e1604af..b67b3b334e69 100644
> --- a/fs/fuse/dir.c
> +++ b/fs/fuse/dir.c
> @@ -2506,6 +2506,9 @@ static int fuse_setattr(struct mnt_idmap *idmap, struct dentry *entry,
>         if (!fuse_allow_current_process(get_fuse_conn(inode)))
>                 return -EACCES;
>
> +       if (fuse_passthrough_op(inode, FUSE_SETATTR))
> +               return fuse_passthrough_setattr(entry, attr);
> +
>         if (attr->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) {
>                 attr->ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID |
>                                     ATTR_MODE);
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index 89c9333e9702..0d978a9837a0 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -1279,7 +1279,7 @@ ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from);
>
>  /* Inode passthrough operations for backing file attached to inode */
>  #define FUSE_PASSTHROUGH_INODE_OPS \
> -       (FUSE_PASSTHROUGH_OP_GETATTR)
> +       (FUSE_PASSTHROUGH_OP_GETATTR | FUSE_PASSTHROUGH_OP_SETATTR)
>
>  #define FUSE_BACKING_MAP_OP(map, op) \
>         ((map)->ops_mask & FUSE_PASSTHROUGH_OP(op))
> @@ -1367,6 +1367,7 @@ static inline bool fuse_passthrough_op(struct inode *inode, enum fuse_opcode op)
>
>  int fuse_passthrough_getattr(struct inode *inode, struct kstat *stat,
>                              u32 request_mask, unsigned int flags);
> +int fuse_passthrough_setattr(struct dentry *entry, struct iattr *attr);
>
>  static inline bool fuse_use_entry2(struct fuse_conn *fc)
>  {
> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
> index ae0137caa06d..c083ab68537e 100644
> --- a/fs/fuse/passthrough.c
> +++ b/fs/fuse/passthrough.c
> @@ -9,6 +9,8 @@
>
>  #include <linux/file.h>
>  #include <linux/backing-file.h>
> +#include <linux/backing-inode.h>
> +#include <linux/posix_acl.h>
>  #include <linux/splice.h>
>
>  static void fuse_file_accessed(struct file *file)
> @@ -275,3 +277,29 @@ int fuse_passthrough_getattr(struct inode *inode, struct kstat *stat,
>
>         return 0;
>  }
> +
> +int fuse_passthrough_setattr(struct dentry *entry, struct iattr *attr)
> +{
> +       struct inode *inode = d_inode(entry);
> +       struct fuse_conn *fc = get_fuse_conn(inode);
> +       struct fuse_inode *fi = get_fuse_inode(inode);
> +       struct fuse_backing *fb = fuse_inode_backing(fi);
> +       struct path path;
> +       int err;
> +
> +       err = setattr_prepare(&nop_mnt_idmap, entry, attr);
> +       if (err)
> +               return err;
> +
> +       path.mnt = fb->file->f_path.mnt;
> +       path.dentry = fb->file->f_path.dentry;
> +
> +       err = backing_inode_setattr(entry, &path, attr, fb->cred);
> +       if (err)
> +               return err;
> +
> +       if (fc->posix_acl)
> +               forget_all_cached_acls(inode);
> +
> +       return 0;
> +}
> diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
> index 3963631558f9..040fee549bb9 100644
> --- a/include/uapi/linux/fuse.h
> +++ b/include/uapi/linux/fuse.h
> @@ -1158,6 +1158,7 @@ struct fuse_backing_map {
>  #define FUSE_PASSTHROUGH_OP_WRITE      FUSE_PASSTHROUGH_OP(FUSE_WRITE)
>  #define FUSE_PASSTHROUGH_OP_READDIR    FUSE_PASSTHROUGH_OP(FUSE_READDIR)
>  #define FUSE_PASSTHROUGH_OP_GETATTR    FUSE_PASSTHROUGH_OP(FUSE_GETATTR)
> +#define FUSE_PASSTHROUGH_OP_SETATTR    FUSE_PASSTHROUGH_OP(FUSE_SETATTR)
>
>  /* Device ioctls: */
>  #define FUSE_DEV_IOC_MAGIC             229
> --
> 2.52.0
>