Blob Blame History Raw
autofs-5.1.1 - fix handle_mounts() termination condition check

From: Ian Kent <raven@themaw.net>

In get_pkt(), if a kernel request is present on the kernel pipe and
the autofs mount point state changes to ST_SHUTDOWN after the poll(2)
check but before the request has been processed the handle_mounts()
thread will exit without shutting down the autofs mount point.

So change the handle_mounts() exit condition check to take account
of this case.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG          |    1 
 daemon/automount.c |  191 ++++++++++++++++++++++++++++-------------------------
 2 files changed, 105 insertions(+), 87 deletions(-)

--- autofs-5.0.7.orig/CHANGELOG
+++ autofs-5.0.7/CHANGELOG
@@ -189,6 +189,7 @@
 - always set direct mounts catatonic at exit.
 - log pipe read errors.
 - fix rwlock unlock crash.
+- fix handle_mounts() termination condition check.
 
 25/07/2012 autofs-5.0.7
 =======================
--- autofs-5.0.7.orig/daemon/automount.c
+++ autofs-5.0.7/daemon/automount.c
@@ -1659,6 +1659,99 @@ static void submount_source_unlock_neste
 	master_source_unlock(parent->entry);
 }
 
+int handle_mounts_exit(struct autofs_point *ap)
+{
+	int ret, cur_state;
+
+	/*
+	 * If we're a submount we need to ensure our parent
+	 * doesn't try to mount us again until our shutdown
+	 * is complete and that any outstanding mounts are
+	 * completed before we try to shutdown.
+	 */
+	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+
+	master_mutex_lock();
+
+	if (!ap->submount)
+		master_source_writelock(ap->entry);
+	else {
+		/*
+		 * If a mount request arrives before the locks are
+		 * aquired just return to ready state.
+		 */
+		ret = submount_source_writelock_nested(ap);
+		if (ret) {
+			warn(ap->logopt,
+			     "can't shutdown submount: mount in progress");
+			/* Return to ST_READY is done immediately */
+			st_add_task(ap, ST_READY);
+			master_mutex_unlock();
+			pthread_setcancelstate(cur_state, NULL);
+			return 0;
+		}
+	}
+
+	if (ap->state != ST_SHUTDOWN) {
+		if (!ap->submount)
+			alarm_add(ap, ap->exp_runfreq);
+		/* Return to ST_READY is done immediately */
+		st_add_task(ap, ST_READY);
+		if (ap->submount)
+			submount_source_unlock_nested(ap);
+		else
+			master_source_unlock(ap->entry);
+		master_mutex_unlock();
+
+		pthread_setcancelstate(cur_state, NULL);
+		return 0;
+	}
+
+	alarm_delete(ap);
+	st_remove_tasks(ap);
+	st_wait_task(ap, ST_ANY, 0);
+
+	/*
+	 * For a direct mount map all mounts have already gone
+	 * by the time we get here and since we only ever
+	 * umount direct mounts at shutdown there is no need
+	 * to check for possible recovery.
+	 */
+	if (ap->type == LKP_DIRECT) {
+		umount_autofs(ap, NULL, 1);
+		handle_mounts_cleanup(ap);
+		return 1;
+	}
+
+	/*
+	 * If umount_autofs returns non-zero it wasn't able
+	 * to complete the umount and has left the mount intact
+	 * so we can continue. This can happen if a lookup
+	 * occurs while we're trying to umount.
+	 */
+	ret = umount_autofs(ap, NULL, 1);
+	if (!ret) {
+		handle_mounts_cleanup(ap);
+		return 1;
+	}
+
+	/* Failed shutdown returns to ready */
+	warn(ap->logopt, "can't shutdown: filesystem %s still busy", ap->path);
+	if (!ap->submount)
+		alarm_add(ap, ap->exp_runfreq);
+	/* Return to ST_READY is done immediately */
+	st_add_task(ap, ST_READY);
+	if (ap->submount)
+		submount_source_unlock_nested(ap);
+	else
+		master_source_unlock(ap->entry);
+	master_mutex_unlock();
+
+	pthread_setcancelstate(cur_state, NULL);
+
+	return 0;
+}
+
 void *handle_mounts(void *arg)
 {
 	struct startup_cond *suc;
@@ -1714,97 +1807,21 @@ void *handle_mounts(void *arg)
 
 	pthread_setcancelstate(cancel_state, NULL);
 
-	while (ap->state != ST_SHUTDOWN) {
+	while (1) {
 		if (handle_packet(ap)) {
-			int ret, cur_state;
-
-			/*
-			 * If we're a submount we need to ensure our parent
-			 * doesn't try to mount us again until our shutdown
-			 * is complete and that any outstanding mounts are
-			 * completed before we try to shutdown.
-			 */
-			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
-
-			master_mutex_lock();
-
-			if (ap->submount) {
-				/*
-				 * If a mount request arrives before the locks are
-				 * aquired just return to ready state.
-				 */
-				ret = submount_source_writelock_nested(ap);
-				if (ret) {
-					warn(ap->logopt,
-					     "can't shutdown submount: mount in progress");
-					/* Return to ST_READY is done immediately */
-					st_add_task(ap, ST_READY);
-					master_mutex_unlock();
-					pthread_setcancelstate(cur_state, NULL);
-					continue;
-				}
-			} else
-				master_source_writelock(ap->entry);
-
-			if (ap->state != ST_SHUTDOWN) {
-				if (!ap->submount)
-					alarm_add(ap, ap->exp_runfreq);
-				/* Return to ST_READY is done immediately */
-				st_add_task(ap, ST_READY);
-				if (ap->submount)
-					submount_source_unlock_nested(ap);
-				else
-					master_source_unlock(ap->entry);
-				master_mutex_unlock();
-
-				pthread_setcancelstate(cur_state, NULL);
-				continue;
-			}
-
-			alarm_delete(ap);
-			st_remove_tasks(ap);
-			st_wait_task(ap, ST_ANY, 0);
-
-			/*
-			 * For a direct mount map all mounts have already gone
-			 * by the time we get here and since we only ever
-			 * umount direct mounts at shutdown there is no need
-			 * to check for possible recovery.
-			 */
-			if (ap->type == LKP_DIRECT) {
-				umount_autofs(ap, NULL, 1);
-				handle_mounts_cleanup(ap);
+			if (handle_mounts_exit(ap))
 				break;
-			}
+		}
 
-			/*
-			 * If umount_autofs returns non-zero it wasn't able
-			 * to complete the umount and has left the mount intact
-			 * so we can continue. This can happen if a lookup
-			 * occurs while we're trying to umount.
-			 */
-			ret = umount_autofs(ap, NULL, 1);
-			if (!ret) {
-				handle_mounts_cleanup(ap);
+		/* If we get here a packet has been received and handled
+		 * and the autofs mount point has not been shutdown. But
+		 * if the autofs mount point has been set to ST_SHUTDOWN
+		 * we should attempt to perform the shutdown cleanup and
+		 * exit if successful.
+		 */
+		if (ap->state == ST_SHUTDOWN) {
+			if (handle_mounts_exit(ap))
 				break;
-			}
-
-			/* Failed shutdown returns to ready */
-			warn(ap->logopt,
-			     "can't shutdown: filesystem %s still busy",
-			     ap->path);
-			if (!ap->submount)
-				alarm_add(ap, ap->exp_runfreq);
-			/* Return to ST_READY is done immediately */
-			st_add_task(ap, ST_READY);
-			if (ap->submount)
-				submount_source_unlock_nested(ap);
-			else
-				master_source_unlock(ap->entry);
-			master_mutex_unlock();
-
-			pthread_setcancelstate(cur_state, NULL);
-
 		}
 	}