vfs: dcache: fix deadlock in tree traversal
[linux-3.10.git] / fs / dcache.c
index 8086636..693f95b 100644 (file)
@@ -389,7 +389,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent)
         * Inform try_to_ascend() that we are no longer attached to the
         * dentry tree
         */
-       dentry->d_flags |= DCACHE_DISCONNECTED;
+       dentry->d_flags |= DCACHE_DENTRY_KILLED;
        if (parent)
                spin_unlock(&parent->d_lock);
        dentry_iput(dentry);
@@ -1048,7 +1048,7 @@ static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq
         * or deletion
         */
        if (new != old->d_parent ||
-                (old->d_flags & DCACHE_DISCONNECTED) ||
+                (old->d_flags & DCACHE_DENTRY_KILLED) ||
                 (!locked && read_seqretry(&rename_lock, seq))) {
                spin_unlock(&new->d_lock);
                new = NULL;
@@ -1134,6 +1134,8 @@ positive:
        return 1;
 
 rename_retry:
+       if (locked)
+               goto again;
        locked = 1;
        write_seqlock(&rename_lock);
        goto again;
@@ -1141,7 +1143,7 @@ rename_retry:
 EXPORT_SYMBOL(have_submounts);
 
 /*
- * Search the dentry child list for the specified parent,
+ * Search the dentry child list of the specified parent,
  * and move any unused dentries to the end of the unused
  * list for prune_dcache(). We descend to the next level
  * whenever the d_subdirs list is non-empty and continue
@@ -1236,6 +1238,8 @@ out:
 rename_retry:
        if (found)
                return found;
+       if (locked)
+               goto again;
        locked = 1;
        write_seqlock(&rename_lock);
        goto again;
@@ -3035,6 +3039,8 @@ resume:
        return;
 
 rename_retry:
+       if (locked)
+               goto again;
        locked = 1;
        write_seqlock(&rename_lock);
        goto again;