On Fri, 2025-06-13 at 08:34 +0100, Al Viro wrote: > Set the things up for kernel-initiated creation of object in > a tree-in-dcache filesystem. With respect to locking it's > an equivalent of filename_create() - we either get a negative > dentry with locked parent, or ERR_PTR() and no locks taken. > > tracefs and debugfs had that open-coded as part of their > object creation machinery; switched to calling new helper. > > Signed-off-by: Al Viro <viro@xxxxxxxxxxxxxxxxxx> > --- > fs/debugfs/inode.c | 21 ++------------------- > fs/libfs.c | 25 +++++++++++++++++++++++++ > fs/tracefs/inode.c | 15 ++------------- > include/linux/fs.h | 1 + > 4 files changed, 30 insertions(+), 32 deletions(-) > > diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c > index 30c4944e1862..08638e39bd12 100644 > --- a/fs/debugfs/inode.c > +++ b/fs/debugfs/inode.c > @@ -384,26 +384,9 @@ static struct dentry *start_creating(const char *name, struct dentry *parent) > if (!parent) > parent = debugfs_mount->mnt_root; > > - inode_lock(d_inode(parent)); > - if (unlikely(IS_DEADDIR(d_inode(parent)))) > - dentry = ERR_PTR(-ENOENT); > - else > - dentry = lookup_noperm(&QSTR(name), parent); > - if (!IS_ERR(dentry) && d_really_is_positive(dentry)) { > - if (d_is_dir(dentry)) > - pr_err("Directory '%s' with parent '%s' already present!\n", > - name, parent->d_name.name); > - else > - pr_err("File '%s' in directory '%s' already present!\n", > - name, parent->d_name.name); Any chance we could keep a pr_err() for this case? I was doing some debugfs work recently, and found it helpful. > - dput(dentry); > - dentry = ERR_PTR(-EEXIST); > - } > - > - if (IS_ERR(dentry)) { > - inode_unlock(d_inode(parent)); > + dentry = simple_start_creating(parent, name); > + if (IS_ERR(dentry)) > simple_release_fs(&debugfs_mount, &debugfs_mount_count); > - } > > return dentry; > } > diff --git a/fs/libfs.c b/fs/libfs.c > index 42e226af6095..833ad5ed10f5 100644 > --- a/fs/libfs.c > +++ b/fs/libfs.c > @@ -2260,3 +2260,28 @@ void stashed_dentry_prune(struct dentry *dentry) > */ > cmpxchg(stashed, dentry, NULL); > } > + > +/* parent must be held exclusive */ > +struct dentry *simple_start_creating(struct dentry *parent, const char *name) > +{ > + struct dentry *dentry; > + struct inode *dir = d_inode(parent); > + > + inode_lock(dir); > + if (unlikely(IS_DEADDIR(dir))) { > + inode_unlock(dir); > + return ERR_PTR(-ENOENT); > + } > + dentry = lookup_noperm(&QSTR(name), parent); > + if (IS_ERR(dentry)) { > + inode_unlock(dir); > + return dentry; > + } > + if (dentry->d_inode) { > + dput(dentry); > + inode_unlock(dir); > + return ERR_PTR(-EEXIST); > + } > + return dentry; > +} > +EXPORT_SYMBOL(simple_start_creating); > diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c > index a3fd3cc591bd..4e5d091e9263 100644 > --- a/fs/tracefs/inode.c > +++ b/fs/tracefs/inode.c > @@ -551,20 +551,9 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent) > if (!parent) > parent = tracefs_mount->mnt_root; > > - inode_lock(d_inode(parent)); > - if (unlikely(IS_DEADDIR(d_inode(parent)))) > - dentry = ERR_PTR(-ENOENT); > - else > - dentry = lookup_noperm(&QSTR(name), parent); > - if (!IS_ERR(dentry) && d_inode(dentry)) { > - dput(dentry); > - dentry = ERR_PTR(-EEXIST); > - } > - > - if (IS_ERR(dentry)) { > - inode_unlock(d_inode(parent)); > + dentry = simple_start_creating(parent, name); > + if (IS_ERR(dentry)) > simple_release_fs(&tracefs_mount, &tracefs_mount_count); > - } > > return dentry; > } > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 96c7925a6551..9f75f8836bbd 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -3619,6 +3619,7 @@ extern int simple_fill_super(struct super_block *, unsigned long, > const struct tree_descr *); > extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count); > extern void simple_release_fs(struct vfsmount **mount, int *count); > +struct dentry *simple_start_creating(struct dentry *, const char *); > > extern ssize_t simple_read_from_buffer(void __user *to, size_t count, > loff_t *ppos, const void *from, size_t available); -- Jeff Layton <jlayton@xxxxxxxxxx>