autofs-5.1.1 - fix handle_mounts() termination condition check From: Ian Kent 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 --- CHANGELOG | 1 daemon/automount.c | 191 ++++++++++++++++++++++++++++------------------------ 2 files changed, 105 insertions(+), 87 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7973598..8164ea9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,7 @@ - always set direct mounts catatonic at exit. - fix use-after-free in st_queue_handler(). - log pipe read errors. +- fix handle_mounts() termination condition check. 21/04/2015 autofs-5.1.1 ======================= diff --git a/daemon/automount.c b/daemon/automount.c index 02c8368..ad5cafd 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -1687,6 +1687,99 @@ static void submount_source_unlock_nested(struct autofs_point *ap) 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; @@ -1742,97 +1835,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); - } }