rcuwalk: recheck mount_lock after mountpoint crossing attempts
[kernel/kernel-generic.git] / fs / namei.c
index cfe6608..399f637 100644 (file)
@@ -1098,7 +1098,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                        return false;
 
                if (!d_mountpoint(path->dentry))
-                       break;
+                       return true;
 
                mounted = __lookup_mnt(path->mnt, path->dentry);
                if (!mounted)
@@ -1114,20 +1114,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
                 */
                *inode = path->dentry->d_inode;
        }
-       return true;
-}
-
-static void follow_mount_rcu(struct nameidata *nd)
-{
-       while (d_mountpoint(nd->path.dentry)) {
-               struct mount *mounted;
-               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
-               if (!mounted)
-                       break;
-               nd->path.mnt = &mounted->mnt;
-               nd->path.dentry = mounted->mnt.mnt_root;
-               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
-       }
+       return read_seqretry(&mount_lock, nd->m_seq);
 }
 
 static int follow_dotdot_rcu(struct nameidata *nd)
@@ -1155,7 +1142,17 @@ static int follow_dotdot_rcu(struct nameidata *nd)
                        break;
                nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
        }
-       follow_mount_rcu(nd);
+       while (d_mountpoint(nd->path.dentry)) {
+               struct mount *mounted;
+               mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
+               if (!mounted)
+                       break;
+               nd->path.mnt = &mounted->mnt;
+               nd->path.dentry = mounted->mnt.mnt_root;
+               nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
+               if (!read_seqretry(&mount_lock, nd->m_seq))
+                       goto failed;
+       }
        nd->inode = nd->path.dentry->d_inode;
        return 0;