return NULL;
 }
 
-static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
+static struct dentry *autofs4_lookup_expiring(struct dentry *dentry,
+                                             bool rcu_walk)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct dentry *parent = dentry->d_parent;
                struct dentry *expiring;
                struct qstr *qstr;
 
+               if (rcu_walk) {
+                       spin_unlock(&sbi->lookup_lock);
+                       return ERR_PTR(-ECHILD);
+               }
+
                ino = list_entry(p, struct autofs_info, expiring);
                expiring = ino->dentry;
 
        return NULL;
 }
 
-static int autofs4_mount_wait(struct dentry *dentry)
+static int autofs4_mount_wait(struct dentry *dentry, bool rcu_walk)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
        int status = 0;
 
        if (ino->flags & AUTOFS_INF_PENDING) {
+               if (rcu_walk)
+                       return -ECHILD;
                DPRINTK("waiting for mount name=%.*s",
                        dentry->d_name.len, dentry->d_name.name);
                status = autofs4_wait(sbi, dentry, NFY_MOUNT);
        return status;
 }
 
-static int do_expire_wait(struct dentry *dentry)
+static int do_expire_wait(struct dentry *dentry, bool rcu_walk)
 {
        struct dentry *expiring;
 
-       expiring = autofs4_lookup_expiring(dentry);
+       expiring = autofs4_lookup_expiring(dentry, rcu_walk);
+       if (IS_ERR(expiring))
+               return PTR_ERR(expiring);
        if (!expiring)
-               return autofs4_expire_wait(dentry);
+               return autofs4_expire_wait(dentry, rcu_walk);
        else {
                /*
                 * If we are racing with expire the request might not
                 * be quite complete, but the directory has been removed
                 * so it must have been successful, just wait for it.
                 */
-               autofs4_expire_wait(expiring);
+               autofs4_expire_wait(expiring, 0);
                autofs4_del_expiring(expiring);
                dput(expiring);
        }
         * and the directory was removed, so just go ahead and try
         * the mount.
         */
-       status = do_expire_wait(dentry);
+       status = do_expire_wait(dentry, 0);
        if (status && status != -EAGAIN)
                return NULL;
 
        spin_lock(&sbi->fs_lock);
        if (ino->flags & AUTOFS_INF_PENDING) {
                spin_unlock(&sbi->fs_lock);
-               status = autofs4_mount_wait(dentry);
+               status = autofs4_mount_wait(dentry, 0);
                if (status)
                        return ERR_PTR(status);
                goto done;
                }
                ino->flags |= AUTOFS_INF_PENDING;
                spin_unlock(&sbi->fs_lock);
-               status = autofs4_mount_wait(dentry);
+               status = autofs4_mount_wait(dentry, 0);
                spin_lock(&sbi->fs_lock);
                ino->flags &= ~AUTOFS_INF_PENDING;
                if (status) {
                return 0;
        }
 
-       /* We need to sleep, so we need pathwalk to be in ref-mode */
-       if (rcu_walk)
-               return -ECHILD;
-
        /* Wait for pending expires */
-       do_expire_wait(dentry);
+       if (do_expire_wait(dentry, rcu_walk) == -ECHILD)
+               return -ECHILD;
 
        /*
         * This dentry may be under construction so wait on mount
         * completion.
         */
-       status = autofs4_mount_wait(dentry);
+       status = autofs4_mount_wait(dentry, rcu_walk);
        if (status)
                return status;
 
+       if (rcu_walk)
+               /* it is always safe to return 0 as the worst that
+                * will happen is we retry in REF-walk mode.
+                * Better than always taking a lock.
+                */
+               return 0;
+
        spin_lock(&sbi->fs_lock);
        /*
         * If the dentry has been selected for expire while we slept