Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b1ae27a authored by Al Viro's avatar Al Viro
Browse files

Revert "autofs4: always use lookup for lookup"



This reverts commit 213614d5.

Alas, ->d_revalidate() can't rely on ->lookup() finishing what
it's started; if d_alloc() in do_lookup() fails, we are not going
to call ->lookup() at all.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 60b341b7
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -60,11 +60,6 @@ do { \
		current->pid, __func__, ##args);	\
} while (0)

struct rehash_entry {
	struct task_struct *task;
	struct list_head list;
};

/* Unified info structure.  This is pointed to by both the dentry and
   inode structures.  Each file in the filesystem has an instance of this
   structure.  It holds a reference to the dentry, so dentries are never
@@ -81,7 +76,6 @@ struct autofs_info {

	struct list_head active;
	int active_count;
	struct list_head rehash_list;

	struct list_head expiring;

@@ -104,7 +98,6 @@ struct autofs_info {
#define AUTOFS_INF_EXPIRING	(1<<0) /* dentry is in the process of expiring */
#define AUTOFS_INF_MOUNTPOINT	(1<<1) /* mountpoint status for direct expire */
#define AUTOFS_INF_PENDING	(1<<2) /* dentry pending mount */
#define AUTOFS_INF_REHASH	(1<<3) /* dentry in transit to ->lookup() */

struct autofs_wait_queue {
	wait_queue_head_t queue;
+1 −5
Original line number Diff line number Diff line
@@ -279,7 +279,6 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
			root->d_mounted--;
		}
		ino->flags |= AUTOFS_INF_EXPIRING;
		autofs4_add_expiring(root);
		init_completion(&ino->expire_complete);
		spin_unlock(&sbi->fs_lock);
		return root;
@@ -407,7 +406,6 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
		expired, (int)expired->d_name.len, expired->d_name.name);
	ino = autofs4_dentry_ino(expired);
	ino->flags |= AUTOFS_INF_EXPIRING;
	autofs4_add_expiring(expired);
	init_completion(&ino->expire_complete);
	spin_unlock(&sbi->fs_lock);
	spin_lock(&dcache_lock);
@@ -435,7 +433,7 @@ int autofs4_expire_wait(struct dentry *dentry)

		DPRINTK("expire done status=%d", status);

		if (d_unhashed(dentry) && IS_DEADDIR(dentry->d_inode))
		if (d_unhashed(dentry))
			return -EAGAIN;

		return status;
@@ -475,7 +473,6 @@ int autofs4_expire_run(struct super_block *sb,
	spin_lock(&sbi->fs_lock);
	ino = autofs4_dentry_ino(dentry);
	ino->flags &= ~AUTOFS_INF_EXPIRING;
	autofs4_del_expiring(dentry);
	complete_all(&ino->expire_complete);
	spin_unlock(&sbi->fs_lock);

@@ -506,7 +503,6 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
			ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
		}
		ino->flags &= ~AUTOFS_INF_EXPIRING;
		autofs4_del_expiring(dentry);
		complete_all(&ino->expire_complete);
		spin_unlock(&sbi->fs_lock);
		dput(dentry);
+0 −1
Original line number Diff line number Diff line
@@ -49,7 +49,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
		ino->dentry = NULL;
		ino->size = 0;
		INIT_LIST_HEAD(&ino->active);
		INIT_LIST_HEAD(&ino->rehash_list);
		ino->active_count = 0;
		INIT_LIST_HEAD(&ino->expiring);
		atomic_set(&ino->count, 0);
+157 −317
Original line number Diff line number Diff line
@@ -104,99 +104,6 @@ static void autofs4_del_active(struct dentry *dentry)
	return;
}

static void autofs4_add_rehash_entry(struct autofs_info *ino,
				     struct rehash_entry *entry)
{
	entry->task = current;
	INIT_LIST_HEAD(&entry->list);
	list_add(&entry->list, &ino->rehash_list);
	return;
}

static void autofs4_remove_rehash_entry(struct autofs_info *ino)
{
	struct list_head *head = &ino->rehash_list;
	struct rehash_entry *entry;
	list_for_each_entry(entry, head, list) {
		if (entry->task == current) {
			list_del(&entry->list);
			kfree(entry);
			break;
		}
	}
	return;
}

static void autofs4_remove_rehash_entrys(struct autofs_info *ino)
{
	struct autofs_sb_info *sbi = ino->sbi;
	struct rehash_entry *entry, *next;
	struct list_head *head;

	spin_lock(&sbi->fs_lock);
	spin_lock(&sbi->lookup_lock);
	if (!(ino->flags & AUTOFS_INF_REHASH)) {
		spin_unlock(&sbi->lookup_lock);
		spin_unlock(&sbi->fs_lock);
		return;
	}
	ino->flags &= ~AUTOFS_INF_REHASH;
	head = &ino->rehash_list;
	list_for_each_entry_safe(entry, next, head, list) {
		list_del(&entry->list);
		kfree(entry);
	}
	spin_unlock(&sbi->lookup_lock);
	spin_unlock(&sbi->fs_lock);
	dput(ino->dentry);

	return;
}

static void autofs4_revalidate_drop(struct dentry *dentry,
				    struct rehash_entry *entry)
{
	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
	struct autofs_info *ino = autofs4_dentry_ino(dentry);
	/*
	 * Add to the active list so we can pick this up in
	 * ->lookup(). Also add an entry to a rehash list so
	 * we know when there are no dentrys in flight so we
	 * know when we can rehash the dentry.
	 */
	spin_lock(&sbi->lookup_lock);
	if (list_empty(&ino->active))
		list_add(&ino->active, &sbi->active_list);
	autofs4_add_rehash_entry(ino, entry);
	spin_unlock(&sbi->lookup_lock);
	if (!(ino->flags & AUTOFS_INF_REHASH)) {
		ino->flags |= AUTOFS_INF_REHASH;
		dget(dentry);
		spin_lock(&dentry->d_lock);
		__d_drop(dentry);
		spin_unlock(&dentry->d_lock);
	}
	return;
}

static void autofs4_revalidate_rehash(struct dentry *dentry)
{
	struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
	struct autofs_info *ino = autofs4_dentry_ino(dentry);
	if (ino->flags & AUTOFS_INF_REHASH) {
		spin_lock(&sbi->lookup_lock);
		autofs4_remove_rehash_entry(ino);
		if (list_empty(&ino->rehash_list)) {
			spin_unlock(&sbi->lookup_lock);
			ino->flags &= ~AUTOFS_INF_REHASH;
			d_rehash(dentry);
			dput(ino->dentry);
		} else
			spin_unlock(&sbi->lookup_lock);
	}
	return;
}

static unsigned int autofs4_need_mount(unsigned int flags)
{
	unsigned int res = 0;
@@ -236,7 +143,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
	return dcache_dir_open(inode, file);
}

static int try_to_fill_dentry(struct dentry *dentry)
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);
@@ -249,6 +156,7 @@ static int try_to_fill_dentry(struct dentry *dentry)
	 * Wait for a pending mount, triggering one if there
	 * isn't one already
	 */
	if (dentry->d_inode == NULL) {
		DPRINTK("waiting for mount name=%.*s",
			 dentry->d_name.len, dentry->d_name.name);

@@ -256,11 +164,48 @@ static int try_to_fill_dentry(struct dentry *dentry)

		DPRINTK("mount done status=%d", status);

	/* Update expiry counter */
	ino->last_used = jiffies;
		/* Turn this into a real negative dentry? */
		if (status == -ENOENT) {
			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 status;
		}
	/* Trigger mount for path component or follow link */
	} 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(&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(&sbi->fs_lock);
			ino->flags &= ~AUTOFS_INF_PENDING;
			spin_unlock(&sbi->fs_lock);
			return status;
		}
	}

	/* Initialize expiry counter after successful mount */
	if (ino)
		ino->last_used = jiffies;

	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)
@@ -313,16 +258,10 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
	 */
	if (ino->flags & AUTOFS_INF_PENDING ||
	    (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) {
		ino->flags |= AUTOFS_INF_PENDING;
		spin_unlock(&dcache_lock);
		spin_unlock(&sbi->fs_lock);

		status = try_to_fill_dentry(dentry);

		spin_lock(&sbi->fs_lock);
		ino->flags &= ~AUTOFS_INF_PENDING;
		spin_unlock(&sbi->fs_lock);

		status = try_to_fill_dentry(dentry, 0);
		if (status)
			goto out_error;

@@ -361,47 +300,18 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
{
	struct inode *dir = dentry->d_parent->d_inode;
	struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
	struct autofs_info *ino = autofs4_dentry_ino(dentry);
	struct rehash_entry *entry;
	int oz_mode = autofs4_oz_mode(sbi);
	int flags = nd ? nd->flags : 0;
	unsigned int mutex_aquired;
	int status = 1;

	DPRINTK("name = %.*s oz_mode = %d",
		dentry->d_name.len, dentry->d_name.name, oz_mode);

	/* Daemon never causes a mount to trigger */
	if (autofs4_oz_mode(sbi))
		return 1;

	entry = kmalloc(sizeof(struct rehash_entry), GFP_KERNEL);
	if (!entry)
		return -ENOMEM;

	mutex_aquired = mutex_trylock(&dir->i_mutex);

	spin_lock(&sbi->fs_lock);
	spin_lock(&dcache_lock);
	/* Pending dentry */
	spin_lock(&sbi->fs_lock);
	if (autofs4_ispending(dentry)) {
		int status;

		/*
		 * We can only unhash and send this to ->lookup() if
		 * the directory mutex is held over d_revalidate() and
		 * ->lookup(). This prevents the VFS from incorrectly
		 * seeing the dentry as non-existent.
		 */
		ino->flags |= AUTOFS_INF_PENDING;
		if (!mutex_aquired) {
			autofs4_revalidate_drop(dentry, entry);
			spin_unlock(&dcache_lock);
		/* The daemon never causes a mount to trigger */
		spin_unlock(&sbi->fs_lock);
			return 0;
		}
		spin_unlock(&dcache_lock);
		spin_unlock(&sbi->fs_lock);
		mutex_unlock(&dir->i_mutex);
		kfree(entry);

		if (oz_mode)
			return 1;

		/*
		 * If the directory has gone away due to an expire
@@ -415,82 +325,45 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
		 * A zero status is success otherwise we have a
		 * negative error code.
		 */
		status = try_to_fill_dentry(dentry);

		spin_lock(&sbi->fs_lock);
		ino->flags &= ~AUTOFS_INF_PENDING;
		spin_unlock(&sbi->fs_lock);

		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)
		return 0;

	/* Check for a non-mountpoint directory with no contents */
	spin_lock(&dcache_lock);
	if (S_ISDIR(dentry->d_inode->i_mode) &&
	    !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
		DPRINTK("dentry=%p %.*s, emptydir",
			 dentry, dentry->d_name.len, dentry->d_name.name);

		if (autofs4_need_mount(flags) || current->link_count) {
			int status;

			/*
			 * We can only unhash and send this to ->lookup() if
			 * the directory mutex is held over d_revalidate() and
			 * ->lookup(). This prevents the VFS from incorrectly
			 * seeing the dentry as non-existent.
			 */
			ino->flags |= AUTOFS_INF_PENDING;
			if (!mutex_aquired) {
				autofs4_revalidate_drop(dentry, entry);
		spin_unlock(&dcache_lock);
				spin_unlock(&sbi->fs_lock);
				return 0;
			}
			spin_unlock(&dcache_lock);
			spin_unlock(&sbi->fs_lock);
			mutex_unlock(&dir->i_mutex);
			kfree(entry);

		/* 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);

			spin_lock(&sbi->fs_lock);
			ino->flags &= ~AUTOFS_INF_PENDING;
			spin_unlock(&sbi->fs_lock);

		status = try_to_fill_dentry(dentry, flags);
		if (status == 0)
			return 1;

		return status;
	}
	}
	spin_unlock(&dcache_lock);
	spin_unlock(&sbi->fs_lock);

	if (mutex_aquired)
		mutex_unlock(&dir->i_mutex);

	kfree(entry);

	return 1;
}

static void autofs4_free_rehash_entrys(struct autofs_info *inf)
{
	struct list_head *head = &inf->rehash_list;
	struct rehash_entry *entry, *next;
	list_for_each_entry_safe(entry, next, head, list) {
		list_del(&entry->list);
		kfree(entry);
	}
}

void autofs4_dentry_release(struct dentry *de)
{
	struct autofs_info *inf;
@@ -509,8 +382,6 @@ void autofs4_dentry_release(struct dentry *de)
				list_del(&inf->active);
			if (!list_empty(&inf->expiring))
				list_del(&inf->expiring);
			if (!list_empty(&inf->rehash_list))
				autofs4_free_rehash_entrys(inf);
			spin_unlock(&sbi->lookup_lock);
		}

@@ -543,7 +414,6 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
	const unsigned char *str = name->name;
	struct list_head *p, *head;

restart:
	spin_lock(&dcache_lock);
	spin_lock(&sbi->lookup_lock);
	head = &sbi->active_list;
@@ -561,19 +431,6 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
		if (atomic_read(&active->d_count) == 0)
			goto next;

		if (active->d_inode && IS_DEADDIR(active->d_inode)) {
			if (!list_empty(&ino->rehash_list)) {
				dget(active);
				spin_unlock(&active->d_lock);
				spin_unlock(&sbi->lookup_lock);
				spin_unlock(&dcache_lock);
				autofs4_remove_rehash_entrys(ino);
				dput(active);
				goto restart;
			}
			goto next;
		}

		qstr = &active->d_name;

		if (active->d_name.hash != hash)
@@ -586,11 +443,13 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
		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);
	}
@@ -639,11 +498,13 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
		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);
	}
@@ -653,11 +514,32 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
	return NULL;
}

static struct autofs_info *init_new_dentry(struct autofs_sb_info *sbi,
					   struct dentry *dentry, int oz_mode)
/* 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",
		dentry->d_name.len, dentry->d_name.name);

	/* File name too long to exist */
	if (dentry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);

	sbi = autofs4_sbi(dir->i_sb);
	oz_mode = autofs4_oz_mode(sbi);

	DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
		 current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);

	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
@@ -683,60 +565,14 @@ static struct autofs_info *init_new_dentry(struct autofs_sb_info *sbi,
		dentry->d_fsdata = ino;
		ino->dentry = dentry;

	/*
	 * Only set the mount pending flag for new dentrys not created
	 * by the daemon.
	 */
	if (!oz_mode)
		ino->flags |= AUTOFS_INF_PENDING;
		autofs4_add_active(dentry);

		d_instantiate(dentry, NULL);

	return ino;
}

/* 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;
	int status = 0;

	DPRINTK("name = %.*s",
		dentry->d_name.len, dentry->d_name.name);

	/* File name too long to exist */
	if (dentry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);

	sbi = autofs4_sbi(dir->i_sb);
	oz_mode = autofs4_oz_mode(sbi);

	DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
		 current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);

	spin_lock(&sbi->fs_lock);
	active = autofs4_lookup_active(dentry);
	if (active) {
		dentry = active;
		ino = autofs4_dentry_ino(dentry);
		/* If this came from revalidate, rehash it */
		autofs4_revalidate_rehash(dentry);
		spin_unlock(&sbi->fs_lock);
	} else {
		spin_unlock(&sbi->fs_lock);
		ino = init_new_dentry(sbi, dentry, oz_mode);
		if (IS_ERR(ino))
			return (struct dentry *) ino;
	}

	autofs4_add_active(dentry);

	if (!oz_mode) {
		expiring = autofs4_lookup_expiring(dentry);
		mutex_unlock(&dir->i_mutex);
		expiring = autofs4_lookup_expiring(dentry);
		if (expiring) {
			/*
			 * If we are racing with expire the request might not
@@ -744,22 +580,23 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
			 * so it must have been successful, so just wait for it.
			 */
			autofs4_expire_wait(expiring);
			autofs4_del_expiring(expiring);
			dput(expiring);
		}
		status = try_to_fill_dentry(dentry);
		mutex_lock(&dir->i_mutex);

		spin_lock(&sbi->fs_lock);
		ino->flags &= ~AUTOFS_INF_PENDING;
		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);
	}

	autofs4_del_active(dentry);

	/*
	 * If we had a mount fail, check if we had to handle
	 * If we are still pending, check if we had to handle
	 * a signal. If so we can force a restart..
	 */
	if (status) {
	if (ino->flags & AUTOFS_INF_PENDING) {
		/* See if we were interrupted */
		if (signal_pending(current)) {
			sigset_t *sigset = &current->pending.signal;
@@ -771,45 +608,42 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
			    return ERR_PTR(-ERESTARTNOINTR);
			}
		}
		if (!oz_mode) {
			spin_lock(&sbi->fs_lock);
			ino->flags &= ~AUTOFS_INF_PENDING;
			spin_unlock(&sbi->fs_lock);
		}
	}

	/*
	 * User space 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.
	 * If this dentry is unhashed, then we shouldn't honour this
	 * 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 (!oz_mode && !have_submounts(dentry)) {
		struct dentry *new;
		new = d_lookup(dentry->d_parent, &dentry->d_name);
		if (new) {
			if (active)
				dput(active);
			return new;
		} else {
			if (!status)
				status = -ENOENT;
		}
	}

	if (!oz_mode && d_unhashed(dentry)) {
		/*
	 * If we had a mount failure, return status to user space.
	 * If the mount succeeded and we used a dentry from the active queue
	 * return it.
		 * 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.
		 */
	if (status) {
		dentry = ERR_PTR(status);
		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;
	} else {
		/*
		 * Valid successful mount, return active dentry or NULL
		 * for a new dentry.
		 */
	}

	if (active)
		return active;
	}

	return NULL;
}
@@ -834,6 +668,8 @@ static int autofs4_dir_symlink(struct inode *dir,
	if (!ino)
		return -ENOMEM;

	autofs4_del_active(dentry);

	ino->size = strlen(symname);
	cp = kmalloc(ino->size + 1, GFP_KERNEL);
	if (!cp) {
@@ -910,6 +746,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
	dir->i_mtime = CURRENT_TIME;

	spin_lock(&dcache_lock);
	autofs4_add_expiring(dentry);
	spin_lock(&dentry->d_lock);
	__d_drop(dentry);
	spin_unlock(&dentry->d_lock);
@@ -935,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);
@@ -972,6 +810,8 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
	if (!ino)
		return -ENOMEM;

	autofs4_del_active(dentry);

	inode = autofs4_get_inode(dir->i_sb, ino);
	if (!inode) {
		if (!dentry->d_fsdata)