Re: [PATCH v2 13/21] fuse: add passthrough lookup
Amir Goldstein <[email protected]> Sat, 16 May 2026 23:11:09 +0200
| Newsgroups | org.kernel.vger.linux-unionfs,dev.linux.lists.fuse-devel |
|---|---|
| Message-ID | <CAOQ4uxhTzoDwrzf-7Zjg+NMO=m2Zqm4du83endsNzejbt1iHqA@mail.gmail.com> |
On Sat, May 16, 2026 at 2:52 AM Joanne Koong <[email protected]> wrote: > > Use the new/extended struct fuse_entry2_out for lookups. If a backing id > is set, associate the fuse inode with the backing inode that should be > used for passthrough operations. > > If no backing id was set, cache the statx attributes from the reply. The 3 lookup patches look fine in general, but I will review them more closely after I have a clear understanding on the desired protocol. Thanks, Amir. > > Signed-off-by: Joanne Koong <[email protected]> > --- > fs/fuse/dir.c | 66 ++++++++++++++++++++++++++++++++++++++++----------- > 1 file changed, 52 insertions(+), 14 deletions(-) > > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c > index b7a9d2b0476a..3a6adae530da 100644 > --- a/fs/fuse/dir.c > +++ b/fs/fuse/dir.c > @@ -420,10 +420,10 @@ static void fuse_entry2_to_entry(struct fuse_entry2_out *outarg2, > outarg->attr.flags = outarg2->flags; > } > > -static __maybe_unused int fuse_process_entry2(struct fuse_conn *fc, > - struct fuse_entry2_out *outarg2, > - struct fuse_entry_out *outarg, > - struct fuse_statx **sxp) > +static int fuse_process_entry2(struct fuse_conn *fc, > + struct fuse_entry2_out *outarg2, > + struct fuse_entry_out *outarg, > + struct fuse_statx **sxp) > { > if (!fuse_use_entry2(fc)) > return 0; > @@ -469,7 +469,9 @@ static int fuse_dentry_revalidate(struct inode *dir, const struct qstr *name, > struct fuse_entry_out outarg; > struct fuse_entry2_out outarg2; > struct fuse_forget_link *forget; > + struct fuse_statx *sx = NULL; > FUSE_ARGS(args); > + int backing_id = 0; > u64 attr_version; > bool need_reval; > int ret; > @@ -512,15 +514,27 @@ static int fuse_dentry_revalidate(struct inode *dir, const struct qstr *name, > > fuse_lookup_init(fc, &args, get_node_id(dir), name, &outarg, &outarg2); > ret = fuse_simple_request(get_fuse_mount(inode), &args); > + if (!ret) > + backing_id = fuse_process_entry2(fc, &outarg2, &outarg, &sx); > if (ret || !outarg.nodeid) { > kfree(forget); > return (ret == -ENOMEM || ret == -EINTR) ? ret : 0; > } > > + if (backing_id < 0) { > + ret = backing_id; > + goto forget; > + } > + > + ret = 0; > if (outarg.nodeid != get_node_id(inode) || > - !!IS_AUTOMOUNT(inode) != !!(outarg.attr.flags & FUSE_ATTR_SUBMOUNT)) { > - fuse_chan_queue_forget(fc->chan, forget, outarg.nodeid, 1); > - return 0; > + !!IS_AUTOMOUNT(inode) != !!(outarg.attr.flags & FUSE_ATTR_SUBMOUNT)) > + goto forget; > + > + if (backing_id) { > + ret = fuse_inode_set_passthrough(inode, backing_id); > + if (ret) > + goto forget; > } > > kfree(forget); > @@ -534,10 +548,14 @@ static int fuse_dentry_revalidate(struct inode *dir, const struct qstr *name, > return 0; > > forget_all_cached_acls(inode); > - fuse_change_attributes(inode, &outarg.attr, NULL, ATTR_TIMEOUT(&outarg), > + fuse_change_attributes(inode, &outarg.attr, sx, ATTR_TIMEOUT(&outarg), > attr_version); > fuse_change_entry_timeout(entry, &outarg); > return 1; > + > +forget: > + fuse_chan_queue_forget(fc->chan, forget, outarg.nodeid, 1); > + return ret; > } > > static int fuse_dentry_init(struct dentry *dentry) > @@ -631,6 +649,8 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name > struct fuse_forget_link *forget; > u64 attr_version, evict_ctr; > struct fuse_entry2_out outarg2; > + struct fuse_statx *sx = NULL; > + int backing_id; > int err; > > *inode = NULL; > @@ -649,9 +669,18 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name > > fuse_lookup_init(fm->fc, &args, nodeid, name, outarg, &outarg2); > err = fuse_simple_request(fm, &args); > + if (err) > + goto out_put_forget; > + > + backing_id = fuse_process_entry2(fm->fc, &outarg2, outarg, &sx); > + > /* Zero nodeid is same as -ENOENT, but with valid timeout */ > - if (err || !outarg->nodeid) > + if (!outarg->nodeid) > goto out_put_forget; > + if (backing_id < 0) { > + err = backing_id; > + goto out_send_forget; > + } > > err = -EIO; > if (fuse_invalid_attr(&outarg->attr)) > @@ -662,19 +691,28 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name > } > > *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, > - &outarg->attr, NULL, ATTR_TIMEOUT(outarg), > + &outarg->attr, sx, ATTR_TIMEOUT(outarg), > attr_version, evict_ctr); > err = -ENOMEM; > - if (!*inode) { > - fuse_chan_queue_forget(fm->fc->chan, forget, outarg->nodeid, 1); > - goto out; > - } > + if (!*inode) > + goto out_send_forget; > + > err = 0; > + if (backing_id) { > + err = fuse_inode_set_passthrough(*inode, backing_id); > + if (err) { > + iput(*inode); > + *inode = NULL; > + } > + } > > out_put_forget: > kfree(forget); > out: > return err; > + out_send_forget: > + fuse_chan_queue_forget(fm->fc->chan, forget, outarg->nodeid, 1); > + return err; > } > > static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, > -- > 2.52.0 >