On Fri, 2025-02-21 at 10:36 +1100, NeilBrown wrote: > fuse already uses d_splice_alias() to ensure an appropriate dentry is > found for a newly created dentry. Now that ->mkdir can return that > dentry we do so. > > This requires changing create_new_entry() to return a dentry and > handling that change in all callers. > > Signed-off-by: NeilBrown <neilb@xxxxxxx> > --- > fs/fuse/dir.c | 55 +++++++++++++++++++++++++++++++-------------------- > 1 file changed, 34 insertions(+), 21 deletions(-) > > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c > index 5bb65f38bfb8..8c44c9c73c38 100644 > --- a/fs/fuse/dir.c > +++ b/fs/fuse/dir.c > @@ -781,9 +781,9 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, > /* > * Code shared between mknod, mkdir, symlink and link > */ > -static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > - struct fuse_args *args, struct inode *dir, > - struct dentry *entry, umode_t mode) > +static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > + struct fuse_args *args, struct inode *dir, > + struct dentry *entry, umode_t mode) > { > struct fuse_entry_out outarg; > struct inode *inode; > @@ -792,11 +792,11 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > struct fuse_forget_link *forget; > > if (fuse_is_bad(dir)) > - return -EIO; > + return ERR_PTR(-EIO); > > forget = fuse_alloc_forget(); > if (!forget) > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > > memset(&outarg, 0, sizeof(outarg)); > args->nodeid = get_node_id(dir); > @@ -826,29 +826,27 @@ static int create_new_entry(struct mnt_idmap *idmap, struct fuse_mount *fm, > &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0); > if (!inode) { > fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); > - return -ENOMEM; > + return ERR_PTR(-ENOMEM); > } > kfree(forget); > > d_drop(entry); > d = d_splice_alias(inode, entry); > if (IS_ERR(d)) > - return PTR_ERR(d); > + return d; > > - if (d) { > + if (d) > fuse_change_entry_timeout(d, &outarg); > - dput(d); > - } else { > + else > fuse_change_entry_timeout(entry, &outarg); > - } > fuse_dir_changed(dir); > - return 0; > + return d; > > out_put_forget_req: > if (err == -EEXIST) > fuse_invalidate_entry(entry); > kfree(forget); > - return err; > + return ERR_PTR(err); > } > > static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, > @@ -856,6 +854,7 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, > { > struct fuse_mknod_in inarg; > struct fuse_mount *fm = get_fuse_mount(dir); > + struct dentry *de; > FUSE_ARGS(args); > > if (!fm->fc->dont_mask) > @@ -871,7 +870,12 @@ static int fuse_mknod(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[0].value = &inarg; > args.in_args[1].size = entry->d_name.len + 1; > args.in_args[1].value = entry->d_name.name; > - return create_new_entry(idmap, fm, &args, dir, entry, mode); > + de = create_new_entry(idmap, fm, &args, dir, entry, mode); > + if (IS_ERR(de)) > + return PTR_ERR(de); > + if (de) > + dput(de); > + return 0; > } > > static int fuse_create(struct mnt_idmap *idmap, struct inode *dir, > @@ -917,7 +921,7 @@ static struct dentry *fuse_mkdir(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[0].value = &inarg; > args.in_args[1].size = entry->d_name.len + 1; > args.in_args[1].value = entry->d_name.name; > - return ERR_PTR(create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR)); > + return create_new_entry(idmap, fm, &args, dir, entry, S_IFDIR); > } > > static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, > @@ -925,6 +929,7 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, > { > struct fuse_mount *fm = get_fuse_mount(dir); > unsigned len = strlen(link) + 1; > + struct dentry *de; > FUSE_ARGS(args); > > args.opcode = FUSE_SYMLINK; > @@ -934,7 +939,12 @@ static int fuse_symlink(struct mnt_idmap *idmap, struct inode *dir, > args.in_args[1].value = entry->d_name.name; > args.in_args[2].size = len; > args.in_args[2].value = link; > - return create_new_entry(idmap, fm, &args, dir, entry, S_IFLNK); > + de = create_new_entry(idmap, fm, &args, dir, entry, S_IFLNK); > + if (IS_ERR(de)) > + return PTR_ERR(de); > + if (de) > + dput(de); > + return 0; > } > > void fuse_flush_time_update(struct inode *inode) > @@ -1117,7 +1127,7 @@ static int fuse_rename2(struct mnt_idmap *idmap, struct inode *olddir, > static int fuse_link(struct dentry *entry, struct inode *newdir, > struct dentry *newent) > { > - int err; > + struct dentry *de; > struct fuse_link_in inarg; > struct inode *inode = d_inode(entry); > struct fuse_mount *fm = get_fuse_mount(inode); > @@ -1131,13 +1141,16 @@ static int fuse_link(struct dentry *entry, struct inode *newdir, > args.in_args[0].value = &inarg; > args.in_args[1].size = newent->d_name.len + 1; > args.in_args[1].value = newent->d_name.name; > - err = create_new_entry(&invalid_mnt_idmap, fm, &args, newdir, newent, inode->i_mode); > - if (!err) > + de = create_new_entry(&invalid_mnt_idmap, fm, &args, newdir, newent, inode->i_mode); > + if (!IS_ERR(de)) { > + if (de) > + dput(de); > + de = NULL; > fuse_update_ctime_in_cache(inode); > - else if (err == -EINTR) > + } else if (PTR_ERR(de) == -EINTR) > fuse_invalidate_attr(inode); > > - return err; > + return PTR_ERR(de); > } > > static void fuse_fillattr(struct mnt_idmap *idmap, struct inode *inode, Pretty straightforward. Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx>