Skip to content

Commit 07fd7c3

Browse files
committed
libfs: add path_from_stashed()
Add a helper for both nsfs and pidfs to reuse an already stashed dentry or to add and stash a new dentry. Link: https://lore.kernel.org/r/20240218-neufahrzeuge-brauhaus-fb0eb6459771@brauner Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent cb12fd8 commit 07fd7c3

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

fs/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,6 @@ ssize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *po
310310
struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns);
311311
struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap);
312312
void mnt_idmap_put(struct mnt_idmap *idmap);
313+
int path_from_stashed(struct dentry **stashed, unsigned long ino,
314+
struct vfsmount *mnt, const struct file_operations *fops,
315+
void *data, struct path *path);

fs/libfs.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,3 +1973,97 @@ struct timespec64 simple_inode_init_ts(struct inode *inode)
19731973
return ts;
19741974
}
19751975
EXPORT_SYMBOL(simple_inode_init_ts);
1976+
1977+
static inline struct dentry *get_stashed_dentry(struct dentry *stashed)
1978+
{
1979+
struct dentry *dentry;
1980+
1981+
guard(rcu)();
1982+
dentry = READ_ONCE(stashed);
1983+
if (!dentry)
1984+
return NULL;
1985+
if (!lockref_get_not_dead(&dentry->d_lockref))
1986+
return NULL;
1987+
return dentry;
1988+
}
1989+
1990+
static struct dentry *stash_dentry(struct dentry **stashed, unsigned long ino,
1991+
struct super_block *sb,
1992+
const struct file_operations *fops,
1993+
void *data)
1994+
{
1995+
struct dentry *dentry;
1996+
struct inode *inode;
1997+
1998+
dentry = d_alloc_anon(sb);
1999+
if (!dentry)
2000+
return ERR_PTR(-ENOMEM);
2001+
2002+
inode = new_inode_pseudo(sb);
2003+
if (!inode) {
2004+
dput(dentry);
2005+
return ERR_PTR(-ENOMEM);
2006+
}
2007+
2008+
inode->i_ino = ino;
2009+
inode->i_flags |= S_IMMUTABLE;
2010+
inode->i_mode = S_IFREG | S_IRUGO;
2011+
inode->i_fop = fops;
2012+
inode->i_private = data;
2013+
simple_inode_init_ts(inode);
2014+
2015+
/* @data is now owned by the fs */
2016+
d_instantiate(dentry, inode);
2017+
2018+
if (cmpxchg(stashed, NULL, dentry)) {
2019+
d_delete(dentry); /* make sure ->d_prune() does nothing */
2020+
dput(dentry);
2021+
cpu_relax();
2022+
return ERR_PTR(-EAGAIN);
2023+
}
2024+
2025+
return dentry;
2026+
}
2027+
2028+
/**
2029+
* path_from_stashed - create path from stashed or new dentry
2030+
* @stashed: where to retrieve or stash dentry
2031+
* @ino: inode number to use
2032+
* @mnt: mnt of the filesystems to use
2033+
* @fops: file operations to use
2034+
* @data: data to store in inode->i_private
2035+
* @path: path to create
2036+
*
2037+
* The function tries to retrieve a stashed dentry from @stashed. If the dentry
2038+
* is still valid then it will be reused. If the dentry isn't able the function
2039+
* will allocate a new dentry and inode. It will then try to update @stashed
2040+
* with the newly added dentry. If it fails -EAGAIN is returned and the caller
2041+
* my retry.
2042+
*
2043+
* Special-purpose helper for nsfs and pidfs.
2044+
*
2045+
* Return: If 0 or an error is returned the caller can be sure that @data must
2046+
* be cleaned up. If 1 or -EAGAIN is returned @data is owned by the
2047+
* filesystem.
2048+
*/
2049+
int path_from_stashed(struct dentry **stashed, unsigned long ino,
2050+
struct vfsmount *mnt, const struct file_operations *fops,
2051+
void *data, struct path *path)
2052+
{
2053+
struct dentry *dentry;
2054+
int ret = 0;
2055+
2056+
dentry = get_stashed_dentry(*stashed);
2057+
if (dentry)
2058+
goto out_path;
2059+
2060+
dentry = stash_dentry(stashed, ino, mnt->mnt_sb, fops, data);
2061+
if (IS_ERR(dentry))
2062+
return PTR_ERR(dentry);
2063+
ret = 1;
2064+
2065+
out_path:
2066+
path->dentry = dentry;
2067+
path->mnt = mntget(mnt);
2068+
return ret;
2069+
}

0 commit comments

Comments
 (0)