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);
-
}
}