mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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>
This commit is contained in:
parent
cb12fd8e0d
commit
07fd7c3298
2 changed files with 97 additions and 0 deletions
|
@ -310,3 +310,6 @@ ssize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *po
|
||||||
struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns);
|
struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns);
|
||||||
struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap);
|
struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap);
|
||||||
void mnt_idmap_put(struct mnt_idmap *idmap);
|
void mnt_idmap_put(struct mnt_idmap *idmap);
|
||||||
|
int path_from_stashed(struct dentry **stashed, unsigned long ino,
|
||||||
|
struct vfsmount *mnt, const struct file_operations *fops,
|
||||||
|
void *data, struct path *path);
|
||||||
|
|
94
fs/libfs.c
94
fs/libfs.c
|
@ -1973,3 +1973,97 @@ struct timespec64 simple_inode_init_ts(struct inode *inode)
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(simple_inode_init_ts);
|
EXPORT_SYMBOL(simple_inode_init_ts);
|
||||||
|
|
||||||
|
static inline struct dentry *get_stashed_dentry(struct dentry *stashed)
|
||||||
|
{
|
||||||
|
struct dentry *dentry;
|
||||||
|
|
||||||
|
guard(rcu)();
|
||||||
|
dentry = READ_ONCE(stashed);
|
||||||
|
if (!dentry)
|
||||||
|
return NULL;
|
||||||
|
if (!lockref_get_not_dead(&dentry->d_lockref))
|
||||||
|
return NULL;
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dentry *stash_dentry(struct dentry **stashed, unsigned long ino,
|
||||||
|
struct super_block *sb,
|
||||||
|
const struct file_operations *fops,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct dentry *dentry;
|
||||||
|
struct inode *inode;
|
||||||
|
|
||||||
|
dentry = d_alloc_anon(sb);
|
||||||
|
if (!dentry)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
inode = new_inode_pseudo(sb);
|
||||||
|
if (!inode) {
|
||||||
|
dput(dentry);
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
inode->i_ino = ino;
|
||||||
|
inode->i_flags |= S_IMMUTABLE;
|
||||||
|
inode->i_mode = S_IFREG | S_IRUGO;
|
||||||
|
inode->i_fop = fops;
|
||||||
|
inode->i_private = data;
|
||||||
|
simple_inode_init_ts(inode);
|
||||||
|
|
||||||
|
/* @data is now owned by the fs */
|
||||||
|
d_instantiate(dentry, inode);
|
||||||
|
|
||||||
|
if (cmpxchg(stashed, NULL, dentry)) {
|
||||||
|
d_delete(dentry); /* make sure ->d_prune() does nothing */
|
||||||
|
dput(dentry);
|
||||||
|
cpu_relax();
|
||||||
|
return ERR_PTR(-EAGAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dentry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* path_from_stashed - create path from stashed or new dentry
|
||||||
|
* @stashed: where to retrieve or stash dentry
|
||||||
|
* @ino: inode number to use
|
||||||
|
* @mnt: mnt of the filesystems to use
|
||||||
|
* @fops: file operations to use
|
||||||
|
* @data: data to store in inode->i_private
|
||||||
|
* @path: path to create
|
||||||
|
*
|
||||||
|
* The function tries to retrieve a stashed dentry from @stashed. If the dentry
|
||||||
|
* is still valid then it will be reused. If the dentry isn't able the function
|
||||||
|
* will allocate a new dentry and inode. It will then try to update @stashed
|
||||||
|
* with the newly added dentry. If it fails -EAGAIN is returned and the caller
|
||||||
|
* my retry.
|
||||||
|
*
|
||||||
|
* Special-purpose helper for nsfs and pidfs.
|
||||||
|
*
|
||||||
|
* Return: If 0 or an error is returned the caller can be sure that @data must
|
||||||
|
* be cleaned up. If 1 or -EAGAIN is returned @data is owned by the
|
||||||
|
* filesystem.
|
||||||
|
*/
|
||||||
|
int path_from_stashed(struct dentry **stashed, unsigned long ino,
|
||||||
|
struct vfsmount *mnt, const struct file_operations *fops,
|
||||||
|
void *data, struct path *path)
|
||||||
|
{
|
||||||
|
struct dentry *dentry;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
dentry = get_stashed_dentry(*stashed);
|
||||||
|
if (dentry)
|
||||||
|
goto out_path;
|
||||||
|
|
||||||
|
dentry = stash_dentry(stashed, ino, mnt->mnt_sb, fops, data);
|
||||||
|
if (IS_ERR(dentry))
|
||||||
|
return PTR_ERR(dentry);
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
out_path:
|
||||||
|
path->dentry = dentry;
|
||||||
|
path->mnt = mntget(mnt);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue