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