]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
libfs: add stashed_dentry_prune()
authorChristian Brauner <brauner@kernel.org>
Wed, 21 Feb 2024 08:59:51 +0000 (09:59 +0100)
committerChristian Brauner <brauner@kernel.org>
Fri, 1 Mar 2024 11:26:29 +0000 (12:26 +0100)
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>
fs/internal.h
fs/libfs.c
fs/nsfs.c
fs/pidfs.c

index a34531bcad6ebee32dda160faf45e0f30934d614..b0c843c3fa3c4eae13531ecfea64dc2606fbf11b 100644 (file)
@@ -314,3 +314,4 @@ int path_from_stashed(struct dentry **stashed, unsigned long ino,
                      struct vfsmount *mnt, const struct file_operations *fops,
                      const struct inode_operations *iops, void *data,
                      struct path *path);
+void stashed_dentry_prune(struct dentry *dentry);
index 7617e1bc6e5ba9f71f0dd9b27e5dfcc7f983a587..472f21bd032549c5531ed8054f49aac5648f223b 100644 (file)
@@ -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);
+}
index 3a36bb62353cf1e8d1e9f7b41305e69fb17a3ac7..2ce229af34e97ce79d50da0fb671cd599568f06c 100644 (file)
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -34,22 +34,10 @@ static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
                ns_ops->name, inode->i_ino);
 }
 
-static void ns_prune_dentry(struct dentry *dentry)
-{
-       struct inode *inode;
-
-       inode = d_inode(dentry);
-       if (inode) {
-               struct ns_common *ns = inode->i_private;
-               cmpxchg(&ns->stashed, dentry, NULL);
-       }
-}
-
-const struct dentry_operations ns_dentry_operations =
-{
-       .d_prune        = ns_prune_dentry,
+const struct dentry_operations ns_dentry_operations = {
        .d_delete       = always_delete_dentry,
        .d_dname        = ns_dname,
+       .d_prune        = stashed_dentry_prune,
 };
 
 static void nsfs_evict(struct inode *inode)
index 5f33c820b7f8e7599013b206af2ee336764a96e4..d38b7a18499420940c32612d47a2974bf34a0c5b 100644 (file)
@@ -187,21 +187,10 @@ static char *pidfs_dname(struct dentry *dentry, char *buffer, int buflen)
                             d_inode(dentry)->i_ino);
 }
 
-static void pidfs_prune_dentry(struct dentry *dentry)
-{
-       struct inode *inode;
-
-       inode = d_inode(dentry);
-       if (inode) {
-               struct pid *pid = inode->i_private;
-               cmpxchg(&pid->stashed, dentry, NULL);
-       }
-}
-
 static const struct dentry_operations pidfs_dentry_operations = {
        .d_delete       = always_delete_dentry,
        .d_dname        = pidfs_dname,
-       .d_prune        = pidfs_prune_dentry,
+       .d_prune        = stashed_dentry_prune,
 };
 
 static int pidfs_init_fs_context(struct fs_context *fc)