step_into(): move fetching ->d_inode past handle_mounts()
authorAl Viro <viro@zeniv.linux.org.uk>
Mon, 4 Jul 2022 02:35:56 +0000 (22:35 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Wed, 6 Jul 2022 17:16:07 +0000 (13:16 -0400)
... and lose messing with it in __follow_mount_rcu()

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namei.c

index 3e30cec54ced7f7323ee2d9b3f14d945f0800e9d..ed3ffd9b22a369b516c753f0e76adf74ef4ee312 100644 (file)
@@ -1474,8 +1474,7 @@ EXPORT_SYMBOL(follow_down);
  * Try to skip to top of mountpoint pile in rcuwalk mode.  Fail if
  * we meet a managed dentry that would need blocking.
  */
-static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
-                              struct inode **inode)
+static bool __follow_mount_rcu(struct nameidata *nd, struct path *path)
 {
        struct dentry *dentry = path->dentry;
        unsigned int flags = dentry->d_flags;
@@ -1505,13 +1504,6 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                                dentry = path->dentry = mounted->mnt.mnt_root;
                                nd->state |= ND_JUMPED;
                                nd->next_seq = read_seqcount_begin(&dentry->d_seq);
-                               *inode = dentry->d_inode;
-                               /*
-                                * We don't need to re-check ->d_seq after this
-                                * ->d_inode read - there will be an RCU delay
-                                * between mount hash removal and ->mnt_root
-                                * becoming unpinned.
-                                */
                                flags = dentry->d_flags;
                                // makes sure that non-RCU pathwalk could reach
                                // this state.
@@ -1527,7 +1519,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
 }
 
 static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
-                         struct path *path, struct inode **inode)
+                         struct path *path)
 {
        bool jumped;
        int ret;
@@ -1536,12 +1528,7 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
        path->dentry = dentry;
        if (nd->flags & LOOKUP_RCU) {
                unsigned int seq = nd->next_seq;
-               *inode = dentry->d_inode;
-               if (read_seqcount_retry(&dentry->d_seq, seq))
-                       return -ECHILD;
-               if (unlikely(!*inode))
-                       return -ENOENT;
-               if (likely(__follow_mount_rcu(nd, path, inode)))
+               if (likely(__follow_mount_rcu(nd, path)))
                        return 0;
                // *path and nd->next_seq might've been clobbered
                path->mnt = nd->path.mnt;
@@ -1561,8 +1548,6 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
                dput(path->dentry);
                if (path->mnt != nd->path.mnt)
                        mntput(path->mnt);
-       } else {
-               *inode = d_backing_inode(path->dentry);
        }
        return ret;
 }
@@ -1843,15 +1828,21 @@ static const char *step_into(struct nameidata *nd, int flags,
 {
        struct path path;
        struct inode *inode;
-       int err = handle_mounts(nd, dentry, &path, &inode);
+       int err = handle_mounts(nd, dentry, &path);
 
        if (err < 0)
                return ERR_PTR(err);
+       inode = path.dentry->d_inode;
        if (likely(!d_is_symlink(path.dentry)) ||
           ((flags & WALK_TRAILING) && !(nd->flags & LOOKUP_FOLLOW)) ||
           (flags & WALK_NOFOLLOW)) {
                /* not a symlink or should not follow */
-               if (!(nd->flags & LOOKUP_RCU)) {
+               if (nd->flags & LOOKUP_RCU) {
+                       if (read_seqcount_retry(&path.dentry->d_seq, nd->next_seq))
+                               return ERR_PTR(-ECHILD);
+                       if (unlikely(!inode))
+                               return ERR_PTR(-ENOENT);
+               } else {
                        dput(nd->path.dentry);
                        if (nd->path.mnt != path.mnt)
                                mntput(nd->path.mnt);