Ian Kent 3685ec
autofs-5.0.3 - fix submount shutdown handling.
Ian Kent 3685ec
Ian Kent 3685ec
From: Ian Kent <raven@themaw.net>
Ian Kent 3685ec
Ian Kent 3685ec
When using submount maps on a busy system autofs can hang.
Ian Kent 3685ec
Ian Kent 3685ec
This problem comes about because of processes walking into the
Ian Kent 3685ec
submount filesystem when it is in the process of shutting down.
Ian Kent 3685ec
While this race has been fixed for other types of mounts it
Ian Kent 3685ec
still isn't possible to to block processes from walking into
Ian Kent 3685ec
submounts that are expiring so we need to be able to recover
Ian Kent 3685ec
when this happens.
Ian Kent 3685ec
Ian Kent 3685ec
This patch improves the submount shutdown logic and allows
Ian Kent 3685ec
submounts that become busy during shutdown to recover.
Ian Kent 3685ec
---
Ian Kent 3685ec
Ian Kent 3685ec
 CHANGELOG              |    1 
Ian Kent 3685ec
 daemon/automount.c     |  208 +++++++++++++++++++-----------------------
Ian Kent 3685ec
 daemon/direct.c        |   97 ++++++++++++++------
Ian Kent 3685ec
 daemon/indirect.c      |  114 ++++++++++++++++++-----
Ian Kent 3685ec
 daemon/lookup.c        |   11 --
Ian Kent 3685ec
 daemon/state.c         |  235 +++++++++++++++++++++++++++++++++---------------
Ian Kent 3685ec
 include/automount.h    |   17 ---
Ian Kent 3685ec
 include/master.h       |    5 -
Ian Kent 3685ec
 include/state.h        |    9 ++
Ian Kent 3685ec
 lib/alarm.c            |   14 ---
Ian Kent 3685ec
 lib/master.c           |  180 +++++++------------------------------
Ian Kent 3685ec
 modules/mount_autofs.c |    2 
Ian Kent 3685ec
 12 files changed, 458 insertions(+), 435 deletions(-)
Ian Kent 3685ec
Ian Kent 3685ec
Ian Kent 3685ec
diff --git a/CHANGELOG b/CHANGELOG
Ian Kent 3685ec
index 9da7be3..ff04985 100644
Ian Kent 3685ec
--- a/CHANGELOG
Ian Kent 3685ec
+++ b/CHANGELOG
Ian Kent 3685ec
@@ -26,6 +26,7 @@
Ian Kent 3685ec
 - add command line option to override check for daemon already running.
Ian Kent 3685ec
 - don't use proc file system when checking if the daemon is running.
Ian Kent 3685ec
 - make handle_mounts startup condition distinct.
Ian Kent 3685ec
+- fix submount shutdown recovery handling.
Ian Kent 3685ec
  
Ian Kent 3685ec
 14/01/2008 autofs-5.0.3
Ian Kent 3685ec
 -----------------------
Ian Kent 3685ec
diff --git a/daemon/automount.c b/daemon/automount.c
Ian Kent 3685ec
index 086affb..68bf1d3 100644
Ian Kent 3685ec
--- a/daemon/automount.c
Ian Kent 3685ec
+++ b/daemon/automount.c
Ian Kent 3685ec
@@ -369,6 +369,18 @@ int count_mounts(unsigned logopt, const char *path, dev_t dev)
Ian Kent 3685ec
 
Ian Kent 3685ec
 static void check_rm_dirs(struct autofs_point *ap, const char *path, int incl)
Ian Kent 3685ec
 {
Ian Kent 3685ec
+	/*
Ian Kent 3685ec
+	 * If we're a submount the kernel can't know we're trying to
Ian Kent 3685ec
+	 * shutdown and so cannot block processes walking into the
Ian Kent 3685ec
+	 * mount point directory. If this is the call to umount_multi()
Ian Kent 3685ec
+	 * made during shutdown (incl == 0) we have to leave any mount
Ian Kent 3685ec
+	 * point directories in place so we can recover if needed. The
Ian Kent 3685ec
+	 * umount itself will clean these directories up for us
Ian Kent 3685ec
+	 * automagically.
Ian Kent 3685ec
+	 */
Ian Kent 3685ec
+	if (!incl && ap->submount)
Ian Kent 3685ec
+		return;
Ian Kent 3685ec
+
Ian Kent 3685ec
 	if ((!ap->ghost) ||
Ian Kent 3685ec
 	    (ap->state == ST_SHUTDOWN_PENDING ||
Ian Kent 3685ec
 	     ap->state == ST_SHUTDOWN_FORCE ||
Ian Kent 3685ec
@@ -390,8 +402,6 @@ static void update_map_cache(struct autofs_point *ap, const char *path)
Ian Kent 3685ec
 	else
Ian Kent 3685ec
 		key = path;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
Ian Kent 3685ec
-	master_source_readlock(ap->entry);
Ian Kent 3685ec
 	map = ap->entry->maps;
Ian Kent 3685ec
 	while (map) {
Ian Kent 3685ec
 		struct mapent *me = NULL;
Ian Kent 3685ec
@@ -413,7 +423,6 @@ static void update_map_cache(struct autofs_point *ap, const char *path)
Ian Kent 3685ec
 
Ian Kent 3685ec
 		map = map->next;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
-	pthread_cleanup_pop(1);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -918,38 +927,22 @@ static int get_pkt(struct autofs_point *ap, union autofs_v5_packet_union *pkt)
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 
Ian Kent 3685ec
 		if (fds[1].revents & POLLIN) {
Ian Kent 3685ec
-			enum states next_state, post_state;
Ian Kent 3685ec
+			enum states next_state;
Ian Kent 3685ec
 			size_t read_size = sizeof(next_state);
Ian Kent 3685ec
 			int state_pipe;
Ian Kent 3685ec
 
Ian Kent 3685ec
-			next_state = post_state = ST_INVAL;
Ian Kent 3685ec
+			next_state = ST_INVAL;
Ian Kent 3685ec
 
Ian Kent 3685ec
-			state_mutex_lock(ap);
Ian Kent 3685ec
+			st_mutex_lock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 			state_pipe = ap->state_pipe[0];
Ian Kent 3685ec
 
Ian Kent 3685ec
 			if (fullread(state_pipe, &next_state, read_size)) {
Ian Kent 3685ec
-				state_mutex_unlock(ap);
Ian Kent 3685ec
+				st_mutex_unlock();
Ian Kent 3685ec
 				continue;
Ian Kent 3685ec
 			}
Ian Kent 3685ec
 
Ian Kent 3685ec
-			if (next_state != ST_INVAL && next_state != ap->state) {
Ian Kent 3685ec
-				if (next_state != ST_SHUTDOWN)
Ian Kent 3685ec
-					post_state = next_state;
Ian Kent 3685ec
-				else
Ian Kent 3685ec
-					ap->state = ST_SHUTDOWN;
Ian Kent 3685ec
-			}
Ian Kent 3685ec
-
Ian Kent 3685ec
-			state_mutex_unlock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
-			if (post_state != ST_INVAL) {
Ian Kent 3685ec
-				if (post_state == ST_SHUTDOWN_PENDING ||
Ian Kent 3685ec
-				    post_state == ST_SHUTDOWN_FORCE) {
Ian Kent 3685ec
-					alarm_delete(ap);
Ian Kent 3685ec
-					st_remove_tasks(ap);
Ian Kent 3685ec
-				}
Ian Kent 3685ec
-				st_add_task(ap, post_state);
Ian Kent 3685ec
-			}
Ian Kent 3685ec
+			st_mutex_unlock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 			if (next_state == ST_SHUTDOWN)
Ian Kent 3685ec
 				return -1;
Ian Kent 3685ec
@@ -985,11 +978,14 @@ int do_expire(struct autofs_point *ap, const char *name, int namelen)
Ian Kent 3685ec
 
Ian Kent 3685ec
 	info(ap->logopt, "expiring path %s", buf);
Ian Kent 3685ec
 
Ian Kent 3685ec
+	pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
Ian Kent 3685ec
+	master_source_readlock(ap->entry);
Ian Kent 3685ec
 	ret = umount_multi(ap, buf, 1);
Ian Kent 3685ec
 	if (ret == 0)
Ian Kent 3685ec
 		info(ap->logopt, "expired %s", buf);
Ian Kent 3685ec
 	else
Ian Kent 3685ec
 		warn(ap->logopt, "couldn't complete expire of %s", buf);
Ian Kent 3685ec
+	pthread_cleanup_pop(1);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return ret;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -1069,7 +1065,7 @@ static int mount_autofs(struct autofs_point *ap)
Ian Kent 3685ec
 	if (status < 0)
Ian Kent 3685ec
 		return -1;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	ap->state = ST_READY;
Ian Kent 3685ec
+	st_add_task(ap, ST_READY);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return 0;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -1423,44 +1419,6 @@ static void return_start_status(void *arg)
Ian Kent 3685ec
 		fatal(status);
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
-static void mutex_operation_wait(pthread_mutex_t *mutex)
Ian Kent 3685ec
-{
Ian Kent 3685ec
-	int status;
Ian Kent 3685ec
-
Ian Kent 3685ec
-	/*
Ian Kent 3685ec
-	 * Unlock a mutex, but wait for a pending operation
Ian Kent 3685ec
-	 * if one is in progress
Ian Kent 3685ec
-	 */
Ian Kent 3685ec
-	status = pthread_mutex_trylock(mutex);
Ian Kent 3685ec
-	if (status) {
Ian Kent 3685ec
-		if (status == EBUSY) {
Ian Kent 3685ec
-			/* Mutex locked - do we own it */
Ian Kent 3685ec
-			status = pthread_mutex_unlock(mutex);
Ian Kent 3685ec
-			if (status) {
Ian Kent 3685ec
-				if (status != EPERM)
Ian Kent 3685ec
-					fatal(status);
Ian Kent 3685ec
-			} else
Ian Kent 3685ec
-				return;
Ian Kent 3685ec
-
Ian Kent 3685ec
-			status = pthread_mutex_lock(mutex);
Ian Kent 3685ec
-			if (status)
Ian Kent 3685ec
-				fatal(status);
Ian Kent 3685ec
-		} else
Ian Kent 3685ec
-			fatal(status);
Ian Kent 3685ec
-
Ian Kent 3685ec
-		/* Operation complete, release it */
Ian Kent 3685ec
-		status = pthread_mutex_unlock(mutex);
Ian Kent 3685ec
-		if (status)
Ian Kent 3685ec
-			fatal(status);
Ian Kent 3685ec
-	} else {
Ian Kent 3685ec
-		status = pthread_mutex_unlock(mutex);
Ian Kent 3685ec
-		if (status)
Ian Kent 3685ec
-			fatal(status);
Ian Kent 3685ec
-	}
Ian Kent 3685ec
-
Ian Kent 3685ec
-	return;
Ian Kent 3685ec
-}
Ian Kent 3685ec
-
Ian Kent 3685ec
 int handle_mounts_startup_cond_init(struct startup_cond *suc)
Ian Kent 3685ec
 {
Ian Kent 3685ec
 	int status;
Ian Kent 3685ec
@@ -1526,22 +1484,25 @@ static void handle_mounts_cleanup(void *arg)
Ian Kent 3685ec
 	if (!submount && strcmp(ap->path, "/-") && ap->dir_created)
Ian Kent 3685ec
 		clean = 1;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	/* If we have been canceled then we may hold the state mutex. */
Ian Kent 3685ec
-	mutex_operation_wait(&ap->state_mutex);
Ian Kent 3685ec
+	if (submount) {
Ian Kent 3685ec
+		/* We are finishing up */
Ian Kent 3685ec
+		ap->parent->submnt_count--;
Ian Kent 3685ec
+		list_del_init(&ap->mounts);
Ian Kent 3685ec
+	}
Ian Kent 3685ec
 
Ian Kent 3685ec
-	alarm_delete(ap);
Ian Kent 3685ec
-	st_remove_tasks(ap);
Ian Kent 3685ec
+	master_remove_mapent(ap->entry);
Ian Kent 3685ec
+	master_source_unlock(ap->entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	umount_autofs(ap, 1);
Ian Kent 3685ec
+	if (submount) {
Ian Kent 3685ec
+		mounts_mutex_unlock(ap->parent);
Ian Kent 3685ec
+		master_source_unlock(ap->parent->entry);
Ian Kent 3685ec
+	}
Ian Kent 3685ec
+	master_mutex_unlock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 	destroy_logpri_fifo(ap);
Ian Kent 3685ec
-	master_signal_submount(ap, MASTER_SUBMNT_JOIN);
Ian Kent 3685ec
-	master_remove_mapent(ap->entry);
Ian Kent 3685ec
 	master_free_mapent_sources(ap->entry, 1);
Ian Kent 3685ec
 	master_free_mapent(ap->entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	sched_yield();
Ian Kent 3685ec
-
Ian Kent 3685ec
 	if (clean) {
Ian Kent 3685ec
 		if (rmdir(path) == -1) {
Ian Kent 3685ec
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
Ian Kent 3685ec
@@ -1572,8 +1533,6 @@ void *handle_mounts(void *arg)
Ian Kent 3685ec
 	pthread_cleanup_push(return_start_status, suc);
Ian Kent 3685ec
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	state_mutex_lock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	status = pthread_mutex_lock(&suc->mutex);
Ian Kent 3685ec
 	if (status) {
Ian Kent 3685ec
 		logerr("failed to lock startup condition mutex!");
Ian Kent 3685ec
@@ -1583,7 +1542,6 @@ void *handle_mounts(void *arg)
Ian Kent 3685ec
 	if (mount_autofs(ap) < 0) {
Ian Kent 3685ec
 		crit(ap->logopt, "mount of %s failed!", ap->path);
Ian Kent 3685ec
 		suc->status = 1;
Ian Kent 3685ec
-		state_mutex_unlock(ap);
Ian Kent 3685ec
 		umount_autofs(ap, 1);
Ian Kent 3685ec
 		pthread_setcancelstate(cancel_state, NULL);
Ian Kent 3685ec
 		pthread_exit(NULL);
Ian Kent 3685ec
@@ -1600,56 +1558,70 @@ void *handle_mounts(void *arg)
Ian Kent 3685ec
 	if (!ap->submount && ap->exp_timeout)
Ian Kent 3685ec
 		alarm_add(ap, ap->exp_runfreq + rand() % ap->exp_runfreq);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	pthread_cleanup_push(handle_mounts_cleanup, ap);
Ian Kent 3685ec
 	pthread_setcancelstate(cancel_state, NULL);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	state_mutex_unlock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	while (ap->state != ST_SHUTDOWN) {
Ian Kent 3685ec
 		if (handle_packet(ap)) {
Ian Kent 3685ec
-			int ret, result;
Ian Kent 3685ec
+			int ret, cur_state;
Ian Kent 3685ec
+
Ian Kent 3685ec
+			/*
Ian Kent 3685ec
+			 * If we're a submount we need to ensure our parent
Ian Kent 3685ec
+			 * doesn't try to mount us again until our shutdown
Ian Kent 3685ec
+			 * is complete and that any outstanding mounts are
Ian Kent 3685ec
+			 * completed before we try to shutdown.
Ian Kent 3685ec
+			 */
Ian Kent 3685ec
+			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Ian Kent 3685ec
+
Ian Kent 3685ec
+			master_mutex_lock();
Ian Kent 3685ec
+
Ian Kent 3685ec
+			if (ap->submount) {
Ian Kent 3685ec
+				master_source_writelock(ap->parent->entry);
Ian Kent 3685ec
+				mounts_mutex_lock(ap->parent);
Ian Kent 3685ec
+			}
Ian Kent 3685ec
+
Ian Kent 3685ec
+			master_source_writelock(ap->entry);
Ian Kent 3685ec
+
Ian Kent 3685ec
+			if (ap->state != ST_SHUTDOWN) {
Ian Kent 3685ec
+				if (!ap->submount)
Ian Kent 3685ec
+					alarm_add(ap, ap->exp_runfreq);
Ian Kent 3685ec
+				/* Return to ST_READY is done immediately */
Ian Kent 3685ec
+				st_add_task(ap, ST_READY);
Ian Kent 3685ec
+				master_source_unlock(ap->entry);
Ian Kent 3685ec
+				if (ap->submount) {
Ian Kent 3685ec
+					mounts_mutex_unlock(ap->parent);
Ian Kent 3685ec
+					master_source_unlock(ap->parent->entry);
Ian Kent 3685ec
+				}
Ian Kent 3685ec
+
Ian Kent 3685ec
+				master_mutex_unlock();
Ian Kent 3685ec
+
Ian Kent 3685ec
+				pthread_setcancelstate(cur_state, NULL);
Ian Kent 3685ec
+				continue;
Ian Kent 3685ec
+			}
Ian Kent 3685ec
+
Ian Kent 3685ec
+			alarm_delete(ap);
Ian Kent 3685ec
+			st_remove_tasks(ap);
Ian Kent 3685ec
+			st_wait_task(ap, ST_ANY, 0);
Ian Kent 3685ec
 
Ian Kent 3685ec
-			state_mutex_lock(ap);
Ian Kent 3685ec
 			/*
Ian Kent 3685ec
 			 * For a direct mount map all mounts have already gone
Ian Kent 3685ec
-			 * by the time we get here.
Ian Kent 3685ec
+			 * by the time we get here and since we only ever
Ian Kent 3685ec
+			 * umount direct mounts at shutdown there is no need
Ian Kent 3685ec
+			 * to check for possible recovery.
Ian Kent 3685ec
 			 */
Ian Kent 3685ec
 			if (ap->type == LKP_DIRECT) {
Ian Kent 3685ec
-				status = 1;
Ian Kent 3685ec
-				state_mutex_unlock(ap);
Ian Kent 3685ec
+				umount_autofs(ap, 1);
Ian Kent 3685ec
 				break;
Ian Kent 3685ec
 			}
Ian Kent 3685ec
 
Ian Kent 3685ec
 			/*
Ian Kent 3685ec
-			 * If the ioctl fails assume the kernel doesn't have
Ian Kent 3685ec
-			 * AUTOFS_IOC_ASKUMOUNT and just continue.
Ian Kent 3685ec
+			 * If umount_autofs returns non-zero it wasn't able
Ian Kent 3685ec
+			 * to complete the umount and has left the mount intact
Ian Kent 3685ec
+			 * so we can continue. This can happen if a lookup
Ian Kent 3685ec
+			 * occurs while we're trying to umount.
Ian Kent 3685ec
 			 */
Ian Kent 3685ec
-			ret = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &result);
Ian Kent 3685ec
-			if (ret == -1) {
Ian Kent 3685ec
-				state_mutex_unlock(ap);
Ian Kent 3685ec
+			ret = umount_autofs(ap, 1);
Ian Kent 3685ec
+			if (!ret)
Ian Kent 3685ec
 				break;
Ian Kent 3685ec
-			}
Ian Kent 3685ec
-
Ian Kent 3685ec
-			/* OK to exit */
Ian Kent 3685ec
-			if (ap->state == ST_SHUTDOWN) {
Ian Kent 3685ec
-				if (result) {
Ian Kent 3685ec
-					state_mutex_unlock(ap);
Ian Kent 3685ec
-					break;
Ian Kent 3685ec
-				}
Ian Kent 3685ec
-#ifdef ENABLE_IGNORE_BUSY_MOUNTS
Ian Kent 3685ec
-				/*
Ian Kent 3685ec
-				 * There weren't any active mounts but if the
Ian Kent 3685ec
-				 * filesystem is busy there may be a mount
Ian Kent 3685ec
-				 * request in progress so return to the ready
Ian Kent 3685ec
-				 * state unless a shutdown has been explicitly
Ian Kent 3685ec
-				 * requested.
Ian Kent 3685ec
-				 */
Ian Kent 3685ec
-				if (ap->shutdown) {
Ian Kent 3685ec
-					state_mutex_unlock(ap);
Ian Kent 3685ec
-					break;
Ian Kent 3685ec
-				}
Ian Kent 3685ec
-#endif
Ian Kent 3685ec
-			}
Ian Kent 3685ec
 
Ian Kent 3685ec
 			/* Failed shutdown returns to ready */
Ian Kent 3685ec
 			warn(ap->logopt,
Ian Kent 3685ec
@@ -1657,14 +1629,22 @@ void *handle_mounts(void *arg)
Ian Kent 3685ec
 			     ap->path);
Ian Kent 3685ec
 			if (!ap->submount)
Ian Kent 3685ec
 				alarm_add(ap, ap->exp_runfreq);
Ian Kent 3685ec
-			nextstate(ap->state_pipe[1], ST_READY);
Ian Kent 3685ec
+			/* Return to ST_READY is done immediately */
Ian Kent 3685ec
+			st_add_task(ap, ST_READY);
Ian Kent 3685ec
+			master_source_unlock(ap->entry);
Ian Kent 3685ec
+			if (ap->submount) {
Ian Kent 3685ec
+				mounts_mutex_unlock(ap->parent);
Ian Kent 3685ec
+				master_source_unlock(ap->parent->entry);
Ian Kent 3685ec
+			}
Ian Kent 3685ec
+
Ian Kent 3685ec
+			master_mutex_unlock();
Ian Kent 3685ec
+
Ian Kent 3685ec
+			pthread_setcancelstate(cur_state, NULL);
Ian Kent 3685ec
 
Ian Kent 3685ec
-			state_mutex_unlock(ap);
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
-	pthread_cleanup_pop(1);
Ian Kent 3685ec
-	sched_yield();
Ian Kent 3685ec
+	handle_mounts_cleanup(ap);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return NULL;
Ian Kent 3685ec
 }
Ian Kent 3685ec
diff --git a/daemon/direct.c b/daemon/direct.c
Ian Kent 3685ec
index a3869a5..334a4b6 100644
Ian Kent 3685ec
--- a/daemon/direct.c
Ian Kent 3685ec
+++ b/daemon/direct.c
Ian Kent 3685ec
@@ -216,8 +216,6 @@ int umount_autofs_direct(struct autofs_point *ap)
Ian Kent 3685ec
 
Ian Kent 3685ec
 	mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
Ian Kent 3685ec
 	pthread_cleanup_push(mnts_cleanup, mnts);
Ian Kent 3685ec
-	pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
Ian Kent 3685ec
-	master_source_readlock(ap->entry);
Ian Kent 3685ec
 	nc = ap->entry->master->nc;
Ian Kent 3685ec
 	cache_readlock(nc);
Ian Kent 3685ec
 	pthread_cleanup_push(cache_lock_cleanup, nc);
Ian Kent 3685ec
@@ -244,7 +242,6 @@ int umount_autofs_direct(struct autofs_point *ap)
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 	pthread_cleanup_pop(1);
Ian Kent 3685ec
 	pthread_cleanup_pop(1);
Ian Kent 3685ec
-	pthread_cleanup_pop(1);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return 0;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -572,9 +569,10 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
Ian Kent 3685ec
 			return 1;
Ian Kent 3685ec
 		} else if (!status) {
Ian Kent 3685ec
 			if (ap->state != ST_SHUTDOWN_FORCE) {
Ian Kent 3685ec
-				error(ap->logopt,
Ian Kent 3685ec
-				      "ask umount returned busy for %s",
Ian Kent 3685ec
-				      me->key);
Ian Kent 3685ec
+				if (ap->shutdown)
Ian Kent 3685ec
+					error(ap->logopt,
Ian Kent 3685ec
+					     "ask umount returned busy for %s",
Ian Kent 3685ec
+					     me->key);
Ian Kent 3685ec
 				return 1;
Ian Kent 3685ec
 			} else {
Ian Kent 3685ec
 				me->ioctlfd = -1;
Ian Kent 3685ec
@@ -904,7 +902,10 @@ void *expire_proc_direct(void *arg)
Ian Kent 3685ec
 		 * All direct mounts must be present in the map
Ian Kent 3685ec
 		 * entry cache.
Ian Kent 3685ec
 		 */
Ian Kent 3685ec
+		pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
Ian Kent 3685ec
+		master_source_readlock(ap->entry);
Ian Kent 3685ec
 		me = lookup_source_mapent(ap, next->path, LKP_DISTINCT);
Ian Kent 3685ec
+		pthread_cleanup_pop(1);
Ian Kent 3685ec
 		if (!me)
Ian Kent 3685ec
 			continue;
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -1110,6 +1111,8 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
Ian Kent 3685ec
 	struct pending_args *mt;
Ian Kent 3685ec
 	char buf[MAX_ERR_BUF];
Ian Kent 3685ec
 	pthread_t thid;
Ian Kent 3685ec
+	struct timespec wait;
Ian Kent 3685ec
+	struct timeval now;
Ian Kent 3685ec
 	int status, state;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Ian Kent 3685ec
@@ -1124,7 +1127,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
Ian Kent 3685ec
 	 * and since it got mounted we have to trust that
Ian Kent 3685ec
 	 * there is an entry in the cache.
Ian Kent 3685ec
 	 */
Ian Kent 3685ec
-	master_source_readlock(ap->entry);
Ian Kent 3685ec
+	master_source_writelock(ap->entry);
Ian Kent 3685ec
 	map = ap->entry->maps;
Ian Kent 3685ec
 	while (map) {
Ian Kent 3685ec
 		mc = map->mc;
Ian Kent 3685ec
@@ -1135,7 +1138,6 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
 		map = map->next;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
-	master_source_unlock(ap->entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	if (!me) {
Ian Kent 3685ec
 		/*
Ian Kent 3685ec
@@ -1144,10 +1146,28 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
Ian Kent 3685ec
 		 */
Ian Kent 3685ec
 		crit(ap->logopt, "can't find map entry for (%lu,%lu)",
Ian Kent 3685ec
 		    (unsigned long) pkt->dev, (unsigned long) pkt->ino);
Ian Kent 3685ec
+		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
+	/* Can't expire it if it isn't mounted */
Ian Kent 3685ec
+	if (me->ioctlfd == -1) {
Ian Kent 3685ec
+		int ioctlfd = open(me->key, O_RDONLY);
Ian Kent 3685ec
+		if (ioctlfd == -1) {
Ian Kent 3685ec
+			crit(ap->logopt, "can't open ioctlfd for %s",
Ian Kent 3685ec
+			     me->key);
Ian Kent 3685ec
+			pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
+			return 1;
Ian Kent 3685ec
+		}
Ian Kent 3685ec
+		send_ready(ap->logopt, ioctlfd, pkt->wait_queue_token);
Ian Kent 3685ec
+		close(ioctlfd);
Ian Kent 3685ec
+		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
+		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
+		return 0;
Ian Kent 3685ec
+	}
Ian Kent 3685ec
 
Ian Kent 3685ec
 	mt = malloc(sizeof(struct pending_args));
Ian Kent 3685ec
 	if (!mt) {
Ian Kent 3685ec
@@ -1155,6 +1175,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
Ian Kent 3685ec
 		error(ap->logopt, "malloc: %s", estr);
Ian Kent 3685ec
 		send_fail(ap->logopt, me->ioctlfd, pkt->wait_queue_token);
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
@@ -1184,6 +1205,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
Ian Kent 3685ec
 		error(ap->logopt, "expire thread create failed");
Ian Kent 3685ec
 		send_fail(ap->logopt, mt->ioctlfd, pkt->wait_queue_token);
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 		expire_mutex_unlock(NULL);
Ian Kent 3685ec
 		pending_cond_destroy(mt);
Ian Kent 3685ec
 		free_pending_args(mt);
Ian Kent 3685ec
@@ -1192,14 +1214,18 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
 	cache_unlock(mc);
Ian Kent 3685ec
+	master_source_unlock(ap->entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	pthread_cleanup_push(expire_mutex_unlock, NULL);
Ian Kent 3685ec
 	pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	mt->signaled = 0;
Ian Kent 3685ec
 	while (!mt->signaled) {
Ian Kent 3685ec
+		gettimeofday(&now, NULL);
Ian Kent 3685ec
+		wait.tv_sec = now.tv_sec + 2;
Ian Kent 3685ec
+		wait.tv_nsec = now.tv_usec * 1000;
Ian Kent 3685ec
 		status = pthread_cond_wait(&mt->cond, &ea_mutex);
Ian Kent 3685ec
-		if (status)
Ian Kent 3685ec
+		if (status && status != ETIMEDOUT)
Ian Kent 3685ec
 			fatal(status);
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -1263,6 +1289,9 @@ static void *do_mount_direct(void *arg)
Ian Kent 3685ec
 	if (status == -1) {
Ian Kent 3685ec
 		error(ap->logopt,
Ian Kent 3685ec
 		      "can't stat direct mount trigger %s", mt.name);
Ian Kent 3685ec
+		send_fail(ap->logopt,
Ian Kent 3685ec
+			  mt.ioctlfd, mt.wait_queue_token);
Ian Kent 3685ec
+		close(mt.ioctlfd);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		pthread_exit(NULL);
Ian Kent 3685ec
 	}
Ian Kent 3685ec
@@ -1272,6 +1301,8 @@ static void *do_mount_direct(void *arg)
Ian Kent 3685ec
 		error(ap->logopt,
Ian Kent 3685ec
 		     "direct trigger not valid or already mounted %s",
Ian Kent 3685ec
 		     mt.name);
Ian Kent 3685ec
+		send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
Ian Kent 3685ec
+		close(mt.ioctlfd);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		pthread_exit(NULL);
Ian Kent 3685ec
 	}
Ian Kent 3685ec
@@ -1290,19 +1321,12 @@ static void *do_mount_direct(void *arg)
Ian Kent 3685ec
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Ian Kent 3685ec
 	if (status) {
Ian Kent 3685ec
 		struct mapent *me;
Ian Kent 3685ec
-		int real_mount, set_fd;
Ian Kent 3685ec
-		cache_readlock(mt.mc);
Ian Kent 3685ec
+		cache_writelock(mt.mc);
Ian Kent 3685ec
 		me = cache_lookup_distinct(mt.mc, mt.name);
Ian Kent 3685ec
-		real_mount = is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL);
Ian Kent 3685ec
-		set_fd = (real_mount || me->multi == me);
Ian Kent 3685ec
-		cache_unlock(mt.mc);
Ian Kent 3685ec
-		if (set_fd) {
Ian Kent 3685ec
+		if (me)
Ian Kent 3685ec
 			me->ioctlfd = mt.ioctlfd;
Ian Kent 3685ec
-			send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
Ian Kent 3685ec
-		} else {
Ian Kent 3685ec
-			send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
Ian Kent 3685ec
-			close(mt.ioctlfd);
Ian Kent 3685ec
-		}
Ian Kent 3685ec
+		send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
Ian Kent 3685ec
+		cache_unlock(mt.mc);
Ian Kent 3685ec
 		info(ap->logopt, "mounted %s", mt.name);
Ian Kent 3685ec
 	} else {
Ian Kent 3685ec
 		send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
Ian Kent 3685ec
@@ -1325,11 +1349,21 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 	struct pending_args *mt;
Ian Kent 3685ec
 	char buf[MAX_ERR_BUF];
Ian Kent 3685ec
 	int status = 0;
Ian Kent 3685ec
+	struct timespec wait;
Ian Kent 3685ec
+	struct timeval now;
Ian Kent 3685ec
 	int ioctlfd, len, cl_flags, state;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	master_source_readlock(ap->entry);
Ian Kent 3685ec
+	/*
Ian Kent 3685ec
+	 * If our parent is a direct or offset mount that has been
Ian Kent 3685ec
+	 * covered by a mount and another lookup occurs after the
Ian Kent 3685ec
+	 * mount but before the device and inode are set in the
Ian Kent 3685ec
+	 * cache entry we will not be able to find the mapent. So
Ian Kent 3685ec
+	 * we must take the source writelock to ensure the parent
Ian Kent 3685ec
+	 * has mount is complete before we look for the entry.
Ian Kent 3685ec
+	 */
Ian Kent 3685ec
+	master_source_writelock(ap->entry);
Ian Kent 3685ec
 	map = ap->entry->maps;
Ian Kent 3685ec
 	while (map) {
Ian Kent 3685ec
 		/*
Ian Kent 3685ec
@@ -1349,7 +1383,6 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
 		map = map->next;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
-	master_source_unlock(ap->entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	if (!me) {
Ian Kent 3685ec
 		/*
Ian Kent 3685ec
@@ -1358,6 +1391,8 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 		 */
Ian Kent 3685ec
 		logerr("can't find map entry for (%lu,%lu)",
Ian Kent 3685ec
 		    (unsigned long) pkt->dev, (unsigned long) pkt->ino);
Ian Kent 3685ec
+		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
@@ -1371,6 +1406,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 
Ian Kent 3685ec
 	if (ioctlfd == -1) {
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
Ian Kent 3685ec
 		/* TODO:  how do we clear wait q in kernel ?? */
Ian Kent 3685ec
@@ -1386,12 +1422,11 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 		  (unsigned long) pkt->wait_queue_token, me->key, pkt->pid);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	/* Ignore packet if we're trying to shut down */
Ian Kent 3685ec
-	if (ap->shutdown ||
Ian Kent 3685ec
-	    ap->state == ST_SHUTDOWN_FORCE ||
Ian Kent 3685ec
-	    ap->state == ST_SHUTDOWN) {
Ian Kent 3685ec
+	if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) {
Ian Kent 3685ec
 		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
Ian Kent 3685ec
 		close(ioctlfd);
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
@@ -1402,6 +1437,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
Ian Kent 3685ec
 		close(ioctlfd);
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
@@ -1413,6 +1449,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
Ian Kent 3685ec
 		close(ioctlfd);
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
@@ -1447,6 +1484,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 		send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token);
Ian Kent 3685ec
 		close(ioctlfd);
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 		mount_mutex_unlock(mt);
Ian Kent 3685ec
 		pending_cond_destroy(mt);
Ian Kent 3685ec
 		pending_mutex_destroy(mt);
Ian Kent 3685ec
@@ -1456,6 +1494,8 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
 	cache_unlock(mc);
Ian Kent 3685ec
+	master_source_unlock(ap->entry);
Ian Kent 3685ec
+
Ian Kent 3685ec
 	pthread_cleanup_push(free_pending_args, mt);
Ian Kent 3685ec
 	pthread_cleanup_push(pending_mutex_destroy, mt);
Ian Kent 3685ec
 	pthread_cleanup_push(pending_cond_destroy, mt);
Ian Kent 3685ec
@@ -1464,8 +1504,11 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 
Ian Kent 3685ec
 	mt->signaled = 0;
Ian Kent 3685ec
 	while (!mt->signaled) {
Ian Kent 3685ec
-		status = pthread_cond_wait(&mt->cond, &mt->mutex);
Ian Kent 3685ec
-		if (status)
Ian Kent 3685ec
+		gettimeofday(&now, NULL);
Ian Kent 3685ec
+		wait.tv_sec = now.tv_sec + 2;
Ian Kent 3685ec
+		wait.tv_nsec = now.tv_usec * 1000;
Ian Kent 3685ec
+		status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait);
Ian Kent 3685ec
+		if (status && status != ETIMEDOUT)
Ian Kent 3685ec
 			fatal(status);
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
diff --git a/daemon/indirect.c b/daemon/indirect.c
Ian Kent 3685ec
index 3922f3f..17bed3e 100644
Ian Kent 3685ec
--- a/daemon/indirect.c
Ian Kent 3685ec
+++ b/daemon/indirect.c
Ian Kent 3685ec
@@ -230,11 +230,8 @@ int mount_autofs_indirect(struct autofs_point *ap)
Ian Kent 3685ec
 	return 0;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
-int umount_autofs_indirect(struct autofs_point *ap)
Ian Kent 3685ec
+static void close_mount_fds(struct autofs_point *ap)
Ian Kent 3685ec
 {
Ian Kent 3685ec
-	char buf[MAX_ERR_BUF];
Ian Kent 3685ec
-	int ret, rv, retries;
Ian Kent 3685ec
-
Ian Kent 3685ec
 	/*
Ian Kent 3685ec
 	 * Since submounts look after themselves the parent never knows
Ian Kent 3685ec
 	 * it needs to close the ioctlfd for offset mounts so we have
Ian Kent 3685ec
@@ -244,6 +241,25 @@ int umount_autofs_indirect(struct autofs_point *ap)
Ian Kent 3685ec
 	if (ap->submount)
Ian Kent 3685ec
 		lookup_source_close_ioctlfd(ap->parent, ap->path);
Ian Kent 3685ec
 
Ian Kent 3685ec
+	close(ap->state_pipe[0]);
Ian Kent 3685ec
+	close(ap->state_pipe[1]);
Ian Kent 3685ec
+	ap->state_pipe[0] = -1;
Ian Kent 3685ec
+	ap->state_pipe[1] = -1;
Ian Kent 3685ec
+
Ian Kent 3685ec
+	if (ap->pipefd >= 0)
Ian Kent 3685ec
+		close(ap->pipefd);
Ian Kent 3685ec
+
Ian Kent 3685ec
+	if (ap->kpipefd >= 0)
Ian Kent 3685ec
+		close(ap->kpipefd);
Ian Kent 3685ec
+
Ian Kent 3685ec
+	return;
Ian Kent 3685ec
+}
Ian Kent 3685ec
+
Ian Kent 3685ec
+int umount_autofs_indirect(struct autofs_point *ap)
Ian Kent 3685ec
+{
Ian Kent 3685ec
+	char buf[MAX_ERR_BUF];
Ian Kent 3685ec
+	int ret, rv, retries;
Ian Kent 3685ec
+
Ian Kent 3685ec
 	/* If we are trying to shutdown make sure we can umount */
Ian Kent 3685ec
 	rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret;;
Ian Kent 3685ec
 	if (rv == -1) {
Ian Kent 3685ec
@@ -251,24 +267,20 @@ int umount_autofs_indirect(struct autofs_point *ap)
Ian Kent 3685ec
 		logerr("ioctl failed: %s", estr);
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	} else if (!ret) {
Ian Kent 3685ec
+#if defined(ENABLE_IGNORE_BUSY_MOUNTS) || defined(ENABLE_FORCED_SHUTDOWN)
Ian Kent 3685ec
+		if (!ap->shutdown)
Ian Kent 3685ec
+			return 1;
Ian Kent 3685ec
 		error(ap->logopt, "ask umount returned busy %s", ap->path);
Ian Kent 3685ec
+#else
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
+#endif
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
-	ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
Ian Kent 3685ec
+	if (ap->shutdown)
Ian Kent 3685ec
+		ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0);
Ian Kent 3685ec
+
Ian Kent 3685ec
 	close(ap->ioctlfd);
Ian Kent 3685ec
 	ap->ioctlfd = -1;
Ian Kent 3685ec
-	close(ap->state_pipe[0]);
Ian Kent 3685ec
-	close(ap->state_pipe[1]);
Ian Kent 3685ec
-	ap->state_pipe[0] = -1;
Ian Kent 3685ec
-	ap->state_pipe[1] = -1;
Ian Kent 3685ec
-
Ian Kent 3685ec
-	if (ap->pipefd >= 0)
Ian Kent 3685ec
-		close(ap->pipefd);
Ian Kent 3685ec
-
Ian Kent 3685ec
-	if (ap->kpipefd >= 0)
Ian Kent 3685ec
-		close(ap->kpipefd);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	sched_yield();
Ian Kent 3685ec
 
Ian Kent 3685ec
 	retries = UMOUNT_RETRIES;
Ian Kent 3685ec
@@ -285,24 +297,61 @@ int umount_autofs_indirect(struct autofs_point *ap)
Ian Kent 3685ec
 		case EINVAL:
Ian Kent 3685ec
 			error(ap->logopt,
Ian Kent 3685ec
 			      "mount point %s does not exist", ap->path);
Ian Kent 3685ec
+			close_mount_fds(ap);
Ian Kent 3685ec
 			return 0;
Ian Kent 3685ec
 			break;
Ian Kent 3685ec
 		case EBUSY:
Ian Kent 3685ec
-			error(ap->logopt,
Ian Kent 3685ec
+			debug(ap->logopt,
Ian Kent 3685ec
 			      "mount point %s is in use", ap->path);
Ian Kent 3685ec
-			if (ap->state == ST_SHUTDOWN_FORCE)
Ian Kent 3685ec
+			if (ap->state == ST_SHUTDOWN_FORCE) {
Ian Kent 3685ec
+				close_mount_fds(ap);
Ian Kent 3685ec
 				goto force_umount;
Ian Kent 3685ec
-			else
Ian Kent 3685ec
-				return 0;
Ian Kent 3685ec
+			} else {
Ian Kent 3685ec
+				int cl_flags;
Ian Kent 3685ec
+				/*
Ian Kent 3685ec
+				 * If the umount returns EBUSY there may be
Ian Kent 3685ec
+				 * a mount request in progress so we need to
Ian Kent 3685ec
+				 * recover unless we have been explicitly
Ian Kent 3685ec
+				 * asked to shutdown and configure option
Ian Kent 3685ec
+				 * ENABLE_IGNORE_BUSY_MOUNTS is enabled.
Ian Kent 3685ec
+				 */
Ian Kent 3685ec
+#ifdef ENABLE_IGNORE_BUSY_MOUNTS
Ian Kent 3685ec
+				if (ap->shutdown) {
Ian Kent 3685ec
+					close_mount_fds(ap);
Ian Kent 3685ec
+					return 0;
Ian Kent 3685ec
+				}
Ian Kent 3685ec
+#endif
Ian Kent 3685ec
+				ap->ioctlfd = open(ap->path, O_RDONLY);
Ian Kent 3685ec
+				if (ap->ioctlfd < 0) {
Ian Kent 3685ec
+					warn(ap->logopt,
Ian Kent 3685ec
+					     "could not recover autofs path %s",
Ian Kent 3685ec
+					     ap->path);
Ian Kent 3685ec
+					close_mount_fds(ap);
Ian Kent 3685ec
+					return 0;
Ian Kent 3685ec
+				}
Ian Kent 3685ec
+
Ian Kent 3685ec
+				if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) != -1) {
Ian Kent 3685ec
+					cl_flags |= FD_CLOEXEC;
Ian Kent 3685ec
+					fcntl(ap->ioctlfd, F_SETFD, cl_flags);
Ian Kent 3685ec
+				}
Ian Kent 3685ec
+			}
Ian Kent 3685ec
 			break;
Ian Kent 3685ec
 		case ENOTDIR:
Ian Kent 3685ec
 			error(ap->logopt, "mount point is not a directory");
Ian Kent 3685ec
+			close_mount_fds(ap);
Ian Kent 3685ec
 			return 0;
Ian Kent 3685ec
 			break;
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
+	/*
Ian Kent 3685ec
+	 * We have successfully umounted the mount so we now close
Ian Kent 3685ec
+	 * the descriptors. The kernel end of the kernel pipe will
Ian Kent 3685ec
+	 * have been put during the umount super block cleanup.
Ian Kent 3685ec
+	 */
Ian Kent 3685ec
+	close_mount_fds(ap);
Ian Kent 3685ec
+
Ian Kent 3685ec
 force_umount:
Ian Kent 3685ec
 	if (rv != 0) {
Ian Kent 3685ec
 		warn(ap->logopt,
Ian Kent 3685ec
@@ -439,9 +488,12 @@ void *expire_proc_indirect(void *arg)
Ian Kent 3685ec
 		 * Otherwise it's a top level indirect mount (possibly
Ian Kent 3685ec
 		 * with offsets in it) and we use the usual ioctlfd.
Ian Kent 3685ec
 		 */
Ian Kent 3685ec
+		pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
Ian Kent 3685ec
+		master_source_readlock(ap->entry);
Ian Kent 3685ec
 		me = lookup_source_mapent(ap, next->path, LKP_DISTINCT);
Ian Kent 3685ec
 		if (!me && ind_key)
Ian Kent 3685ec
 			me = lookup_source_mapent(ap, ind_key, LKP_NORMAL);
Ian Kent 3685ec
+		pthread_cleanup_pop(1);
Ian Kent 3685ec
 		if (!me)
Ian Kent 3685ec
 			continue;
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -586,6 +638,8 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_
Ian Kent 3685ec
 	struct pending_args *mt;
Ian Kent 3685ec
 	char buf[MAX_ERR_BUF];
Ian Kent 3685ec
 	pthread_t thid;
Ian Kent 3685ec
+	struct timespec wait;
Ian Kent 3685ec
+	struct timeval now;
Ian Kent 3685ec
 	int status, state;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Ian Kent 3685ec
@@ -632,8 +686,11 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_
Ian Kent 3685ec
 
Ian Kent 3685ec
 	mt->signaled = 0;
Ian Kent 3685ec
 	while (!mt->signaled) {
Ian Kent 3685ec
-		status = pthread_cond_wait(&mt->cond, &ea_mutex);
Ian Kent 3685ec
-		if (status)
Ian Kent 3685ec
+		gettimeofday(&now, NULL);
Ian Kent 3685ec
+		wait.tv_sec = now.tv_sec + 2;
Ian Kent 3685ec
+		wait.tv_nsec = now.tv_usec * 1000;
Ian Kent 3685ec
+		status = pthread_cond_timedwait(&mt->cond, &ea_mutex, &wait);
Ian Kent 3685ec
+		if (status && status != ETIMEDOUT)
Ian Kent 3685ec
 			fatal(status);
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -735,6 +792,8 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin
Ian Kent 3685ec
 	pthread_t thid;
Ian Kent 3685ec
 	char buf[MAX_ERR_BUF];
Ian Kent 3685ec
 	struct pending_args *mt;
Ian Kent 3685ec
+	struct timespec wait;
Ian Kent 3685ec
+	struct timeval now;
Ian Kent 3685ec
 	int status, state;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
Ian Kent 3685ec
@@ -743,9 +802,7 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin
Ian Kent 3685ec
 		(unsigned long) pkt->wait_queue_token, pkt->name, pkt->pid);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	/* Ignore packet if we're trying to shut down */
Ian Kent 3685ec
-	if (ap->shutdown ||
Ian Kent 3685ec
-	    ap->state == ST_SHUTDOWN_FORCE ||
Ian Kent 3685ec
-	    ap->state == ST_SHUTDOWN) {
Ian Kent 3685ec
+	if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) {
Ian Kent 3685ec
 		send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token);
Ian Kent 3685ec
 		pthread_setcancelstate(state, NULL);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
@@ -802,8 +859,11 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin
Ian Kent 3685ec
 
Ian Kent 3685ec
 	mt->signaled = 0;
Ian Kent 3685ec
 	while (!mt->signaled) {
Ian Kent 3685ec
-		status = pthread_cond_wait(&mt->cond, &mt->mutex);
Ian Kent 3685ec
-		if (status)
Ian Kent 3685ec
+		gettimeofday(&now, NULL);
Ian Kent 3685ec
+		wait.tv_sec = now.tv_sec + 2;
Ian Kent 3685ec
+		wait.tv_nsec = now.tv_usec * 1000;
Ian Kent 3685ec
+		status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait);
Ian Kent 3685ec
+		if (status && status != ETIMEDOUT)
Ian Kent 3685ec
 			fatal(status);
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
diff --git a/daemon/lookup.c b/daemon/lookup.c
Ian Kent 3685ec
index 2277623..85ac519 100644
Ian Kent 3685ec
--- a/daemon/lookup.c
Ian Kent 3685ec
+++ b/daemon/lookup.c
Ian Kent 3685ec
@@ -935,16 +935,10 @@ void lookup_close_lookup(struct autofs_point *ap)
Ian Kent 3685ec
 	if (!map)
Ian Kent 3685ec
 		return;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	/*
Ian Kent 3685ec
-	 * Make sure we don't kill the context if a mount
Ian Kent 3685ec
-	 * request has come in while were shutting down.
Ian Kent 3685ec
-	 */
Ian Kent 3685ec
-	master_source_writelock(ap->entry);
Ian Kent 3685ec
 	while (map) {
Ian Kent 3685ec
 		lookup_close_lookup_instances(map);
Ian Kent 3685ec
 		map = map->next;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
-	master_source_unlock(ap->entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -1122,7 +1116,6 @@ struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, un
Ian Kent 3685ec
 	struct mapent_cache *mc;
Ian Kent 3685ec
 	struct mapent *me = NULL;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	master_source_readlock(entry);
Ian Kent 3685ec
 	map = entry->maps;
Ian Kent 3685ec
 	while (map) {
Ian Kent 3685ec
 		mc = map->mc;
Ian Kent 3685ec
@@ -1136,7 +1129,6 @@ struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, un
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
 		map = map->next;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
-	master_source_unlock(entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return me;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -1149,8 +1141,6 @@ int lookup_source_close_ioctlfd(struct autofs_point *ap, const char *key)
Ian Kent 3685ec
 	struct mapent *me;
Ian Kent 3685ec
 	int ret = 0;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	pthread_cleanup_push(master_source_lock_cleanup, entry);
Ian Kent 3685ec
-	master_source_readlock(entry);
Ian Kent 3685ec
 	map = entry->maps;
Ian Kent 3685ec
 	while (map) {
Ian Kent 3685ec
 		mc = map->mc;
Ian Kent 3685ec
@@ -1168,7 +1158,6 @@ int lookup_source_close_ioctlfd(struct autofs_point *ap, const char *key)
Ian Kent 3685ec
 		cache_unlock(mc);
Ian Kent 3685ec
 		map = map->next;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
-	pthread_cleanup_pop(1);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return ret;
Ian Kent 3685ec
 }
Ian Kent 3685ec
diff --git a/daemon/state.c b/daemon/state.c
Ian Kent 3685ec
index 5804707..122177c 100644
Ian Kent 3685ec
--- a/daemon/state.c
Ian Kent 3685ec
+++ b/daemon/state.c
Ian Kent 3685ec
@@ -37,19 +37,19 @@ static LIST_HEAD(state_queue);
Ian Kent 3685ec
 static void st_set_thid(struct autofs_point *, pthread_t);
Ian Kent 3685ec
 static void st_set_done(struct autofs_point *ap);
Ian Kent 3685ec
 
Ian Kent 3685ec
-#define st_mutex_lock() \
Ian Kent 3685ec
-do { \
Ian Kent 3685ec
-	int status = pthread_mutex_lock(&mutex); \
Ian Kent 3685ec
-	if (status) \
Ian Kent 3685ec
-		fatal(status); \
Ian Kent 3685ec
-} while (0)
Ian Kent 3685ec
-
Ian Kent 3685ec
-#define st_mutex_unlock() \
Ian Kent 3685ec
-do { \
Ian Kent 3685ec
-	int status = pthread_mutex_unlock(&mutex); \
Ian Kent 3685ec
-	if (status) \
Ian Kent 3685ec
-		fatal(status); \
Ian Kent 3685ec
-} while (0)
Ian Kent 3685ec
+void st_mutex_lock(void)
Ian Kent 3685ec
+{
Ian Kent 3685ec
+	int status = pthread_mutex_lock(&mutex);
Ian Kent 3685ec
+	if (status)
Ian Kent 3685ec
+		fatal(status);
Ian Kent 3685ec
+}
Ian Kent 3685ec
+
Ian Kent 3685ec
+void st_mutex_unlock(void)
Ian Kent 3685ec
+{
Ian Kent 3685ec
+	int status = pthread_mutex_unlock(&mutex);
Ian Kent 3685ec
+	if (status)
Ian Kent 3685ec
+		fatal(status);
Ian Kent 3685ec
+}
Ian Kent 3685ec
 
Ian Kent 3685ec
 int do_mount_autofs_direct(struct autofs_point *, struct mnt_list *, struct mapent *);
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -96,21 +96,19 @@ void expire_cleanup(void *arg)
Ian Kent 3685ec
 	pthread_t thid = pthread_self();
Ian Kent 3685ec
 	struct expire_args *ec;
Ian Kent 3685ec
 	struct autofs_point *ap;
Ian Kent 3685ec
-	int statefd, success;
Ian Kent 3685ec
+	int success;
Ian Kent 3685ec
 	enum states next = ST_INVAL;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	ec = (struct expire_args *) arg;
Ian Kent 3685ec
 	ap = ec->ap;
Ian Kent 3685ec
 	success = ec->status;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	state_mutex_lock(ap);
Ian Kent 3685ec
+	st_mutex_lock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 	debug(ap->logopt,
Ian Kent 3685ec
 	      "got thid %lu path %s stat %d",
Ian Kent 3685ec
 	      (unsigned long) thid, ap->path, success);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	statefd = ap->state_pipe[1];
Ian Kent 3685ec
-
Ian Kent 3685ec
 	/* Check to see if expire process finished */
Ian Kent 3685ec
 	if (thid == ap->exp_thread) {
Ian Kent 3685ec
 		int rv, idle;
Ian Kent 3685ec
@@ -199,11 +197,11 @@ void expire_cleanup(void *arg)
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
 	if (next != ST_INVAL)
Ian Kent 3685ec
-		nextstate(statefd, next);
Ian Kent 3685ec
+		__st_add_task(ap, next);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	st_set_done(ap);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	state_mutex_unlock(ap);
Ian Kent 3685ec
+	st_mutex_unlock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -216,9 +214,6 @@ static unsigned int st_ready(struct autofs_point *ap)
Ian Kent 3685ec
 	ap->shutdown = 0;
Ian Kent 3685ec
 	ap->state = ST_READY;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	if (ap->submount)
Ian Kent 3685ec
-		master_signal_submount(ap, MASTER_SUBMNT_CONTINUE);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	return 1;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -333,18 +328,18 @@ static void do_readmap_cleanup(void *arg)
Ian Kent 3685ec
 	ra = (struct readmap_args *) arg;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	ap = ra->ap;
Ian Kent 3685ec
-	ap->readmap_thread = 0;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	state_mutex_lock(ap);
Ian Kent 3685ec
+	st_mutex_lock();
Ian Kent 3685ec
 
Ian Kent 3685ec
-	nextstate(ap->state_pipe[1], ST_READY);
Ian Kent 3685ec
+	ap->readmap_thread = 0;
Ian Kent 3685ec
+	st_ready(ap);
Ian Kent 3685ec
 	st_set_done(ap);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	state_mutex_unlock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	if (!ap->submount)
Ian Kent 3685ec
 		alarm_add(ap, ap->exp_runfreq);
Ian Kent 3685ec
 
Ian Kent 3685ec
+	st_mutex_unlock();
Ian Kent 3685ec
+
Ian Kent 3685ec
 	free(ra);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return;
Ian Kent 3685ec
@@ -499,10 +494,8 @@ static unsigned int st_readmap(struct autofs_point *ap)
Ian Kent 3685ec
 	ra = malloc(sizeof(struct readmap_args));
Ian Kent 3685ec
 	if (!ra) {
Ian Kent 3685ec
 		error(ap->logopt, "failed to malloc reamap cond struct");
Ian Kent 3685ec
-		state_mutex_lock(ap);
Ian Kent 3685ec
-		nextstate(ap->state_pipe[1], ST_READY);
Ian Kent 3685ec
-		state_mutex_unlock(ap);
Ian Kent 3685ec
 		/* It didn't work: return to ready */
Ian Kent 3685ec
+		st_ready(ap);
Ian Kent 3685ec
 		if (!ap->submount)
Ian Kent 3685ec
 			alarm_add(ap, ap->exp_runfreq);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
@@ -528,10 +521,8 @@ static unsigned int st_readmap(struct autofs_point *ap)
Ian Kent 3685ec
 		error(ap->logopt, "read map thread create failed");
Ian Kent 3685ec
 		st_readmap_cleanup(ra);
Ian Kent 3685ec
 		free(ra);
Ian Kent 3685ec
-		state_mutex_lock(ap);
Ian Kent 3685ec
-		nextstate(ap->state_pipe[1], ST_READY);
Ian Kent 3685ec
-		state_mutex_unlock(ap);
Ian Kent 3685ec
 		/* It didn't work: return to ready */
Ian Kent 3685ec
+		st_ready(ap);
Ian Kent 3685ec
 		if (!ap->submount)
Ian Kent 3685ec
 			alarm_add(ap, ap->exp_runfreq);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
@@ -570,7 +561,7 @@ static unsigned int st_prepare_shutdown(struct autofs_point *ap)
Ian Kent 3685ec
 		/* It didn't work: return to ready */
Ian Kent 3685ec
 		if (!ap->submount)
Ian Kent 3685ec
 			alarm_add(ap, ap->exp_runfreq);
Ian Kent 3685ec
-		nextstate(ap->state_pipe[1], ST_READY);
Ian Kent 3685ec
+		st_ready(ap);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	case EXP_STARTED:
Ian Kent 3685ec
@@ -596,7 +587,7 @@ static unsigned int st_force_shutdown(struct autofs_point *ap)
Ian Kent 3685ec
 		/* It didn't work: return to ready */
Ian Kent 3685ec
 		if (!ap->submount)
Ian Kent 3685ec
 			alarm_add(ap, ap->exp_runfreq);
Ian Kent 3685ec
-		nextstate(ap->state_pipe[1], ST_READY);
Ian Kent 3685ec
+		st_ready(ap);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	case EXP_STARTED:
Ian Kent 3685ec
@@ -605,6 +596,18 @@ static unsigned int st_force_shutdown(struct autofs_point *ap)
Ian Kent 3685ec
 	return 0;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
+static unsigned int st_shutdown(struct autofs_point *ap)
Ian Kent 3685ec
+{
Ian Kent 3685ec
+	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
Ian Kent 3685ec
+
Ian Kent 3685ec
+	assert(ap->state == ST_SHUTDOWN_PENDING || ap->state == ST_SHUTDOWN_FORCE);
Ian Kent 3685ec
+
Ian Kent 3685ec
+	ap->state = ST_SHUTDOWN;
Ian Kent 3685ec
+	nextstate(ap->state_pipe[1], ST_SHUTDOWN);
Ian Kent 3685ec
+
Ian Kent 3685ec
+	return 0;
Ian Kent 3685ec
+}
Ian Kent 3685ec
+
Ian Kent 3685ec
 static unsigned int st_prune(struct autofs_point *ap)
Ian Kent 3685ec
 {
Ian Kent 3685ec
 	debug(ap->logopt, "state %d path %s", ap->state, ap->path);
Ian Kent 3685ec
@@ -617,7 +620,7 @@ static unsigned int st_prune(struct autofs_point *ap)
Ian Kent 3685ec
 	case EXP_PARTIAL:
Ian Kent 3685ec
 		if (!ap->submount)
Ian Kent 3685ec
 			alarm_add(ap, ap->exp_runfreq);
Ian Kent 3685ec
-		nextstate(ap->state_pipe[1], ST_READY);
Ian Kent 3685ec
+		st_ready(ap);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	case EXP_STARTED:
Ian Kent 3685ec
@@ -638,7 +641,7 @@ static unsigned int st_expire(struct autofs_point *ap)
Ian Kent 3685ec
 	case EXP_PARTIAL:
Ian Kent 3685ec
 		if (!ap->submount)
Ian Kent 3685ec
 			alarm_add(ap, ap->exp_runfreq);
Ian Kent 3685ec
-		nextstate(ap->state_pipe[1], ST_READY);
Ian Kent 3685ec
+		st_ready(ap);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	case EXP_STARTED:
Ian Kent 3685ec
@@ -665,43 +668,35 @@ static struct state_queue *st_alloc_task(struct autofs_point *ap, enum states st
Ian Kent 3685ec
 	return task;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
-/* Insert alarm entry on ordered list. */
Ian Kent 3685ec
-int st_add_task(struct autofs_point *ap, enum states state)
Ian Kent 3685ec
+/*
Ian Kent 3685ec
+ * Insert alarm entry on ordered list.
Ian Kent 3685ec
+ * State queue mutex and ap state mutex, in that order, must be held.
Ian Kent 3685ec
+ */
Ian Kent 3685ec
+int __st_add_task(struct autofs_point *ap, enum states state)
Ian Kent 3685ec
 {
Ian Kent 3685ec
 	struct list_head *head;
Ian Kent 3685ec
 	struct list_head *p, *q;
Ian Kent 3685ec
 	struct state_queue *new;
Ian Kent 3685ec
-	enum states ap_state;
Ian Kent 3685ec
 	unsigned int empty = 1;
Ian Kent 3685ec
 	int status;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	/* Task termination marker, poke state machine */
Ian Kent 3685ec
 	if (state == ST_READY) {
Ian Kent 3685ec
-		state_mutex_lock(ap);
Ian Kent 3685ec
 		st_ready(ap);
Ian Kent 3685ec
-		state_mutex_unlock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
-		st_mutex_lock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 		signaled = 1;
Ian Kent 3685ec
 		status = pthread_cond_signal(&cond;;
Ian Kent 3685ec
 		if (status)
Ian Kent 3685ec
 			fatal(status);
Ian Kent 3685ec
 
Ian Kent 3685ec
-		st_mutex_unlock();
Ian Kent 3685ec
-
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
-	state_mutex_lock(ap);
Ian Kent 3685ec
-	ap_state = ap->state;
Ian Kent 3685ec
-	if (ap_state == ST_SHUTDOWN) {
Ian Kent 3685ec
-		state_mutex_unlock(ap);
Ian Kent 3685ec
+	if (ap->state == ST_SHUTDOWN)
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
-	}
Ian Kent 3685ec
-	state_mutex_unlock(ap);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	st_mutex_lock();
Ian Kent 3685ec
+	if (state == ST_SHUTDOWN)
Ian Kent 3685ec
+		return st_shutdown(ap);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	head = &state_queue;
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -718,8 +713,8 @@ int st_add_task(struct autofs_point *ap, enum states state)
Ian Kent 3685ec
 
Ian Kent 3685ec
 		/* Don't add duplicate tasks */
Ian Kent 3685ec
 		if ((task->state == state && !task->done) ||
Ian Kent 3685ec
-		   (ap_state == ST_SHUTDOWN_PENDING ||
Ian Kent 3685ec
-		    ap_state == ST_SHUTDOWN_FORCE))
Ian Kent 3685ec
+		   (ap->state == ST_SHUTDOWN_PENDING ||
Ian Kent 3685ec
+		    ap->state == ST_SHUTDOWN_FORCE))
Ian Kent 3685ec
 			break;
Ian Kent 3685ec
 
Ian Kent 3685ec
 		/* No pending tasks */
Ian Kent 3685ec
@@ -736,8 +731,8 @@ int st_add_task(struct autofs_point *ap, enum states state)
Ian Kent 3685ec
 			p_task = list_entry(q, struct state_queue, pending);
Ian Kent 3685ec
 
Ian Kent 3685ec
 			if (p_task->state == state ||
Ian Kent 3685ec
-			   (ap_state == ST_SHUTDOWN_PENDING ||
Ian Kent 3685ec
-			    ap_state == ST_SHUTDOWN_FORCE))
Ian Kent 3685ec
+			   (ap->state == ST_SHUTDOWN_PENDING ||
Ian Kent 3685ec
+			    ap->state == ST_SHUTDOWN_FORCE))
Ian Kent 3685ec
 				goto done;
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -760,11 +755,24 @@ done:
Ian Kent 3685ec
 	if (status)
Ian Kent 3685ec
 		fatal(status);
Ian Kent 3685ec
 
Ian Kent 3685ec
+	return 1;
Ian Kent 3685ec
+}
Ian Kent 3685ec
+
Ian Kent 3685ec
+int st_add_task(struct autofs_point *ap, enum states state)
Ian Kent 3685ec
+{
Ian Kent 3685ec
+	int ret;
Ian Kent 3685ec
+
Ian Kent 3685ec
+	st_mutex_lock();
Ian Kent 3685ec
+	ret = __st_add_task(ap, state);
Ian Kent 3685ec
 	st_mutex_unlock();
Ian Kent 3685ec
 
Ian Kent 3685ec
-	return 1;
Ian Kent 3685ec
+	return ret;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
+/*
Ian Kent 3685ec
+ * Remove state queue tasks for ap.
Ian Kent 3685ec
+ * State queue mutex and ap state mutex, in that order, must be held.
Ian Kent 3685ec
+ */
Ian Kent 3685ec
 void st_remove_tasks(struct autofs_point *ap)
Ian Kent 3685ec
 {
Ian Kent 3685ec
 	struct list_head *head;
Ian Kent 3685ec
@@ -772,14 +780,10 @@ void st_remove_tasks(struct autofs_point *ap)
Ian Kent 3685ec
 	struct state_queue *task, *waiting;
Ian Kent 3685ec
 	int status;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	st_mutex_lock();
Ian Kent 3685ec
-
Ian Kent 3685ec
 	head = &state_queue;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	if (list_empty(head)) {
Ian Kent 3685ec
-		st_mutex_unlock();
Ian Kent 3685ec
+	if (list_empty(head))
Ian Kent 3685ec
 		return;
Ian Kent 3685ec
-	}
Ian Kent 3685ec
 
Ian Kent 3685ec
 	p = head->next;
Ian Kent 3685ec
 	while (p != head) {
Ian Kent 3685ec
@@ -816,12 +820,107 @@ void st_remove_tasks(struct autofs_point *ap)
Ian Kent 3685ec
 	if (status)
Ian Kent 3685ec
 		fatal(status);
Ian Kent 3685ec
 
Ian Kent 3685ec
+	return;
Ian Kent 3685ec
+}
Ian Kent 3685ec
+
Ian Kent 3685ec
+static int st_task_active(struct autofs_point *ap, enum states state)
Ian Kent 3685ec
+{
Ian Kent 3685ec
+	struct list_head *head;
Ian Kent 3685ec
+	struct list_head *p, *q;
Ian Kent 3685ec
+	struct state_queue *task, *waiting;
Ian Kent 3685ec
+	unsigned int active = 0;
Ian Kent 3685ec
+
Ian Kent 3685ec
+	st_mutex_lock();
Ian Kent 3685ec
+
Ian Kent 3685ec
+	head = &state_queue;
Ian Kent 3685ec
+
Ian Kent 3685ec
+	list_for_each(p, head) {
Ian Kent 3685ec
+		task = list_entry(p, struct state_queue, list);
Ian Kent 3685ec
+
Ian Kent 3685ec
+		if (task->ap != ap)
Ian Kent 3685ec
+			continue;
Ian Kent 3685ec
+
Ian Kent 3685ec
+		if (task->state == state) {
Ian Kent 3685ec
+			active = 1;
Ian Kent 3685ec
+			break;
Ian Kent 3685ec
+		}
Ian Kent 3685ec
+
Ian Kent 3685ec
+		if (state == ST_ANY) {
Ian Kent 3685ec
+			active = 1;
Ian Kent 3685ec
+			break;
Ian Kent 3685ec
+		}
Ian Kent 3685ec
+
Ian Kent 3685ec
+		list_for_each(q, &task->pending) {
Ian Kent 3685ec
+			waiting = list_entry(q, struct state_queue, pending);
Ian Kent 3685ec
+
Ian Kent 3685ec
+			if (waiting->state == state) {
Ian Kent 3685ec
+				active = 1;
Ian Kent 3685ec
+				break;
Ian Kent 3685ec
+			}
Ian Kent 3685ec
+
Ian Kent 3685ec
+			if (state == ST_ANY) {
Ian Kent 3685ec
+				active = 1;
Ian Kent 3685ec
+				break;
Ian Kent 3685ec
+			}
Ian Kent 3685ec
+		}
Ian Kent 3685ec
+	}
Ian Kent 3685ec
+
Ian Kent 3685ec
 	st_mutex_unlock();
Ian Kent 3685ec
 
Ian Kent 3685ec
-	return;
Ian Kent 3685ec
+	return active;
Ian Kent 3685ec
+}
Ian Kent 3685ec
+
Ian Kent 3685ec
+int st_wait_task(struct autofs_point *ap, enum states state, unsigned int seconds)
Ian Kent 3685ec
+{
Ian Kent 3685ec
+	unsigned int wait = 0;
Ian Kent 3685ec
+	unsigned int duration = 0;
Ian Kent 3685ec
+	int ret = 0;
Ian Kent 3685ec
 
Ian Kent 3685ec
+	while (1) {
Ian Kent 3685ec
+		struct timespec t = { 0, 200000000 };
Ian Kent 3685ec
+		struct timespec r;
Ian Kent 3685ec
+
Ian Kent 3685ec
+		while (nanosleep(&t, &r) == -1 && errno == EINTR)
Ian Kent 3685ec
+			memcpy(&t, &r, sizeof(struct timespec));
Ian Kent 3685ec
+
Ian Kent 3685ec
+		if (wait++ == 4) {
Ian Kent 3685ec
+			wait = 0;
Ian Kent 3685ec
+			duration++;
Ian Kent 3685ec
+		}
Ian Kent 3685ec
+
Ian Kent 3685ec
+		if (!st_task_active(ap, state)) {
Ian Kent 3685ec
+			ret = 1;
Ian Kent 3685ec
+			break;
Ian Kent 3685ec
+		}
Ian Kent 3685ec
+
Ian Kent 3685ec
+		if (seconds && duration >= seconds)
Ian Kent 3685ec
+			break;
Ian Kent 3685ec
+	}
Ian Kent 3685ec
+
Ian Kent 3685ec
+	return ret;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
+int st_wait_state(struct autofs_point *ap, enum states state)
Ian Kent 3685ec
+{
Ian Kent 3685ec
+	while (1) {
Ian Kent 3685ec
+		struct timespec t = { 0, 200000000 };
Ian Kent 3685ec
+		struct timespec r;
Ian Kent 3685ec
+
Ian Kent 3685ec
+		while (nanosleep(&t, &r) == -1 && errno == EINTR)
Ian Kent 3685ec
+			memcpy(&t, &r, sizeof(struct timespec));
Ian Kent 3685ec
+
Ian Kent 3685ec
+		st_mutex_lock();
Ian Kent 3685ec
+		if (ap->state == state) {
Ian Kent 3685ec
+			st_mutex_unlock();
Ian Kent 3685ec
+			return 1;
Ian Kent 3685ec
+		}
Ian Kent 3685ec
+		st_mutex_unlock();
Ian Kent 3685ec
+	}
Ian Kent 3685ec
+
Ian Kent 3685ec
+	return 0;
Ian Kent 3685ec
+}
Ian Kent 3685ec
+
Ian Kent 3685ec
+
Ian Kent 3685ec
 static int run_state_task(struct state_queue *task)
Ian Kent 3685ec
 {
Ian Kent 3685ec
 	struct autofs_point *ap;
Ian Kent 3685ec
@@ -831,8 +930,6 @@ static int run_state_task(struct state_queue *task)
Ian Kent 3685ec
 	ap = task->ap;
Ian Kent 3685ec
 	next_state = task->state;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	state_mutex_lock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	state = ap->state;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	if (next_state != state) {
Ian Kent 3685ec
@@ -862,8 +959,6 @@ static int run_state_task(struct state_queue *task)
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
-	state_mutex_unlock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	return ret;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -888,8 +983,6 @@ static void st_set_done(struct autofs_point *ap)
Ian Kent 3685ec
 	struct list_head *p, *head;
Ian Kent 3685ec
 	struct state_queue *task;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	st_mutex_lock();
Ian Kent 3685ec
-
Ian Kent 3685ec
 	head = &state_queue;
Ian Kent 3685ec
 	list_for_each(p, head) {
Ian Kent 3685ec
 		task = list_entry(p, struct state_queue, list);
Ian Kent 3685ec
@@ -899,8 +992,6 @@ static void st_set_done(struct autofs_point *ap)
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
-	st_mutex_unlock();
Ian Kent 3685ec
-
Ian Kent 3685ec
 	return;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
diff --git a/include/automount.h b/include/automount.h
Ian Kent 3685ec
index 1a20cd9..8ff24a7 100644
Ian Kent 3685ec
--- a/include/automount.h
Ian Kent 3685ec
+++ b/include/automount.h
Ian Kent 3685ec
@@ -399,7 +399,6 @@ struct autofs_point {
Ian Kent 3685ec
 	unsigned logopt;		/* Per map logging */
Ian Kent 3685ec
 	pthread_t exp_thread;		/* Thread that is expiring */
Ian Kent 3685ec
 	pthread_t readmap_thread;	/* Thread that is reading maps */
Ian Kent 3685ec
-	pthread_mutex_t state_mutex;	/* Protect state changes */
Ian Kent 3685ec
 	enum states state;		/* Current state */
Ian Kent 3685ec
 	int state_pipe[2];		/* State change router pipe */
Ian Kent 3685ec
 	unsigned dir_created;		/* Directory created for this mount? */
Ian Kent 3685ec
@@ -407,8 +406,6 @@ struct autofs_point {
Ian Kent 3685ec
 					 * host from which to mount */
Ian Kent 3685ec
 	struct autofs_point *parent;	/* Owner of mounts list for submount */
Ian Kent 3685ec
 	pthread_mutex_t mounts_mutex;	/* Protect mount lists */
Ian Kent 3685ec
-	pthread_cond_t mounts_cond;	/* Submounts condition variable */
Ian Kent 3685ec
-	unsigned int mounts_signaled;	/* Submount signals task complete */
Ian Kent 3685ec
 	struct list_head mounts;	/* List of autofs mounts at current level */
Ian Kent 3685ec
 	unsigned int submount;		/* Is this a submount */
Ian Kent 3685ec
 	unsigned int shutdown;		/* Shutdown notification */
Ian Kent 3685ec
@@ -446,20 +443,6 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_
Ian Kent 3685ec
 void rm_unwanted(unsigned logopt, const char *path, int incl, dev_t dev);
Ian Kent 3685ec
 int count_mounts(unsigned logopt, const char *path, dev_t dev);
Ian Kent 3685ec
 
Ian Kent 3685ec
-#define state_mutex_lock(ap) \
Ian Kent 3685ec
-do { \
Ian Kent 3685ec
-	int _st_lock = pthread_mutex_lock(&ap->state_mutex); \
Ian Kent 3685ec
-	if (_st_lock) \
Ian Kent 3685ec
-		fatal(_st_lock); \
Ian Kent 3685ec
-} while(0)
Ian Kent 3685ec
-
Ian Kent 3685ec
-#define state_mutex_unlock(ap) \
Ian Kent 3685ec
-do{ \
Ian Kent 3685ec
-	int _st_unlock = pthread_mutex_unlock(&ap->state_mutex); \
Ian Kent 3685ec
-	if (_st_unlock) \
Ian Kent 3685ec
-		fatal(_st_unlock); \
Ian Kent 3685ec
-} while (0)
Ian Kent 3685ec
-
Ian Kent 3685ec
 #define mounts_mutex_lock(ap) \
Ian Kent 3685ec
 do { \
Ian Kent 3685ec
 	int _m_lock = pthread_mutex_lock(&ap->mounts_mutex); \
Ian Kent 3685ec
diff --git a/include/master.h b/include/master.h
Ian Kent 3685ec
index 5f10d1f..86ae045 100644
Ian Kent 3685ec
--- a/include/master.h
Ian Kent 3685ec
+++ b/include/master.h
Ian Kent 3685ec
@@ -20,10 +20,6 @@
Ian Kent 3685ec
 #ifndef MASTER_H
Ian Kent 3685ec
 #define MASTER_H
Ian Kent 3685ec
 
Ian Kent 3685ec
-#define MASTER_SUBMNT_WAIT	0
Ian Kent 3685ec
-#define MASTER_SUBMNT_CONTINUE	1
Ian Kent 3685ec
-#define MASTER_SUBMNT_JOIN	2
Ian Kent 3685ec
-
Ian Kent 3685ec
 struct map_source {
Ian Kent 3685ec
 	char *type;
Ian Kent 3685ec
 	char *format;
Ian Kent 3685ec
@@ -104,7 +100,6 @@ struct master *master_new(const char *, unsigned int, unsigned int);
Ian Kent 3685ec
 int master_read_master(struct master *, time_t, int);
Ian Kent 3685ec
 int master_submount_list_empty(struct autofs_point *ap);
Ian Kent 3685ec
 int master_notify_submount(struct autofs_point *, const char *path, enum states);
Ian Kent 3685ec
-void master_signal_submount(struct autofs_point *, unsigned int);
Ian Kent 3685ec
 void master_notify_state_change(struct master *, int);
Ian Kent 3685ec
 int master_mount_mounts(struct master *, time_t, int);
Ian Kent 3685ec
 extern inline unsigned int master_get_logopt(void);
Ian Kent 3685ec
diff --git a/include/state.h b/include/state.h
Ian Kent 3685ec
index 8aed234..d7349d9 100644
Ian Kent 3685ec
--- a/include/state.h
Ian Kent 3685ec
+++ b/include/state.h
Ian Kent 3685ec
@@ -38,7 +38,8 @@
Ian Kent 3685ec
  *
Ian Kent 3685ec
  */
Ian Kent 3685ec
 enum states {
Ian Kent 3685ec
-	ST_INVAL = -1,
Ian Kent 3685ec
+	ST_ANY = -2,
Ian Kent 3685ec
+	ST_INVAL,
Ian Kent 3685ec
 	ST_INIT,
Ian Kent 3685ec
 	ST_READY,
Ian Kent 3685ec
 	ST_EXPIRE,
Ian Kent 3685ec
@@ -81,12 +82,18 @@ struct readmap_args {
Ian Kent 3685ec
 	time_t now;              /* Time when map is read */
Ian Kent 3685ec
 };
Ian Kent 3685ec
 
Ian Kent 3685ec
+void st_mutex_lock(void);
Ian Kent 3685ec
+void st_mutex_unlock(void);
Ian Kent 3685ec
+
Ian Kent 3685ec
 void expire_cleanup(void *);
Ian Kent 3685ec
 void expire_proc_cleanup(void *);
Ian Kent 3685ec
 void nextstate(int, enum states);
Ian Kent 3685ec
 
Ian Kent 3685ec
 int st_add_task(struct autofs_point *, enum states);
Ian Kent 3685ec
+int __st_add_task(struct autofs_point *, enum states);
Ian Kent 3685ec
 void st_remove_tasks(struct autofs_point *);
Ian Kent 3685ec
+int st_wait_task(struct autofs_point *, enum states, unsigned int);
Ian Kent 3685ec
+int st_wait_state(struct autofs_point *ap, enum states state);
Ian Kent 3685ec
 int st_start_handler(void);
Ian Kent 3685ec
 
Ian Kent 3685ec
 #endif
Ian Kent 3685ec
diff --git a/lib/alarm.c b/lib/alarm.c
Ian Kent 3685ec
index 6a70ed1..1e32291 100755
Ian Kent 3685ec
--- a/lib/alarm.c
Ian Kent 3685ec
+++ b/lib/alarm.c
Ian Kent 3685ec
@@ -178,7 +178,6 @@ static void *alarm_handler(void *arg)
Ian Kent 3685ec
 	head = &alarms;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	while (1) {
Ian Kent 3685ec
-
Ian Kent 3685ec
 		if (list_empty(head)) {
Ian Kent 3685ec
 			/* No alarms, wait for one to be added */
Ian Kent 3685ec
 			status = pthread_cond_wait(&cond, &mutex);
Ian Kent 3685ec
@@ -211,19 +210,8 @@ static void *alarm_handler(void *arg)
Ian Kent 3685ec
 
Ian Kent 3685ec
 			if (!first->cancel) {
Ian Kent 3685ec
 				struct autofs_point *ap = first->ap;
Ian Kent 3685ec
-				/* 
Ian Kent 3685ec
-				 * We need to unlock the alarm list in case
Ian Kent 3685ec
-				 * some other thread holds the state_mutex
Ian Kent 3685ec
-				 *_lock(ap), and is currently trying to do
Ian Kent 3685ec
-				 * some alarm_* function (i.e if we don't 
Ian Kent 3685ec
-				 * unlock, we might deadlock).
Ian Kent 3685ec
-				 */
Ian Kent 3685ec
 				alarm_unlock(); 
Ian Kent 3685ec
-
Ian Kent 3685ec
-				state_mutex_lock(ap);
Ian Kent 3685ec
-				nextstate(ap->state_pipe[1], ST_EXPIRE);
Ian Kent 3685ec
-				state_mutex_unlock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
+				st_add_task(ap, ST_EXPIRE);
Ian Kent 3685ec
 				alarm_lock();
Ian Kent 3685ec
 			}
Ian Kent 3685ec
 			free(first);
Ian Kent 3685ec
diff --git a/lib/master.c b/lib/master.c
Ian Kent 3685ec
index edd3bdc..522b919 100644
Ian Kent 3685ec
--- a/lib/master.c
Ian Kent 3685ec
+++ b/lib/master.c
Ian Kent 3685ec
@@ -90,41 +90,20 @@ int master_add_autofs_point(struct master_mapent *entry,
Ian Kent 3685ec
 	ap->logopt = logopt;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	ap->parent = NULL;
Ian Kent 3685ec
+	ap->thid = 0;
Ian Kent 3685ec
 	ap->submnt_count = 0;
Ian Kent 3685ec
 	ap->submount = submount;
Ian Kent 3685ec
 	INIT_LIST_HEAD(&ap->mounts);
Ian Kent 3685ec
 	INIT_LIST_HEAD(&ap->submounts);
Ian Kent 3685ec
 	ap->shutdown = 0;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	status = pthread_mutex_init(&ap->state_mutex, NULL);
Ian Kent 3685ec
-	if (status) {
Ian Kent 3685ec
-		free(ap->path);
Ian Kent 3685ec
-		free(ap);
Ian Kent 3685ec
-		return 0;
Ian Kent 3685ec
-	}
Ian Kent 3685ec
-
Ian Kent 3685ec
 	status = pthread_mutex_init(&ap->mounts_mutex, NULL);
Ian Kent 3685ec
 	if (status) {
Ian Kent 3685ec
-		status = pthread_mutex_destroy(&ap->state_mutex);
Ian Kent 3685ec
-		if (status)
Ian Kent 3685ec
-			fatal(status);
Ian Kent 3685ec
 		free(ap->path);
Ian Kent 3685ec
 		free(ap);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
-	status = pthread_cond_init(&ap->mounts_cond, NULL);
Ian Kent 3685ec
-	if (status) {
Ian Kent 3685ec
-		status = pthread_mutex_destroy(&ap->mounts_mutex);
Ian Kent 3685ec
-		if (status)
Ian Kent 3685ec
-			fatal(status);
Ian Kent 3685ec
-		status = pthread_mutex_destroy(&ap->state_mutex);
Ian Kent 3685ec
-		if (status)
Ian Kent 3685ec
-			fatal(status);
Ian Kent 3685ec
-		free(ap->path);
Ian Kent 3685ec
-		free(ap);
Ian Kent 3685ec
-		return 0;
Ian Kent 3685ec
-	}
Ian Kent 3685ec
 	entry->ap = ap;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return 1;
Ian Kent 3685ec
@@ -137,18 +116,10 @@ void master_free_autofs_point(struct autofs_point *ap)
Ian Kent 3685ec
 	if (!ap)
Ian Kent 3685ec
 		return;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	status = pthread_mutex_destroy(&ap->state_mutex);
Ian Kent 3685ec
-	if (status)
Ian Kent 3685ec
-		fatal(status);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	status = pthread_mutex_destroy(&ap->mounts_mutex);
Ian Kent 3685ec
 	if (status)
Ian Kent 3685ec
 		fatal(status);
Ian Kent 3685ec
 
Ian Kent 3685ec
-	status = pthread_cond_destroy(&ap->mounts_cond);
Ian Kent 3685ec
-	if (status)
Ian Kent 3685ec
-		fatal(status);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	free(ap->path);
Ian Kent 3685ec
 	free(ap);
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -295,11 +266,9 @@ struct map_source *master_find_map_source(struct master_mapent *entry,
Ian Kent 3685ec
 {
Ian Kent 3685ec
 	struct map_source *source = NULL;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	master_mutex_lock();
Ian Kent 3685ec
-
Ian Kent 3685ec
+	master_source_readlock(entry);
Ian Kent 3685ec
 	source = __master_find_map_source(entry, type, format, argc, argv);
Ian Kent 3685ec
-
Ian Kent 3685ec
-	master_mutex_unlock();
Ian Kent 3685ec
+	master_source_unlock(entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return source;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -519,13 +488,7 @@ void send_map_update_request(struct autofs_point *ap)
Ian Kent 3685ec
 	if (!need_update)
Ian Kent 3685ec
 		return;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	status = pthread_mutex_lock(&ap->state_mutex);
Ian Kent 3685ec
-	if (status)
Ian Kent 3685ec
-		fatal(status);
Ian Kent 3685ec
-	nextstate(ap->state_pipe[1], ST_READMAP);
Ian Kent 3685ec
-	status = pthread_mutex_unlock(&ap->state_mutex);
Ian Kent 3685ec
-	if (status)
Ian Kent 3685ec
-		fatal(status);
Ian Kent 3685ec
+	st_add_task(ap, ST_READMAP);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -695,17 +658,13 @@ void master_remove_mapent(struct master_mapent *entry)
Ian Kent 3685ec
 	if (entry->ap->submount)
Ian Kent 3685ec
 		return;
Ian Kent 3685ec
 
Ian Kent 3685ec
-	master_mutex_lock();
Ian Kent 3685ec
 	if (!list_empty(&entry->list))
Ian Kent 3685ec
 		list_del_init(&entry->list);
Ian Kent 3685ec
-	master_mutex_unlock();
Ian Kent 3685ec
 	return;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
 void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_cache)
Ian Kent 3685ec
 {
Ian Kent 3685ec
-	master_source_writelock(entry);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	if (entry->maps) {
Ian Kent 3685ec
 		struct map_source *m, *n;
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -718,8 +677,6 @@ void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_c
Ian Kent 3685ec
 		entry->maps = NULL;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
-	master_source_unlock(entry);
Ian Kent 3685ec
-
Ian Kent 3685ec
 	return;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -827,10 +784,9 @@ int master_submount_list_empty(struct autofs_point *ap)
Ian Kent 3685ec
 int master_notify_submount(struct autofs_point *ap, const char *path, enum states state)
Ian Kent 3685ec
 {
Ian Kent 3685ec
 	struct list_head *head, *p;
Ian Kent 3685ec
-	struct autofs_point *this;
Ian Kent 3685ec
-	pthread_t thid;
Ian Kent 3685ec
+	struct autofs_point *this = NULL;
Ian Kent 3685ec
 	size_t plen = strlen(path);
Ian Kent 3685ec
-	int status, ret = 1;
Ian Kent 3685ec
+	int ret = 1;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	mounts_mutex_lock(ap);
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -869,33 +825,25 @@ int master_notify_submount(struct autofs_point *ap, const char *path, enum state
Ian Kent 3685ec
 
Ian Kent 3685ec
 		/* Now we have a submount to expire */
Ian Kent 3685ec
 
Ian Kent 3685ec
-		state_mutex_lock(this);
Ian Kent 3685ec
+		st_mutex_lock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 		if (this->state == ST_SHUTDOWN) {
Ian Kent 3685ec
-			state_mutex_unlock(this);
Ian Kent 3685ec
+			this = NULL;
Ian Kent 3685ec
+			st_mutex_unlock();
Ian Kent 3685ec
 			break;
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 
Ian Kent 3685ec
-		nextstate(this->state_pipe[1], state);
Ian Kent 3685ec
+		this->shutdown = ap->shutdown;
Ian Kent 3685ec
 
Ian Kent 3685ec
-		state_mutex_unlock(this);
Ian Kent 3685ec
+		__st_add_task(this, state);
Ian Kent 3685ec
 
Ian Kent 3685ec
-		thid = this->thid;
Ian Kent 3685ec
-		ap->mounts_signaled = MASTER_SUBMNT_WAIT;
Ian Kent 3685ec
-		while (ap->mounts_signaled == MASTER_SUBMNT_WAIT) {
Ian Kent 3685ec
-			status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex);
Ian Kent 3685ec
-			if (status)
Ian Kent 3685ec
-				fatal(status);
Ian Kent 3685ec
-		}
Ian Kent 3685ec
+		st_mutex_unlock();
Ian Kent 3685ec
+		mounts_mutex_unlock(ap);
Ian Kent 3685ec
 
Ian Kent 3685ec
-		if (ap->mounts_signaled == MASTER_SUBMNT_JOIN) {
Ian Kent 3685ec
-			status = pthread_join(thid, NULL);
Ian Kent 3685ec
-			if (status)
Ian Kent 3685ec
-				fatal(status);
Ian Kent 3685ec
-		} else
Ian Kent 3685ec
-			ret = 0;
Ian Kent 3685ec
+		st_wait_task(this, state, 0);
Ian Kent 3685ec
+
Ian Kent 3685ec
+		return ret;
Ian Kent 3685ec
 
Ian Kent 3685ec
-		break;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
 	mounts_mutex_unlock(ap);
Ian Kent 3685ec
@@ -903,38 +851,12 @@ int master_notify_submount(struct autofs_point *ap, const char *path, enum state
Ian Kent 3685ec
 	return ret;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
-void master_signal_submount(struct autofs_point *ap, unsigned int join)
Ian Kent 3685ec
-{
Ian Kent 3685ec
-	int status;
Ian Kent 3685ec
-
Ian Kent 3685ec
-	if (!ap->parent || !ap->submount)
Ian Kent 3685ec
-		return;
Ian Kent 3685ec
-
Ian Kent 3685ec
-	mounts_mutex_lock(ap->parent);
Ian Kent 3685ec
-
Ian Kent 3685ec
-	ap->parent->mounts_signaled = join;
Ian Kent 3685ec
-
Ian Kent 3685ec
-	if (join == MASTER_SUBMNT_JOIN) {
Ian Kent 3685ec
-		/* We are finishing up */
Ian Kent 3685ec
-		ap->parent->submnt_count--;
Ian Kent 3685ec
-		list_del(&ap->mounts);
Ian Kent 3685ec
-	}
Ian Kent 3685ec
-
Ian Kent 3685ec
-	status = pthread_cond_signal(&ap->parent->mounts_cond);
Ian Kent 3685ec
-	if (status)
Ian Kent 3685ec
-		fatal(status);
Ian Kent 3685ec
-
Ian Kent 3685ec
-	mounts_mutex_unlock(ap->parent);
Ian Kent 3685ec
-
Ian Kent 3685ec
-	return;
Ian Kent 3685ec
-}
Ian Kent 3685ec
-
Ian Kent 3685ec
 void master_notify_state_change(struct master *master, int sig)
Ian Kent 3685ec
 {
Ian Kent 3685ec
 	struct master_mapent *entry;
Ian Kent 3685ec
 	struct autofs_point *ap;
Ian Kent 3685ec
 	struct list_head *p;
Ian Kent 3685ec
-	int state_pipe, cur_state;
Ian Kent 3685ec
+	int cur_state;
Ian Kent 3685ec
 	unsigned int logopt;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
Ian Kent 3685ec
@@ -948,13 +870,11 @@ void master_notify_state_change(struct master *master, int sig)
Ian Kent 3685ec
 		ap = entry->ap;
Ian Kent 3685ec
 		logopt = ap->logopt;
Ian Kent 3685ec
 
Ian Kent 3685ec
-		state_mutex_lock(ap);
Ian Kent 3685ec
+		st_mutex_lock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 		if (ap->state == ST_SHUTDOWN)
Ian Kent 3685ec
 			goto next;
Ian Kent 3685ec
 
Ian Kent 3685ec
-		state_pipe = ap->state_pipe[1];
Ian Kent 3685ec
-
Ian Kent 3685ec
 		switch (sig) {
Ian Kent 3685ec
 		case SIGTERM:
Ian Kent 3685ec
 		case SIGINT:
Ian Kent 3685ec
@@ -962,7 +882,7 @@ void master_notify_state_change(struct master *master, int sig)
Ian Kent 3685ec
 			    ap->state != ST_SHUTDOWN_FORCE) {
Ian Kent 3685ec
 				next = ST_SHUTDOWN_PENDING;
Ian Kent 3685ec
 				ap->shutdown = 1;
Ian Kent 3685ec
-				nextstate(state_pipe, next);
Ian Kent 3685ec
+				__st_add_task(ap, next);
Ian Kent 3685ec
 			}
Ian Kent 3685ec
 			break;
Ian Kent 3685ec
 #ifdef ENABLE_FORCED_SHUTDOWN
Ian Kent 3685ec
@@ -970,14 +890,15 @@ void master_notify_state_change(struct master *master, int sig)
Ian Kent 3685ec
 			if (ap->state != ST_SHUTDOWN_FORCE &&
Ian Kent 3685ec
 			    ap->state != ST_SHUTDOWN_PENDING) {
Ian Kent 3685ec
 				next = ST_SHUTDOWN_FORCE;
Ian Kent 3685ec
-				nextstate(state_pipe, next);
Ian Kent 3685ec
+				ap->shutdown = 1;
Ian Kent 3685ec
+				__st_add_task(ap, next);
Ian Kent 3685ec
 			}
Ian Kent 3685ec
 			break;
Ian Kent 3685ec
 #endif
Ian Kent 3685ec
 		case SIGUSR1:
Ian Kent 3685ec
 			assert(ap->state == ST_READY);
Ian Kent 3685ec
 			next = ST_PRUNE;
Ian Kent 3685ec
-			nextstate(state_pipe, next);
Ian Kent 3685ec
+			__st_add_task(ap, next);
Ian Kent 3685ec
 			break;
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 next:
Ian Kent 3685ec
@@ -986,7 +907,7 @@ next:
Ian Kent 3685ec
 			      "sig %d switching %s from %d to %d",
Ian Kent 3685ec
 			      sig, ap->path, ap->state, next);
Ian Kent 3685ec
 
Ian Kent 3685ec
-		state_mutex_unlock(ap);
Ian Kent 3685ec
+		st_mutex_unlock();
Ian Kent 3685ec
 	}
Ian Kent 3685ec
 
Ian Kent 3685ec
 	master_mutex_unlock();
Ian Kent 3685ec
@@ -1024,7 +945,6 @@ static int master_do_mount(struct master_mapent *entry)
Ian Kent 3685ec
 		handle_mounts_startup_cond_destroy(&suc);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
-	entry->thid = thid;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	while (!suc.done) {
Ian Kent 3685ec
 		status = pthread_cond_wait(&suc.cond, &suc.mutex);
Ian Kent 3685ec
@@ -1037,45 +957,18 @@ static int master_do_mount(struct master_mapent *entry)
Ian Kent 3685ec
 		handle_mounts_startup_cond_destroy(&suc);
Ian Kent 3685ec
 		return 0;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
+	entry->thid = thid;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	handle_mounts_startup_cond_destroy(&suc);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return 1;
Ian Kent 3685ec
 }
Ian Kent 3685ec
 
Ian Kent 3685ec
-static void shutdown_entry(struct master_mapent *entry)
Ian Kent 3685ec
-{
Ian Kent 3685ec
-	int state_pipe;
Ian Kent 3685ec
-	struct autofs_point *ap;
Ian Kent 3685ec
-	struct stat st;
Ian Kent 3685ec
-	int ret;
Ian Kent 3685ec
-
Ian Kent 3685ec
-	ap = entry->ap;
Ian Kent 3685ec
-
Ian Kent 3685ec
-	debug(ap->logopt, "%s", entry->path);
Ian Kent 3685ec
-
Ian Kent 3685ec
-	state_mutex_lock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
-	state_pipe = ap->state_pipe[1];
Ian Kent 3685ec
-
Ian Kent 3685ec
-	ret = fstat(state_pipe, &st);
Ian Kent 3685ec
-	if (ret == -1)
Ian Kent 3685ec
-		goto next;
Ian Kent 3685ec
-
Ian Kent 3685ec
-	nextstate(state_pipe, ST_SHUTDOWN_PENDING);
Ian Kent 3685ec
-next:
Ian Kent 3685ec
-	state_mutex_unlock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
-	return;
Ian Kent 3685ec
-}
Ian Kent 3685ec
-
Ian Kent 3685ec
 static void check_update_map_sources(struct master_mapent *entry, int readall)
Ian Kent 3685ec
 {
Ian Kent 3685ec
 	struct map_source *source, *last;
Ian Kent 3685ec
-	int state_pipe, map_stale = 0;
Ian Kent 3685ec
 	struct autofs_point *ap;
Ian Kent 3685ec
-	struct stat st;
Ian Kent 3685ec
-	int ret;
Ian Kent 3685ec
+	int map_stale = 0;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	if (readall)
Ian Kent 3685ec
 		map_stale = 1;
Ian Kent 3685ec
@@ -1128,17 +1021,8 @@ static void check_update_map_sources(struct master_mapent *entry, int readall)
Ian Kent 3685ec
 	master_source_unlock(entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	/* The map sources have changed */
Ian Kent 3685ec
-	if (map_stale) {
Ian Kent 3685ec
-		state_mutex_lock(ap);
Ian Kent 3685ec
-
Ian Kent 3685ec
-		state_pipe = entry->ap->state_pipe[1];
Ian Kent 3685ec
-
Ian Kent 3685ec
-		ret = fstat(state_pipe, &st);
Ian Kent 3685ec
-		if (ret != -1)
Ian Kent 3685ec
-			nextstate(state_pipe, ST_READMAP);
Ian Kent 3685ec
-
Ian Kent 3685ec
-		state_mutex_unlock(ap);
Ian Kent 3685ec
-	}
Ian Kent 3685ec
+	if (map_stale)
Ian Kent 3685ec
+		st_add_task(ap, ST_READMAP);
Ian Kent 3685ec
 
Ian Kent 3685ec
 	return;
Ian Kent 3685ec
 }
Ian Kent 3685ec
@@ -1169,17 +1053,19 @@ int master_mount_mounts(struct master *master, time_t age, int readall)
Ian Kent 3685ec
 
Ian Kent 3685ec
 		/* A master map entry has gone away */
Ian Kent 3685ec
 		if (this->age < age) {
Ian Kent 3685ec
-			shutdown_entry(this);
Ian Kent 3685ec
+			st_add_task(ap, ST_SHUTDOWN_PENDING);
Ian Kent 3685ec
 			continue;
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 
Ian Kent 3685ec
+		master_source_writelock(ap->entry);
Ian Kent 3685ec
 		lookup_close_lookup(ap);
Ian Kent 3685ec
+		master_source_unlock(ap->entry);
Ian Kent 3685ec
 
Ian Kent 3685ec
 		cache_readlock(nc);
Ian Kent 3685ec
 		ne = cache_lookup_distinct(nc, this->path);
Ian Kent 3685ec
 		if (ne && this->age > ne->age) {
Ian Kent 3685ec
 			cache_unlock(nc);
Ian Kent 3685ec
-			shutdown_entry(this);
Ian Kent 3685ec
+			st_add_task(ap, ST_SHUTDOWN_PENDING);
Ian Kent 3685ec
 			continue;
Ian Kent 3685ec
 		}
Ian Kent 3685ec
 		nested = cache_partial_match(nc, this->path);
Ian Kent 3685ec
@@ -1195,7 +1081,7 @@ int master_mount_mounts(struct master *master, time_t age, int readall)
Ian Kent 3685ec
 
Ian Kent 3685ec
 		check_update_map_sources(this, readall);
Ian Kent 3685ec
 
Ian Kent 3685ec
-		state_mutex_lock(ap);
Ian Kent 3685ec
+		st_mutex_lock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 		state_pipe = this->ap->state_pipe[1];
Ian Kent 3685ec
 
Ian Kent 3685ec
@@ -1203,7 +1089,7 @@ int master_mount_mounts(struct master *master, time_t age, int readall)
Ian Kent 3685ec
 		ret = fstat(state_pipe, &st);
Ian Kent 3685ec
 		save_errno = errno;
Ian Kent 3685ec
 
Ian Kent 3685ec
-		state_mutex_unlock(ap);
Ian Kent 3685ec
+		st_mutex_unlock();
Ian Kent 3685ec
 
Ian Kent 3685ec
 		if (ret == -1 && save_errno == EBADF)
Ian Kent 3685ec
 			if (!master_do_mount(this)) {
Ian Kent 3685ec
diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
Ian Kent 3685ec
index 6f66564..d6cbda8 100644
Ian Kent 3685ec
--- a/modules/mount_autofs.c
Ian Kent 3685ec
+++ b/modules/mount_autofs.c
Ian Kent 3685ec
@@ -242,7 +242,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
Ian Kent 3685ec
 		master_free_mapent(entry);
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
-	nap->thid = thid;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	while (!suc.done) {
Ian Kent 3685ec
 		status = pthread_cond_wait(&suc.cond, &suc.mutex);
Ian Kent 3685ec
@@ -264,6 +263,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
Ian Kent 3685ec
 		master_free_mapent(entry);
Ian Kent 3685ec
 		return 1;
Ian Kent 3685ec
 	}
Ian Kent 3685ec
+	nap->thid = thid;
Ian Kent 3685ec
 
Ian Kent 3685ec
 	ap->submnt_count++;
Ian Kent 3685ec
 	list_add(&nap->mounts, &ap->submounts);