OSDN Git Service

move handle_dots(), follow_dotdot() and follow_dotdot_rcu() past step_into()
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 26 Feb 2020 06:40:04 +0000 (01:40 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 14 Mar 2020 01:09:13 +0000 (21:09 -0400)
pure move; we are going to have step_into() called by that bunch.

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

index 577dc54..3ee3b87 100644 (file)
@@ -1363,70 +1363,6 @@ static inline int handle_mounts(struct nameidata *nd, struct dentry *dentry,
        return ret;
 }
 
-static int follow_dotdot_rcu(struct nameidata *nd)
-{
-       struct dentry *parent = NULL;
-       struct inode *inode = nd->inode;
-       unsigned seq;
-
-       while (1) {
-               if (path_equal(&nd->path, &nd->root))
-                       break;
-               if (nd->path.dentry != nd->path.mnt->mnt_root) {
-                       struct dentry *old = nd->path.dentry;
-
-                       parent = old->d_parent;
-                       inode = parent->d_inode;
-                       seq = read_seqcount_begin(&parent->d_seq);
-                       if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
-                               return -ECHILD;
-                       if (unlikely(!path_connected(nd->path.mnt, parent)))
-                               return -ECHILD;
-                       break;
-               } else {
-                       struct mount *mnt = real_mount(nd->path.mnt);
-                       struct mount *mparent = mnt->mnt_parent;
-                       struct dentry *mountpoint = mnt->mnt_mountpoint;
-                       struct inode *inode2 = mountpoint->d_inode;
-                       unsigned seq = read_seqcount_begin(&mountpoint->d_seq);
-                       if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
-                               return -ECHILD;
-                       if (&mparent->mnt == nd->path.mnt)
-                               break;
-                       if (unlikely(nd->flags & LOOKUP_NO_XDEV))
-                               return -ECHILD;
-                       /* we know that mountpoint was pinned */
-                       nd->path.dentry = mountpoint;
-                       nd->path.mnt = &mparent->mnt;
-                       inode = inode2;
-                       nd->seq = seq;
-               }
-       }
-       if (unlikely(!parent)) {
-               if (unlikely(nd->flags & LOOKUP_BENEATH))
-                       return -ECHILD;
-       } else {
-               nd->path.dentry = parent;
-               nd->seq = seq;
-       }
-       while (unlikely(d_mountpoint(nd->path.dentry))) {
-               struct mount *mounted;
-               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
-               if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
-                       return -ECHILD;
-               if (!mounted)
-                       break;
-               if (unlikely(nd->flags & LOOKUP_NO_XDEV))
-                       return -ECHILD;
-               nd->path.mnt = &mounted->mnt;
-               nd->path.dentry = mounted->mnt.mnt_root;
-               inode = nd->path.dentry->d_inode;
-               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
-       }
-       nd->inode = inode;
-       return 0;
-}
-
 /*
  * Skip to top of mountpoint pile in refwalk mode for follow_dotdot()
  */
@@ -1443,38 +1379,6 @@ static void follow_mount(struct path *path)
        }
 }
 
-static int follow_dotdot(struct nameidata *nd)
-{
-       struct dentry *parent = NULL;
-       while (1) {
-               if (path_equal(&nd->path, &nd->root))
-                       break;
-               if (nd->path.dentry != nd->path.mnt->mnt_root) {
-                       /* rare case of legitimate dget_parent()... */
-                       parent = dget_parent(nd->path.dentry);
-                       if (unlikely(!path_connected(nd->path.mnt, parent))) {
-                               dput(parent);
-                               return -ENOENT;
-                       }
-                       break;
-               }
-               if (!follow_up(&nd->path))
-                       break;
-               if (unlikely(nd->flags & LOOKUP_NO_XDEV))
-                       return -EXDEV;
-       }
-       if (unlikely(!parent)) {
-               if (unlikely(nd->flags & LOOKUP_BENEATH))
-                       return -EXDEV;
-       } else {
-               dput(nd->path.dentry);
-               nd->path.dentry = parent;
-       }
-       follow_mount(&nd->path);
-       nd->inode = nd->path.dentry->d_inode;
-       return 0;
-}
-
 /*
  * This looks up the name in dcache and possibly revalidates the found dentry.
  * NULL is returned if the dentry does not exist in the cache.
@@ -1654,40 +1558,6 @@ static inline int may_lookup(struct nameidata *nd)
        return inode_permission(nd->inode, MAY_EXEC);
 }
 
-static inline int handle_dots(struct nameidata *nd, int type)
-{
-       if (type == LAST_DOTDOT) {
-               int error = 0;
-
-               if (!nd->root.mnt) {
-                       error = set_root(nd);
-                       if (error)
-                               return error;
-               }
-               if (nd->flags & LOOKUP_RCU)
-                       error = follow_dotdot_rcu(nd);
-               else
-                       error = follow_dotdot(nd);
-               if (error)
-                       return error;
-
-               if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) {
-                       /*
-                        * If there was a racing rename or mount along our
-                        * path, then we can't be sure that ".." hasn't jumped
-                        * above nd->root (and so userspace should retry or use
-                        * some fallback).
-                        */
-                       smp_rmb();
-                       if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq)))
-                               return -EAGAIN;
-                       if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq)))
-                               return -EAGAIN;
-               }
-       }
-       return 0;
-}
-
 enum {WALK_TRAILING = 1, WALK_MORE = 2, WALK_NOFOLLOW = 4};
 
 static const char *pick_link(struct nameidata *nd, struct path *link,
@@ -1817,6 +1687,136 @@ static const char *step_into(struct nameidata *nd, int flags,
        return pick_link(nd, &path, inode, seq, flags);
 }
 
+static int follow_dotdot_rcu(struct nameidata *nd)
+{
+       struct dentry *parent = NULL;
+       struct inode *inode = nd->inode;
+       unsigned seq;
+
+       while (1) {
+               if (path_equal(&nd->path, &nd->root))
+                       break;
+               if (nd->path.dentry != nd->path.mnt->mnt_root) {
+                       struct dentry *old = nd->path.dentry;
+
+                       parent = old->d_parent;
+                       inode = parent->d_inode;
+                       seq = read_seqcount_begin(&parent->d_seq);
+                       if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq)))
+                               return -ECHILD;
+                       if (unlikely(!path_connected(nd->path.mnt, parent)))
+                               return -ECHILD;
+                       break;
+               } else {
+                       struct mount *mnt = real_mount(nd->path.mnt);
+                       struct mount *mparent = mnt->mnt_parent;
+                       struct dentry *mountpoint = mnt->mnt_mountpoint;
+                       struct inode *inode2 = mountpoint->d_inode;
+                       unsigned seq = read_seqcount_begin(&mountpoint->d_seq);
+                       if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
+                               return -ECHILD;
+                       if (&mparent->mnt == nd->path.mnt)
+                               break;
+                       if (unlikely(nd->flags & LOOKUP_NO_XDEV))
+                               return -ECHILD;
+                       /* we know that mountpoint was pinned */
+                       nd->path.dentry = mountpoint;
+                       nd->path.mnt = &mparent->mnt;
+                       inode = inode2;
+                       nd->seq = seq;
+               }
+       }
+       if (unlikely(!parent)) {
+               if (unlikely(nd->flags & LOOKUP_BENEATH))
+                       return -ECHILD;
+       } else {
+               nd->path.dentry = parent;
+               nd->seq = seq;
+       }
+       while (unlikely(d_mountpoint(nd->path.dentry))) {
+               struct mount *mounted;
+               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
+               if (unlikely(read_seqretry(&mount_lock, nd->m_seq)))
+                       return -ECHILD;
+               if (!mounted)
+                       break;
+               if (unlikely(nd->flags & LOOKUP_NO_XDEV))
+                       return -ECHILD;
+               nd->path.mnt = &mounted->mnt;
+               nd->path.dentry = mounted->mnt.mnt_root;
+               inode = nd->path.dentry->d_inode;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+       }
+       nd->inode = inode;
+       return 0;
+}
+
+static int follow_dotdot(struct nameidata *nd)
+{
+       struct dentry *parent = NULL;
+       while (1) {
+               if (path_equal(&nd->path, &nd->root))
+                       break;
+               if (nd->path.dentry != nd->path.mnt->mnt_root) {
+                       /* rare case of legitimate dget_parent()... */
+                       parent = dget_parent(nd->path.dentry);
+                       if (unlikely(!path_connected(nd->path.mnt, parent))) {
+                               dput(parent);
+                               return -ENOENT;
+                       }
+                       break;
+               }
+               if (!follow_up(&nd->path))
+                       break;
+               if (unlikely(nd->flags & LOOKUP_NO_XDEV))
+                       return -EXDEV;
+       }
+       if (unlikely(!parent)) {
+               if (unlikely(nd->flags & LOOKUP_BENEATH))
+                       return -EXDEV;
+       } else {
+               dput(nd->path.dentry);
+               nd->path.dentry = parent;
+       }
+       follow_mount(&nd->path);
+       nd->inode = nd->path.dentry->d_inode;
+       return 0;
+}
+
+static inline int handle_dots(struct nameidata *nd, int type)
+{
+       if (type == LAST_DOTDOT) {
+               int error = 0;
+
+               if (!nd->root.mnt) {
+                       error = set_root(nd);
+                       if (error)
+                               return error;
+               }
+               if (nd->flags & LOOKUP_RCU)
+                       error = follow_dotdot_rcu(nd);
+               else
+                       error = follow_dotdot(nd);
+               if (error)
+                       return error;
+
+               if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) {
+                       /*
+                        * If there was a racing rename or mount along our
+                        * path, then we can't be sure that ".." hasn't jumped
+                        * above nd->root (and so userspace should retry or use
+                        * some fallback).
+                        */
+                       smp_rmb();
+                       if (unlikely(__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq)))
+                               return -EAGAIN;
+                       if (unlikely(__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq)))
+                               return -EAGAIN;
+               }
+       }
+       return 0;
+}
+
 static const char *walk_component(struct nameidata *nd, int flags)
 {
        struct dentry *dentry;