}
 }
 
+/*
+ * This tries to ascend one level of parenthood, but
+ * we can race with renaming, so we need to re-check
+ * the parenthood after dropping the lock and check
+ * that the sequence number still matches.
+ */
+static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq)
+{
+       struct dentry *new = old->d_parent;
+
+       rcu_read_lock();
+       spin_unlock(&old->d_lock);
+       spin_lock(&new->d_lock);
+
+       /*
+        * might go back up the wrong parent if we have had a rename
+        * or deletion
+        */
+       if (new != old->d_parent ||
+                (!locked && read_seqretry(&rename_lock, seq))) {
+               spin_unlock(&new->d_lock);
+               new = NULL;
+       }
+       rcu_read_unlock();
+       return new;
+}
+
+
 /*
  * Search for at least 1 mount point in the dentry's subdirs.
  * We descend to the next level whenever the d_subdirs
         * All done at this level ... ascend and resume the search.
         */
        if (this_parent != parent) {
-               struct dentry *tmp;
-               struct dentry *child;
-
-               tmp = this_parent->d_parent;
-               rcu_read_lock();
-               spin_unlock(&this_parent->d_lock);
-               child = this_parent;
-               this_parent = tmp;
-               spin_lock(&this_parent->d_lock);
-               /* might go back up the wrong parent if we have had a rename
-                * or deletion */
-               if (this_parent != child->d_parent ||
-                        (!locked && read_seqretry(&rename_lock, seq))) {
-                       spin_unlock(&this_parent->d_lock);
-                       rcu_read_unlock();
+               struct dentry *child = this_parent;
+               this_parent = try_to_ascend(this_parent, locked, seq);
+               if (!this_parent)
                        goto rename_retry;
-               }
-               rcu_read_unlock();
                next = child->d_u.d_child.next;
                goto resume;
        }
         * All done at this level ... ascend and resume the search.
         */
        if (this_parent != parent) {
-               struct dentry *tmp;
-               struct dentry *child;
-
-               tmp = this_parent->d_parent;
-               rcu_read_lock();
-               spin_unlock(&this_parent->d_lock);
-               child = this_parent;
-               this_parent = tmp;
-               spin_lock(&this_parent->d_lock);
-               /* might go back up the wrong parent if we have had a rename
-                * or deletion */
-               if (this_parent != child->d_parent ||
-                       (!locked && read_seqretry(&rename_lock, seq))) {
-                       spin_unlock(&this_parent->d_lock);
-                       rcu_read_unlock();
+               struct dentry *child = this_parent;
+               this_parent = try_to_ascend(this_parent, locked, seq);
+               if (!this_parent)
                        goto rename_retry;
-               }
-               rcu_read_unlock();
                next = child->d_u.d_child.next;
                goto resume;
        }
                spin_unlock(&dentry->d_lock);
        }
        if (this_parent != root) {
-               struct dentry *tmp;
-               struct dentry *child;
-
-               tmp = this_parent->d_parent;
+               struct dentry *child = this_parent;
                if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
                        this_parent->d_flags |= DCACHE_GENOCIDE;
                        this_parent->d_count--;
                }
-               rcu_read_lock();
-               spin_unlock(&this_parent->d_lock);
-               child = this_parent;
-               this_parent = tmp;
-               spin_lock(&this_parent->d_lock);
-               /* might go back up the wrong parent if we have had a rename
-                * or deletion */
-               if (this_parent != child->d_parent ||
-                        (!locked && read_seqretry(&rename_lock, seq))) {
-                       spin_unlock(&this_parent->d_lock);
-                       rcu_read_unlock();
+               this_parent = try_to_ascend(this_parent, locked, seq);
+               if (!this_parent)
                        goto rename_retry;
-               }
-               rcu_read_unlock();
                next = child->d_u.d_child.next;
                goto resume;
        }