make handle_dots() leave RCU mode on error
authorAl Viro <viro@zeniv.linux.org.uk>
Fri, 4 Mar 2011 19:35:59 +0000 (14:35 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 14 Mar 2011 13:15:25 +0000 (09:15 -0400)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namei.c

index f09887a45831498525d7520e4bc7f4c59e1a8919..ea14bfb04785a17753be8c2159c609c3dc5be9c9 100644 (file)
@@ -1052,7 +1052,7 @@ static int follow_dotdot_rcu(struct nameidata *nd)
 
                        seq = read_seqcount_begin(&parent->d_seq);
                        if (read_seqcount_retry(&old->d_seq, nd->seq))
-                               return -ECHILD;
+                               goto failed;
                        inode = parent->d_inode;
                        nd->path.dentry = parent;
                        nd->seq = seq;
@@ -1065,8 +1065,14 @@ static int follow_dotdot_rcu(struct nameidata *nd)
        }
        __follow_mount_rcu(nd, &nd->path, &inode, true);
        nd->inode = inode;
-
        return 0;
+
+failed:
+       nd->flags &= ~LOOKUP_RCU;
+       nd->root.mnt = NULL;
+       rcu_read_unlock();
+       br_read_unlock(vfsmount_lock);
+       return -ECHILD;
 }
 
 /*
@@ -1405,9 +1411,8 @@ static int link_path_walk(const char *name, struct nameidata *nd)
                 * parent relationships.
                 */
                if (unlikely(type != LAST_NORM)) {
-                       err = handle_dots(nd, type);
-                       if (err)
-                               goto return_err;
+                       if (handle_dots(nd, type))
+                               return -ECHILD;
                        continue;
                }
 
@@ -1441,12 +1446,8 @@ last_component:
                nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
                if (lookup_flags & LOOKUP_PARENT)
                        goto lookup_parent;
-               if (unlikely(type != LAST_NORM)) {
-                       err = handle_dots(nd, type);
-                       if (err)
-                               goto return_err;
-                       return 0;
-               }
+               if (unlikely(type != LAST_NORM))
+                       return handle_dots(nd, type);
                err = do_lookup(nd, &this, &next, &inode);
                if (err)
                        break;