Re: [PATCH v2 02/21] fuse: prepare for passthrough of inode operations

Amir Goldstein <[email protected]> Sat, 16 May 2026 18:11:37 +0200
Newsgroups org.kernel.vger.linux-unionfs,dev.linux.lists.fuse-devel
Message-ID <CAOQ4uxhyZU_6jbv8kY8od_SgG9yQ6aX+KcB2c1um4DajJdSPqA@mail.gmail.com>
On Sat, May 16, 2026 at 3:34 AM Joanne Koong <[email protected]> wrote:
>
> On Fri, May 15, 2026 at 5:52 PM Joanne Koong <[email protected]> wrote:
> >
> > From: Amir Goldstein <[email protected]>
> >
> > So far, fuse passthrough was implemented for read/write/splice/mmap
> > operations for regular files opened with FOPEN_PASSTHROUGH.
> >
> > A backing file is attached to a fuse inode, but only for as long as
> > there are FOPEN_PASSTHROUGH files opened on this inode.
> >
> > We would like to attach a backing file to fuse inode also without an
> > open file to allow passthrough of some inode operations.
> >
> > Add field ops_mask to the input argument of FUSE_DEV_IOC_BACKING_OPEN
> > ioctl to declare the operations that would passthrough to the backing
> > file once it has been attached to the fuse inode on lookup.
> >
> > Setting the FUSE_READ/FUSE_WRITE operations in the ops_mask is not
> > required because those operations are implied by FOPEN_PASSTHROUGH.
> >
> > When setting operations other than FUSE_READ/FUSE_WRITE in ops_mask,
> > non-regular backing files are allowed, so we need to verify when
> > attaching a backing file to a fuse inode, that their file types match.
> >
> > For simplification of inode attribute caching, for now, require a
> > filesystem with FUSE_PASSTHROUGH_INO (one-to-one mapping from fuse inode
> > to backing inode) for setting up passthrough of any inode operations.
> > We may consider relaxing this requirement for some inode operations
> > in the future.
> >
> > Reviewed-by: Joanne Koong <[email protected]>
> > Signed-off-by: Amir Goldstein <[email protected]>
> > ---
> >  fs/fuse/backing.c         | 13 ++++++++++---
> >  fs/fuse/fuse_i.h          | 30 ++++++++++++++++++++++++++++++
> >  fs/fuse/iomode.c          | 16 ++++++++++++++++
> >  include/uapi/linux/fuse.h |  9 ++++++++-
> >  4 files changed, 64 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
> > index 4be9ccc5b3ff..0f1e1c1ec367 100644
> > --- a/include/uapi/linux/fuse.h
> > +++ b/include/uapi/linux/fuse.h
> > @@ -243,6 +243,7 @@
> >
> > +#define FUSE_PASSTHROUGH_OP(op)        (1ULL << ((op) - 1))
> > +
> > +/* op bits for fuse_backing_map ops_mask */
> > +#define FUSE_PASSTHROUGH_OP_READ       FUSE_PASSTHROUGH_OP(FUSE_READ)
> > +#define FUSE_PASSTHROUGH_OP_WRITE      FUSE_PASSTHROUGH_OP(FUSE_WRITE)
>
> Do you think we should couple the passthrough op code to the fuse
> opcode so closely, instead of defining the passthrough ops separately,
> eg doing something like this?:
>
> #define FUSE_PASSTHROUGH_READ         (1 << 0)
> #define FUSE_PASSTHROUGH_WRITE       (1 << 1)

Don't drop the _OP_ please
Need it to distinguish from FUSE_PASSTHROUGH{,_INO}
and we need to think if we want to format this as 32bit and extend later
or start with a u64 ops_mask format from the start.

>
> In the (far) future when some more advanced passthrough features get
> added (eg full subtree passthrough), it seems like we'd want to add a
> passthrough op for that,

I don't know. fuse_backing_map has flags, why would we want to put that
in ops_mask.

> but that wouldn't map to a fuse op. I think
> there are also some fuse ops we might skip defining as passthrough ops
> but are implicitly passed through (eg FUSE_STATX which is covered by
> FUSE_GETATTR),

This could also become the case with FUSE_CREATE{,_HANDLE}
or {FUSE,FUSEX}_CREAT.

TBH, the fact that some ops will never be in the mask and
that some ops have a canonical bit in itself does not justify creating
a different mapping. Do we also want to squeeze the mask into 32bit
and leave reserved space? my intuition is to leave it u64.

> so it seems more intuitive to define the passthrough
> ops as describing capabilities rather than implying that it describes
> what specific opcodes get passed through?

hmm. I guess you have a point that it is a bit limiting to commit
to this arithmetic in UAPI.

My thinking behind this was ease of use with these helpers:

       if (!fuse_passthrough_op(file_inode(in), FUSE_READ))

but those could just as well be macros:

static inline bool fuse_inode_passthrough_op(struct inode *inode,
                                            u64 opbit)...

#define FUSE_PASSTHROUGH_OP(inode, opname)    \
             fuse_passthrough_op(inode, FUSE_PASSTHROUGH_OP_ ## opname)

#define FUSE_BACKING_MAP_OP(map, opname) \
       ((map)->ops_mask & FUSE_PASSTHROUGH_OP ## opname))

...
       if (!FUSE_PASSTHROUGH_OP(file_inode(in), READ))

wdyt?

Thanks,
Amir.