Revert "autofs4: always use lookup for lookup"
[safe/jmp/linux-2.6] / fs / autofs4 / root.c
index 72dca33..a015b49 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
  *  Copyright 1999-2000 Jeremy Fitzhardinge <jeremy@goop.org>
- *  Copyright 2001-2003 Ian Kent <raven@themaw.net>
+ *  Copyright 2001-2006 Ian Kent <raven@themaw.net>
  *
  * This file is part of the Linux kernel and is made available under
  * the terms of the GNU General Public License, version 2, or at your
@@ -17,7 +17,6 @@
 #include <linux/stat.h>
 #include <linux/param.h>
 #include <linux/time.h>
-#include <linux/smp_lock.h>
 #include "autofs_i.h"
 
 static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
@@ -26,27 +25,30 @@ static int autofs4_dir_rmdir(struct inode *,struct dentry *);
 static int autofs4_dir_mkdir(struct inode *,struct dentry *,int);
 static int autofs4_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
 static int autofs4_dir_open(struct inode *inode, struct file *file);
-static int autofs4_dir_close(struct inode *inode, struct file *file);
-static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir);
-static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir);
 static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
+static void *autofs4_follow_link(struct dentry *, struct nameidata *);
 
-struct file_operations autofs4_root_operations = {
+#define TRIGGER_FLAGS   (LOOKUP_CONTINUE | LOOKUP_DIRECTORY)
+#define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE)
+
+const struct file_operations autofs4_root_operations = {
        .open           = dcache_dir_open,
        .release        = dcache_dir_close,
        .read           = generic_read_dir,
-       .readdir        = autofs4_root_readdir,
+       .readdir        = dcache_readdir,
+       .llseek         = dcache_dir_lseek,
        .ioctl          = autofs4_root_ioctl,
 };
 
-struct file_operations autofs4_dir_operations = {
+const struct file_operations autofs4_dir_operations = {
        .open           = autofs4_dir_open,
-       .release        = autofs4_dir_close,
+       .release        = dcache_dir_close,
        .read           = generic_read_dir,
-       .readdir        = autofs4_dir_readdir,
+       .readdir        = dcache_readdir,
+       .llseek         = dcache_dir_lseek,
 };
 
-struct inode_operations autofs4_root_inode_operations = {
+const struct inode_operations autofs4_indirect_root_inode_operations = {
        .lookup         = autofs4_lookup,
        .unlink         = autofs4_dir_unlink,
        .symlink        = autofs4_dir_symlink,
@@ -54,149 +56,66 @@ struct inode_operations autofs4_root_inode_operations = {
        .rmdir          = autofs4_dir_rmdir,
 };
 
-struct inode_operations autofs4_dir_inode_operations = {
+const struct inode_operations autofs4_direct_root_inode_operations = {
        .lookup         = autofs4_lookup,
        .unlink         = autofs4_dir_unlink,
-       .symlink        = autofs4_dir_symlink,
        .mkdir          = autofs4_dir_mkdir,
        .rmdir          = autofs4_dir_rmdir,
+       .follow_link    = autofs4_follow_link,
 };
 
-static int autofs4_root_readdir(struct file *file, void *dirent,
-                               filldir_t filldir)
-{
-       struct autofs_sb_info *sbi = autofs4_sbi(file->f_dentry->d_sb);
-       int oz_mode = autofs4_oz_mode(sbi);
-
-       DPRINTK("called, filp->f_pos = %lld", file->f_pos);
-
-       /*
-        * Don't set reghost flag if:
-        * 1) f_pos is larger than zero -- we've already been here.
-        * 2) we haven't even enabled reghosting in the 1st place.
-        * 3) this is the daemon doing a readdir
-        */
-       if (oz_mode && file->f_pos == 0 && sbi->reghost_enabled)
-               sbi->needs_reghost = 1;
-
-       DPRINTK("needs_reghost = %d", sbi->needs_reghost);
-
-       return dcache_readdir(file, dirent, filldir);
-}
+const struct inode_operations autofs4_dir_inode_operations = {
+       .lookup         = autofs4_lookup,
+       .unlink         = autofs4_dir_unlink,
+       .symlink        = autofs4_dir_symlink,
+       .mkdir          = autofs4_dir_mkdir,
+       .rmdir          = autofs4_dir_rmdir,
+};
 
-static int autofs4_dir_open(struct inode *inode, struct file *file)
+static void autofs4_add_active(struct dentry *dentry)
 {
-       struct dentry *dentry = file->f_dentry;
-       struct vfsmount *mnt = file->f_vfsmnt;
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
-       struct dentry *cursor;
-       int status;
-
-       status = dcache_dir_open(inode, file);
-       if (status)
-               goto out;
-
-       cursor = file->private_data;
-       cursor->d_fsdata = NULL;
-
-       DPRINTK("file=%p dentry=%p %.*s",
-               file, dentry, dentry->d_name.len, dentry->d_name.name);
-
-       if (autofs4_oz_mode(sbi))
-               goto out;
-
-       if (autofs4_ispending(dentry)) {
-               DPRINTK("dentry busy");
-               dcache_dir_close(inode, file);
-               status = -EBUSY;
-               goto out;
-       }
-
-       status = -ENOENT;
-       if (!d_mountpoint(dentry) && dentry->d_op && dentry->d_op->d_revalidate) {
-               struct nameidata nd;
-               int empty, ret;
-
-               /* In case there are stale directory dentrys from a failed mount */
-               spin_lock(&dcache_lock);
-               empty = list_empty(&dentry->d_subdirs);
-               spin_unlock(&dcache_lock);
-
-               if (!empty)
-                       d_invalidate(dentry);
-
-               nd.flags = LOOKUP_DIRECTORY;
-               ret = (dentry->d_op->d_revalidate)(dentry, &nd);
-
-               if (!ret) {
-                       dcache_dir_close(inode, file);
-                       goto out;
-               }
-       }
-
-       if (d_mountpoint(dentry)) {
-               struct file *fp = NULL;
-               struct vfsmount *fp_mnt = mntget(mnt);
-               struct dentry *fp_dentry = dget(dentry);
-
-               if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) {
-                       dput(fp_dentry);
-                       mntput(fp_mnt);
-                       dcache_dir_close(inode, file);
-                       goto out;
-               }
-
-               fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
-               status = PTR_ERR(fp);
-               if (IS_ERR(fp)) {
-                       dcache_dir_close(inode, file);
-                       goto out;
+       struct autofs_info *ino = autofs4_dentry_ino(dentry);
+       if (ino) {
+               spin_lock(&sbi->lookup_lock);
+               if (!ino->active_count) {
+                       if (list_empty(&ino->active))
+                               list_add(&ino->active, &sbi->active_list);
                }
-               cursor->d_fsdata = fp;
+               ino->active_count++;
+               spin_unlock(&sbi->lookup_lock);
        }
-       return 0;
-out:
-       return status;
+       return;
 }
 
-static int autofs4_dir_close(struct inode *inode, struct file *file)
+static void autofs4_del_active(struct dentry *dentry)
 {
-       struct dentry *dentry = file->f_dentry;
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
-       struct dentry *cursor = file->private_data;
-       int status = 0;
-
-       DPRINTK("file=%p dentry=%p %.*s",
-               file, dentry, dentry->d_name.len, dentry->d_name.name);
-
-       if (autofs4_oz_mode(sbi))
-               goto out;
-
-       if (autofs4_ispending(dentry)) {
-               DPRINTK("dentry busy");
-               status = -EBUSY;
-               goto out;
-       }
-
-       if (d_mountpoint(dentry)) {
-               struct file *fp = cursor->d_fsdata;
-               if (!fp) {
-                       status = -ENOENT;
-                       goto out;
+       struct autofs_info *ino = autofs4_dentry_ino(dentry);
+       if (ino) {
+               spin_lock(&sbi->lookup_lock);
+               ino->active_count--;
+               if (!ino->active_count) {
+                       if (!list_empty(&ino->active))
+                               list_del_init(&ino->active);
                }
-               filp_close(fp, current->files);
+               spin_unlock(&sbi->lookup_lock);
        }
-out:
-       dcache_dir_close(inode, file);
-       return status;
+       return;
 }
 
-static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldir)
+static unsigned int autofs4_need_mount(unsigned int flags)
 {
-       struct dentry *dentry = file->f_dentry;
+       unsigned int res = 0;
+       if (flags & (TRIGGER_FLAGS | TRIGGER_INTENTS))
+               res = 1;
+       return res;
+}
+
+static int autofs4_dir_open(struct inode *inode, struct file *file)
+{
+       struct dentry *dentry = file->f_path.dentry;
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
-       struct dentry *cursor = file->private_data;
-       int status;
 
        DPRINTK("file=%p dentry=%p %.*s",
                file, dentry, dentry->d_name.len, dentry->d_name.name);
@@ -204,56 +123,31 @@ static int autofs4_dir_readdir(struct file *file, void *dirent, filldir_t filldi
        if (autofs4_oz_mode(sbi))
                goto out;
 
-       if (autofs4_ispending(dentry)) {
-               DPRINTK("dentry busy");
-               return -EBUSY;
+       /*
+        * An empty directory in an autofs file system is always a
+        * mount point. The daemon must have failed to mount this
+        * during lookup so it doesn't exist. This can happen, for
+        * example, if user space returns an incorrect status for a
+        * mount request. Otherwise we're doing a readdir on the
+        * autofs file system so just let the libfs routines handle
+        * it.
+        */
+       spin_lock(&dcache_lock);
+       if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
+               spin_unlock(&dcache_lock);
+               return -ENOENT;
        }
+       spin_unlock(&dcache_lock);
 
-       if (d_mountpoint(dentry)) {
-               struct file *fp = cursor->d_fsdata;
-
-               if (!fp)
-                       return -ENOENT;
-
-               if (!fp->f_op || !fp->f_op->readdir)
-                       goto out;
-
-               status = vfs_readdir(fp, filldir, dirent);
-               file->f_pos = fp->f_pos;
-               if (status)
-                       autofs4_copy_atime(file, fp);
-               return status;
-       }
 out:
-       return dcache_readdir(file, dirent, filldir);
+       return dcache_dir_open(inode, file);
 }
 
 static int try_to_fill_dentry(struct dentry *dentry, int flags)
 {
        struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
-       int status = 0;
-
-       /* Block on any pending expiry here; invalidate the dentry
-           when expiration is done to trigger mount request with a new
-           dentry */
-       if (ino && (ino->flags & AUTOFS_INF_EXPIRING)) {
-               DPRINTK("waiting for expire %p name=%.*s",
-                        dentry, dentry->d_name.len, dentry->d_name.name);
-
-               status = autofs4_wait(sbi, dentry, NFY_NONE);
-
-               DPRINTK("expire done status=%d", status);
-
-               /*
-                * If the directory still exists the mount request must
-                * continue otherwise it can't be followed at the right
-                * time during the walk.
-                */
-               status = d_invalidate(dentry);
-               if (status != -EBUSY)
-                       return 0;
-       }
+       int status;
 
        DPRINTK("dentry=%p %.*s ino=%p",
                 dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
@@ -270,37 +164,35 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags)
 
                DPRINTK("mount done status=%d", status);
 
-               if (status && dentry->d_inode)
-                       return 0; /* Try to get the kernel to invalidate this dentry */
-
                /* Turn this into a real negative dentry? */
                if (status == -ENOENT) {
-                       spin_lock(&dentry->d_lock);
-                       dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
-                       spin_unlock(&dentry->d_lock);
-                       return 0;
+                       spin_lock(&sbi->fs_lock);
+                       ino->flags &= ~AUTOFS_INF_PENDING;
+                       spin_unlock(&sbi->fs_lock);
+                       return status;
                } else if (status) {
                        /* Return a negative dentry, but leave it "pending" */
-                       return 0;
+                       return status;
                }
        /* Trigger mount for path component or follow link */
-       } else if (flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) ||
+       } else if (ino->flags & AUTOFS_INF_PENDING ||
+                       autofs4_need_mount(flags) ||
                        current->link_count) {
                DPRINTK("waiting for mount name=%.*s",
                        dentry->d_name.len, dentry->d_name.name);
 
-               spin_lock(&dentry->d_lock);
-               dentry->d_flags |= DCACHE_AUTOFS_PENDING;
-               spin_unlock(&dentry->d_lock);
+               spin_lock(&sbi->fs_lock);
+               ino->flags |= AUTOFS_INF_PENDING;
+               spin_unlock(&sbi->fs_lock);
                status = autofs4_wait(sbi, dentry, NFY_MOUNT);
 
                DPRINTK("mount done status=%d", status);
 
                if (status) {
-                       spin_lock(&dentry->d_lock);
-                       dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
-                       spin_unlock(&dentry->d_lock);
-                       return 0;
+                       spin_lock(&sbi->fs_lock);
+                       ino->flags &= ~AUTOFS_INF_PENDING;
+                       spin_unlock(&sbi->fs_lock);
+                       return status;
                }
        }
 
@@ -308,10 +200,94 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags)
        if (ino)
                ino->last_used = jiffies;
 
-       spin_lock(&dentry->d_lock);
-       dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
-       spin_unlock(&dentry->d_lock);
-       return 1;
+       spin_lock(&sbi->fs_lock);
+       ino->flags &= ~AUTOFS_INF_PENDING;
+       spin_unlock(&sbi->fs_lock);
+
+       return 0;
+}
+
+/* For autofs direct mounts the follow link triggers the mount */
+static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+       struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+       struct autofs_info *ino = autofs4_dentry_ino(dentry);
+       int oz_mode = autofs4_oz_mode(sbi);
+       unsigned int lookup_type;
+       int status;
+
+       DPRINTK("dentry=%p %.*s oz_mode=%d nd->flags=%d",
+               dentry, dentry->d_name.len, dentry->d_name.name, oz_mode,
+               nd->flags);
+       /*
+        * For an expire of a covered direct or offset mount we need
+        * to break out of follow_down() at the autofs mount trigger
+        * (d_mounted--), so we can see the expiring flag, and manage
+        * the blocking and following here until the expire is completed.
+        */
+       if (oz_mode) {
+               spin_lock(&sbi->fs_lock);
+               if (ino->flags & AUTOFS_INF_EXPIRING) {
+                       spin_unlock(&sbi->fs_lock);
+                       /* Follow down to our covering mount. */
+                       if (!follow_down(&nd->path))
+                               goto done;
+                       goto follow;
+               }
+               spin_unlock(&sbi->fs_lock);
+               goto done;
+       }
+
+       /* If an expire request is pending everyone must wait. */
+       autofs4_expire_wait(dentry);
+
+       /* We trigger a mount for almost all flags */
+       lookup_type = autofs4_need_mount(nd->flags);
+       spin_lock(&sbi->fs_lock);
+       spin_lock(&dcache_lock);
+       if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) {
+               spin_unlock(&dcache_lock);
+               spin_unlock(&sbi->fs_lock);
+               goto follow;
+       }
+
+       /*
+        * If the dentry contains directories then it is an autofs
+        * multi-mount with no root mount offset. So don't try to
+        * mount it again.
+        */
+       if (ino->flags & AUTOFS_INF_PENDING ||
+           (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) {
+               spin_unlock(&dcache_lock);
+               spin_unlock(&sbi->fs_lock);
+
+               status = try_to_fill_dentry(dentry, 0);
+               if (status)
+                       goto out_error;
+
+               goto follow;
+       }
+       spin_unlock(&dcache_lock);
+       spin_unlock(&sbi->fs_lock);
+follow:
+       /*
+        * If there is no root mount it must be an autofs
+        * multi-mount with no root offset so we don't need
+        * to follow it.
+        */
+       if (d_mountpoint(dentry)) {
+               if (!autofs4_follow_mount(&nd->path)) {
+                       status = -ENOENT;
+                       goto out_error;
+               }
+       }
+
+done:
+       return NULL;
+
+out_error:
+       path_put(&nd->path);
+       return ERR_PTR(status);
 }
 
 /*
@@ -329,11 +305,33 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
        int status = 1;
 
        /* Pending dentry */
+       spin_lock(&sbi->fs_lock);
        if (autofs4_ispending(dentry)) {
-               if (!oz_mode)
-                       status = try_to_fill_dentry(dentry, flags);
+               /* The daemon never causes a mount to trigger */
+               spin_unlock(&sbi->fs_lock);
+
+               if (oz_mode)
+                       return 1;
+
+               /*
+                * If the directory has gone away due to an expire
+                * we have been called as ->d_revalidate() and so
+                * we need to return false and proceed to ->lookup().
+                */
+               if (autofs4_expire_wait(dentry) == -EAGAIN)
+                       return 0;
+
+               /*
+                * A zero status is success otherwise we have a
+                * negative error code.
+                */
+               status = try_to_fill_dentry(dentry, flags);
+               if (status == 0)
+                       return 1;
+
                return status;
        }
+       spin_unlock(&sbi->fs_lock);
 
        /* Negative dentry.. invalidate if "old" */
        if (dentry->d_inode == NULL)
@@ -342,13 +340,23 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
        /* Check for a non-mountpoint directory with no contents */
        spin_lock(&dcache_lock);
        if (S_ISDIR(dentry->d_inode->i_mode) &&
-           !d_mountpoint(dentry) && 
-           simple_empty_nolock(dentry)) {
+           !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
                DPRINTK("dentry=%p %.*s, emptydir",
                         dentry, dentry->d_name.len, dentry->d_name.name);
                spin_unlock(&dcache_lock);
-               if (!oz_mode)
-                       status = try_to_fill_dentry(dentry, flags);
+
+               /* The daemon never causes a mount to trigger */
+               if (oz_mode)
+                       return 1;
+
+               /*
+                * A zero status is success otherwise we have a
+                * negative error code.
+                */
+               status = try_to_fill_dentry(dentry, flags);
+               if (status == 0)
+                       return 1;
+
                return status;
        }
        spin_unlock(&dcache_lock);
@@ -356,7 +364,7 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
        return 1;
 }
 
-static void autofs4_dentry_release(struct dentry *de)
+void autofs4_dentry_release(struct dentry *de)
 {
        struct autofs_info *inf;
 
@@ -366,6 +374,17 @@ static void autofs4_dentry_release(struct dentry *de)
        de->d_fsdata = NULL;
 
        if (inf) {
+               struct autofs_sb_info *sbi = autofs4_sbi(de->d_sb);
+
+               if (sbi) {
+                       spin_lock(&sbi->lookup_lock);
+                       if (!list_empty(&inf->active))
+                               list_del(&inf->active);
+                       if (!list_empty(&inf->expiring))
+                               list_del(&inf->expiring);
+                       spin_unlock(&sbi->lookup_lock);
+               }
+
                inf->dentry = NULL;
                inf->inode = NULL;
 
@@ -374,21 +393,133 @@ static void autofs4_dentry_release(struct dentry *de)
 }
 
 /* For dentries of directories in the root dir */
-static struct dentry_operations autofs4_root_dentry_operations = {
+static const struct dentry_operations autofs4_root_dentry_operations = {
        .d_revalidate   = autofs4_revalidate,
        .d_release      = autofs4_dentry_release,
 };
 
 /* For other dentries */
-static struct dentry_operations autofs4_dentry_operations = {
+static const struct dentry_operations autofs4_dentry_operations = {
        .d_revalidate   = autofs4_revalidate,
        .d_release      = autofs4_dentry_release,
 };
 
+static struct dentry *autofs4_lookup_active(struct dentry *dentry)
+{
+       struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+       struct dentry *parent = dentry->d_parent;
+       struct qstr *name = &dentry->d_name;
+       unsigned int len = name->len;
+       unsigned int hash = name->hash;
+       const unsigned char *str = name->name;
+       struct list_head *p, *head;
+
+       spin_lock(&dcache_lock);
+       spin_lock(&sbi->lookup_lock);
+       head = &sbi->active_list;
+       list_for_each(p, head) {
+               struct autofs_info *ino;
+               struct dentry *active;
+               struct qstr *qstr;
+
+               ino = list_entry(p, struct autofs_info, active);
+               active = ino->dentry;
+
+               spin_lock(&active->d_lock);
+
+               /* Already gone? */
+               if (atomic_read(&active->d_count) == 0)
+                       goto next;
+
+               qstr = &active->d_name;
+
+               if (active->d_name.hash != hash)
+                       goto next;
+               if (active->d_parent != parent)
+                       goto next;
+
+               if (qstr->len != len)
+                       goto next;
+               if (memcmp(qstr->name, str, len))
+                       goto next;
+
+               if (d_unhashed(active)) {
+                       dget(active);
+                       spin_unlock(&active->d_lock);
+                       spin_unlock(&sbi->lookup_lock);
+                       spin_unlock(&dcache_lock);
+                       return active;
+               }
+next:
+               spin_unlock(&active->d_lock);
+       }
+       spin_unlock(&sbi->lookup_lock);
+       spin_unlock(&dcache_lock);
+
+       return NULL;
+}
+
+static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
+{
+       struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
+       struct dentry *parent = dentry->d_parent;
+       struct qstr *name = &dentry->d_name;
+       unsigned int len = name->len;
+       unsigned int hash = name->hash;
+       const unsigned char *str = name->name;
+       struct list_head *p, *head;
+
+       spin_lock(&dcache_lock);
+       spin_lock(&sbi->lookup_lock);
+       head = &sbi->expiring_list;
+       list_for_each(p, head) {
+               struct autofs_info *ino;
+               struct dentry *expiring;
+               struct qstr *qstr;
+
+               ino = list_entry(p, struct autofs_info, expiring);
+               expiring = ino->dentry;
+
+               spin_lock(&expiring->d_lock);
+
+               /* Bad luck, we've already been dentry_iput */
+               if (!expiring->d_inode)
+                       goto next;
+
+               qstr = &expiring->d_name;
+
+               if (expiring->d_name.hash != hash)
+                       goto next;
+               if (expiring->d_parent != parent)
+                       goto next;
+
+               if (qstr->len != len)
+                       goto next;
+               if (memcmp(qstr->name, str, len))
+                       goto next;
+
+               if (d_unhashed(expiring)) {
+                       dget(expiring);
+                       spin_unlock(&expiring->d_lock);
+                       spin_unlock(&sbi->lookup_lock);
+                       spin_unlock(&dcache_lock);
+                       return expiring;
+               }
+next:
+               spin_unlock(&expiring->d_lock);
+       }
+       spin_unlock(&sbi->lookup_lock);
+       spin_unlock(&dcache_lock);
+
+       return NULL;
+}
+
 /* Lookups in the root directory */
 static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
 {
        struct autofs_sb_info *sbi;
+       struct autofs_info *ino;
+       struct dentry *expiring, *active;
        int oz_mode;
 
        DPRINTK("name = %.*s",
@@ -402,31 +533,62 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
        oz_mode = autofs4_oz_mode(sbi);
 
        DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
-                current->pid, process_group(current), sbi->catatonic, oz_mode);
+                current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);
 
-       /*
-        * Mark the dentry incomplete, but add it. This is needed so
-        * that the VFS layer knows about the dentry, and we can count
-        * on catching any lookups through the revalidate.
-        *
-        * Let all the hard work be done by the revalidate function that
-        * needs to be able to do this anyway..
-        *
-        * We need to do this before we release the directory semaphore.
-        */
-       dentry->d_op = &autofs4_root_dentry_operations;
+       active = autofs4_lookup_active(dentry);
+       if (active) {
+               dentry = active;
+               ino = autofs4_dentry_ino(dentry);
+       } else {
+               /*
+                * Mark the dentry incomplete but don't hash it. We do this
+                * to serialize our inode creation operations (symlink and
+                * mkdir) which prevents deadlock during the callback to
+                * the daemon. Subsequent user space lookups for the same
+                * dentry are placed on the wait queue while the daemon
+                * itself is allowed passage unresticted so the create
+                * operation itself can then hash the dentry. Finally,
+                * we check for the hashed dentry and return the newly
+                * hashed dentry.
+                */
+               dentry->d_op = &autofs4_root_dentry_operations;
 
-       if (!oz_mode) {
-               spin_lock(&dentry->d_lock);
-               dentry->d_flags |= DCACHE_AUTOFS_PENDING;
-               spin_unlock(&dentry->d_lock);
+               /*
+                * And we need to ensure that the same dentry is used for
+                * all following lookup calls until it is hashed so that
+                * the dentry flags are persistent throughout the request.
+                */
+               ino = autofs4_init_ino(NULL, sbi, 0555);
+               if (!ino)
+                       return ERR_PTR(-ENOMEM);
+
+               dentry->d_fsdata = ino;
+               ino->dentry = dentry;
+
+               autofs4_add_active(dentry);
+
+               d_instantiate(dentry, NULL);
        }
-       dentry->d_fsdata = NULL;
-       d_add(dentry, NULL);
 
-       if (dentry->d_op && dentry->d_op->d_revalidate) {
+       if (!oz_mode) {
                mutex_unlock(&dir->i_mutex);
-               (dentry->d_op->d_revalidate)(dentry, nd);
+               expiring = autofs4_lookup_expiring(dentry);
+               if (expiring) {
+                       /*
+                        * 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, so just wait for it.
+                        */
+                       autofs4_expire_wait(expiring);
+                       autofs4_del_expiring(expiring);
+                       dput(expiring);
+               }
+
+               spin_lock(&sbi->fs_lock);
+               ino->flags |= AUTOFS_INF_PENDING;
+               spin_unlock(&sbi->fs_lock);
+               if (dentry->d_op && dentry->d_op->d_revalidate)
+                       (dentry->d_op->d_revalidate)(dentry, nd);
                mutex_lock(&dir->i_mutex);
        }
 
@@ -434,26 +596,54 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
         * If we are still pending, check if we had to handle
         * a signal. If so we can force a restart..
         */
-       if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
+       if (ino->flags & AUTOFS_INF_PENDING) {
                /* See if we were interrupted */
                if (signal_pending(current)) {
                        sigset_t *sigset = &current->pending.signal;
                        if (sigismember (sigset, SIGKILL) ||
                            sigismember (sigset, SIGQUIT) ||
                            sigismember (sigset, SIGINT)) {
+                           if (active)
+                               dput(active);
                            return ERR_PTR(-ERESTARTNOINTR);
                        }
                }
+               if (!oz_mode) {
+                       spin_lock(&sbi->fs_lock);
+                       ino->flags &= ~AUTOFS_INF_PENDING;
+                       spin_unlock(&sbi->fs_lock);
+               }
        }
 
        /*
         * If this dentry is unhashed, then we shouldn't honour this
-        * lookup even if the dentry is positive.  Returning ENOENT here
-        * doesn't do the right thing for all system calls, but it should
-        * be OK for the operations we permit from an autofs.
+        * lookup.  Returning ENOENT here doesn't do the right thing
+        * for all system calls, but it should be OK for the operations
+        * we permit from an autofs.
         */
-       if (dentry->d_inode && d_unhashed(dentry))
-               return ERR_PTR(-ENOENT);
+       if (!oz_mode && d_unhashed(dentry)) {
+               /*
+                * A user space application can (and has done in the past)
+                * remove and re-create this directory during the callback.
+                * This can leave us with an unhashed dentry, but a
+                * successful mount!  So we need to perform another
+                * cached lookup in case the dentry now exists.
+                */
+               struct dentry *parent = dentry->d_parent;
+               struct dentry *new = d_lookup(parent, &dentry->d_name);
+               if (new != NULL)
+                       dentry = new;
+               else
+                       dentry = ERR_PTR(-ENOENT);
+
+               if (active)
+                       dput(active);
+
+               return dentry;
+       }
+
+       if (active)
+               return active;
 
        return NULL;
 }
@@ -475,21 +665,29 @@ static int autofs4_dir_symlink(struct inode *dir,
                return -EACCES;
 
        ino = autofs4_init_ino(ino, sbi, S_IFLNK | 0555);
-       if (ino == NULL)
-               return -ENOSPC;
+       if (!ino)
+               return -ENOMEM;
 
-       ino->size = strlen(symname);
-       ino->u.symlink = cp = kmalloc(ino->size + 1, GFP_KERNEL);
+       autofs4_del_active(dentry);
 
-       if (cp == NULL) {
-               kfree(ino);
-               return -ENOSPC;
+       ino->size = strlen(symname);
+       cp = kmalloc(ino->size + 1, GFP_KERNEL);
+       if (!cp) {
+               if (!dentry->d_fsdata)
+                       kfree(ino);
+               return -ENOMEM;
        }
 
        strcpy(cp, symname);
 
        inode = autofs4_get_inode(dir->i_sb, ino);
-       d_instantiate(dentry, inode);
+       if (!inode) {
+               kfree(cp);
+               if (!dentry->d_fsdata)
+                       kfree(ino);
+               return -ENOMEM;
+       }
+       d_add(dentry, inode);
 
        if (dir == dir->i_sb->s_root->d_inode)
                dentry->d_op = &autofs4_root_dentry_operations;
@@ -504,6 +702,7 @@ static int autofs4_dir_symlink(struct inode *dir,
                atomic_inc(&p_ino->count);
        ino->inode = inode;
 
+       ino->u.symlink = cp;
        dir->i_mtime = CURRENT_TIME;
 
        return 0;
@@ -515,9 +714,9 @@ static int autofs4_dir_symlink(struct inode *dir,
  * Normal filesystems would do a "d_delete()" to tell the VFS dcache
  * that the file no longer exists. However, doing that means that the
  * VFS layer can turn the dentry into a negative dentry.  We don't want
- * this, because since the unlink is probably the result of an expire.
- * We simply d_drop it, which allows the dentry lookup to remount it
- * if necessary.
+ * this, because the unlink is probably the result of an expire.
+ * We simply d_drop it and add it to a expiring list in the super block,
+ * which allows the dentry lookup to check for an incomplete expire.
  *
  * If a process is blocked on the dentry waiting for the expire to finish,
  * it will invalidate the dentry and try to mount with a new one.
@@ -531,7 +730,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
        struct autofs_info *p_ino;
        
        /* This allows root to remove symlinks */
-       if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+       if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
                return -EACCES;
 
        if (atomic_dec_and_test(&ino->count)) {
@@ -542,11 +741,16 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
        dput(ino->dentry);
 
        dentry->d_inode->i_size = 0;
-       dentry->d_inode->i_nlink = 0;
+       clear_nlink(dentry->d_inode);
 
        dir->i_mtime = CURRENT_TIME;
 
-       d_drop(dentry);
+       spin_lock(&dcache_lock);
+       autofs4_add_expiring(dentry);
+       spin_lock(&dentry->d_lock);
+       __d_drop(dentry);
+       spin_unlock(&dentry->d_lock);
+       spin_unlock(&dcache_lock);
 
        return 0;
 }
@@ -557,6 +761,9 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
        struct autofs_info *ino = autofs4_dentry_ino(dentry);
        struct autofs_info *p_ino;
        
+       DPRINTK("dentry %p, removing %.*s",
+               dentry, dentry->d_name.len, dentry->d_name.name);
+
        if (!autofs4_oz_mode(sbi))
                return -EACCES;
 
@@ -565,6 +772,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
                spin_unlock(&dcache_lock);
                return -ENOTEMPTY;
        }
+       autofs4_add_expiring(dentry);
        spin_lock(&dentry->d_lock);
        __d_drop(dentry);
        spin_unlock(&dentry->d_lock);
@@ -577,10 +785,10 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
        }
        dput(ino->dentry);
        dentry->d_inode->i_size = 0;
-       dentry->d_inode->i_nlink = 0;
+       clear_nlink(dentry->d_inode);
 
        if (dir->i_nlink)
-               dir->i_nlink--;
+               drop_nlink(dir);
 
        return 0;
 }
@@ -592,18 +800,25 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        struct autofs_info *p_ino;
        struct inode *inode;
 
-       if ( !autofs4_oz_mode(sbi) )
+       if (!autofs4_oz_mode(sbi))
                return -EACCES;
 
        DPRINTK("dentry %p, creating %.*s",
                dentry, dentry->d_name.len, dentry->d_name.name);
 
        ino = autofs4_init_ino(ino, sbi, S_IFDIR | 0555);
-       if (ino == NULL)
-               return -ENOSPC;
+       if (!ino)
+               return -ENOMEM;
+
+       autofs4_del_active(dentry);
 
        inode = autofs4_get_inode(dir->i_sb, ino);
-       d_instantiate(dentry, inode);
+       if (!inode) {
+               if (!dentry->d_fsdata)
+                       kfree(ino);
+               return -ENOMEM;
+       }
+       d_add(dentry, inode);
 
        if (dir == dir->i_sb->s_root->d_inode)
                dentry->d_op = &autofs4_root_dentry_operations;
@@ -617,7 +832,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        if (p_ino && dentry->d_parent != dentry)
                atomic_inc(&p_ino->count);
        ino->inode = inode;
-       dir->i_nlink++;
+       inc_nlink(dir);
        dir->i_mtime = CURRENT_TIME;
 
        return 0;
@@ -630,11 +845,11 @@ static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi,
        int rv;
        unsigned long ntimeout;
 
-       if ( (rv = get_user(ntimeout, p)) ||
-            (rv = put_user(sbi->exp_timeout/HZ, p)) )
+       if ((rv = get_user(ntimeout, p)) ||
+            (rv = put_user(sbi->exp_timeout/HZ, p)))
                return rv;
 
-       if ( ntimeout > ULONG_MAX/HZ )
+       if (ntimeout > ULONG_MAX/HZ)
                sbi->exp_timeout = 0;
        else
                sbi->exp_timeout = ntimeout * HZ;
@@ -655,51 +870,13 @@ static inline int autofs4_get_protosubver(struct autofs_sb_info *sbi, int __user
 }
 
 /*
- * Tells the daemon whether we need to reghost or not. Also, clears
- * the reghost_needed flag.
- */
-static inline int autofs4_ask_reghost(struct autofs_sb_info *sbi, int __user *p)
-{
-       int status;
-
-       DPRINTK("returning %d", sbi->needs_reghost);
-
-       status = put_user(sbi->needs_reghost, p);
-       if ( status )
-               return status;
-
-       sbi->needs_reghost = 0;
-       return 0;
-}
-
-/*
- * Enable / Disable reghosting ioctl() operation
- */
-static inline int autofs4_toggle_reghost(struct autofs_sb_info *sbi, int __user *p)
-{
-       int status;
-       int val;
-
-       status = get_user(val, p);
-
-       DPRINTK("reghost = %d", val);
-
-       if (status)
-               return status;
-
-       /* turn on/off reghosting, with the val */
-       sbi->reghost_enabled = val;
-       return 0;
-}
-
-/*
 * Tells the daemon whether it can umount the autofs mount.
 */
 static inline int autofs4_ask_umount(struct vfsmount *mnt, int __user *p)
 {
        int status = 0;
 
-       if (may_umount(mnt) == 0)
+       if (may_umount(mnt))
                status = 1;
 
        DPRINTK("returning %d", status);
@@ -732,13 +909,13 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
        void __user *p = (void __user *)arg;
 
        DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u",
-               cmd,arg,sbi,process_group(current));
+               cmd,arg,sbi,task_pgrp_nr(current));
 
-       if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
-            _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+       if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+            _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT)
                return -ENOTTY;
        
-       if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+       if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
                return -EPERM;
        
        switch(cmd) {
@@ -756,20 +933,15 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp,
        case AUTOFS_IOC_SETTIMEOUT:
                return autofs4_get_set_timeout(sbi, p);
 
-       case AUTOFS_IOC_TOGGLEREGHOST:
-               return autofs4_toggle_reghost(sbi, p);
-       case AUTOFS_IOC_ASKREGHOST:
-               return autofs4_ask_reghost(sbi, p);
-
        case AUTOFS_IOC_ASKUMOUNT:
-               return autofs4_ask_umount(filp->f_vfsmnt, p);
+               return autofs4_ask_umount(filp->f_path.mnt, p);
 
        /* return a single thing to expire */
        case AUTOFS_IOC_EXPIRE:
-               return autofs4_expire_run(inode->i_sb,filp->f_vfsmnt,sbi, p);
+               return autofs4_expire_run(inode->i_sb,filp->f_path.mnt,sbi, p);
        /* same as above, but can send multiple expires through pipe */
        case AUTOFS_IOC_EXPIRE_MULTI:
-               return autofs4_expire_multi(inode->i_sb,filp->f_vfsmnt,sbi, p);
+               return autofs4_expire_multi(inode->i_sb,filp->f_path.mnt,sbi, p);
 
        default:
                return -ENOSYS;