diff options
author | Christian Brauner <brauner@kernel.org> | 2024-02-21 09:59:51 +0100 |
---|---|---|
committer | Christian Brauner <brauner@kernel.org> | 2024-03-01 12:26:29 +0100 |
commit | 2558e3b23112adb82a558bab616890a790a38bc6 (patch) | |
tree | 89ce523bb85eab34592d8d859469858e90f9ef8f /fs/libfs.c | |
parent | 159a0d9fd50b92cc48e4c82cde79c4cb34c85953 (diff) |
libfs: add stashed_dentry_prune()
Both pidfs and nsfs use a memory location to stash a dentry for reuse by
concurrent openers. Right now two custom
dentry->d_prune::{ns,pidfs}_prune_dentry() methods are needed that do
the same thing. The only thing that differs is that they need to get to
the memory location to store or retrieve the dentry from differently.
Fix that by remember the stashing location for the dentry in
dentry->d_fsdata which allows us to retrieve it in dentry->d_prune. That
in turn makes it possible to add a common helper that pidfs and nsfs can
both use.
Link: https://lore.kernel.org/r/CAHk-=wg8cHY=i3m6RnXQ2Y2W8psicKWQEZq1=94ivUiviM-0OA@mail.gmail.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'fs/libfs.c')
-rw-r--r-- | fs/libfs.c | 29 |
1 files changed, 27 insertions, 2 deletions
diff --git a/fs/libfs.c b/fs/libfs.c index 7617e1bc6e5b..472f21bd0325 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -1988,7 +1988,8 @@ static inline struct dentry *get_stashed_dentry(struct dentry *stashed) return dentry; } -static struct dentry *prepare_anon_dentry(unsigned long ino, +static struct dentry *prepare_anon_dentry(struct dentry **stashed, + unsigned long ino, struct super_block *sb, const struct file_operations *fops, const struct inode_operations *iops, @@ -2019,6 +2020,9 @@ static struct dentry *prepare_anon_dentry(unsigned long ino, inode->i_private = data; simple_inode_init_ts(inode); + /* Store address of location where dentry's supposed to be stashed. */ + dentry->d_fsdata = stashed; + /* @data is now owned by the fs */ d_instantiate(dentry, inode); return dentry; @@ -2081,7 +2085,7 @@ int path_from_stashed(struct dentry **stashed, unsigned long ino, goto out_path; /* Allocate a new dentry. */ - dentry = prepare_anon_dentry(ino, mnt->mnt_sb, fops, iops, data); + dentry = prepare_anon_dentry(stashed, ino, mnt->mnt_sb, fops, iops, data); if (IS_ERR(dentry)) return PTR_ERR(dentry); @@ -2092,6 +2096,27 @@ int path_from_stashed(struct dentry **stashed, unsigned long ino, ret = 1; out_path: + WARN_ON_ONCE(path->dentry->d_fsdata != stashed); + WARN_ON_ONCE(d_inode(path->dentry)->i_private != data); path->mnt = mntget(mnt); return ret; } + +void stashed_dentry_prune(struct dentry *dentry) +{ + struct dentry **stashed = dentry->d_fsdata; + struct inode *inode = d_inode(dentry); + + if (WARN_ON_ONCE(!stashed)) + return; + + if (!inode) + return; + + /* + * Only replace our own @dentry as someone else might've + * already cleared out @dentry and stashed their own + * dentry in there. + */ + cmpxchg(stashed, dentry, NULL); +} |