diff --git a/CHANGELOG b/CHANGELOG index 2382695..152eec5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -60,6 +60,7 @@ - use mount option "nodev" for "-hosts" map unless "dev" is explicily specified. - add LDAP paged query handling to deal with query size restrictions (Edward Newman). - add additional case for "mark map instances stale so they aren't "cleaned" during updates". +- fix race during sub-mount shutdown. 18/06/2007 autofs-5.0.2 ----------------------- diff --git a/daemon/automount.c b/daemon/automount.c index f31ec11..afbcb56 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -1564,9 +1564,24 @@ void *handle_mounts(void *arg) } /* OK to exit */ - if (ap->state == ST_SHUTDOWN || result) { - state_mutex_unlock(ap); - break; + if (ap->state == ST_SHUTDOWN) { + if (result) { + state_mutex_unlock(ap); + break; + } +#ifdef ENABLE_IGNORE_BUSY_MOUNTS + /* + * There weren't any active mounts but if the + * filesystem is busy there may be a mount + * request in progress so return to the ready + * state unless a shutdown has been explicitly + * requested. + */ + if (ap->shutdown) { + state_mutex_unlock(ap); + break; + } +#endif } /* Failed shutdown returns to ready */ diff --git a/daemon/direct.c b/daemon/direct.c index 619efce..529f143 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -1494,7 +1494,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ (unsigned long) pkt->wait_queue_token, me->key, pkt->pid); /* Ignore packet if we're trying to shut down */ - if (ap->state == ST_SHUTDOWN_PENDING || + if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN) { send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); diff --git a/daemon/indirect.c b/daemon/indirect.c index f6b93d0..fd94e59 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -863,7 +863,7 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin (unsigned long) pkt->wait_queue_token, pkt->name, pkt->pid); /* Ignore packet if we're trying to shut down */ - if (ap->state == ST_SHUTDOWN_PENDING || + if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN) { send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); diff --git a/daemon/lookup.c b/daemon/lookup.c index eb72411..eac6053 100644 --- a/daemon/lookup.c +++ b/daemon/lookup.c @@ -928,10 +928,17 @@ void lookup_close_lookup(struct autofs_point *ap) if (!map) return; + /* + * Make sure we don't kill the context if a mount + * request has come in while were shutting down. + */ + master_source_writelock(ap->entry); while (map) { lookup_close_lookup_instances(map); map = map->next; } + master_source_unlock(ap->entry); + return; } diff --git a/daemon/state.c b/daemon/state.c index 5bccfef..5804707 100644 --- a/daemon/state.c +++ b/daemon/state.c @@ -113,6 +113,8 @@ void expire_cleanup(void *arg) /* Check to see if expire process finished */ if (thid == ap->exp_thread) { + int rv, idle; + ap->exp_thread = 0; switch (ap->state) { @@ -133,8 +135,6 @@ void expire_cleanup(void *arg) * allowing it to shutdown. */ if (ap->submount && !success) { - int rv, idle; - rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &idle); if (!rv && idle && ap->submount > 1) { next = ST_SHUTDOWN_PENDING; @@ -155,6 +155,19 @@ void expire_cleanup(void *arg) break; case ST_SHUTDOWN_PENDING: + /* + * If we reveive a mount request while trying to + * shutdown return to ready state unless we have + * been signaled to shutdown. + */ + rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &idle); + if (!idle && !ap->shutdown) { + next = ST_READY; + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); + break; + } + next = ST_SHUTDOWN; #ifdef ENABLE_IGNORE_BUSY_MOUNTS break; @@ -200,6 +213,7 @@ static unsigned int st_ready(struct autofs_point *ap) debug(ap->logopt, "st_ready(): state = %d path %s", ap->state, ap->path); + ap->shutdown = 0; ap->state = ST_READY; if (ap->submount) diff --git a/include/automount.h b/include/automount.h index 133fd32..cd8ce7b 100644 --- a/include/automount.h +++ b/include/automount.h @@ -461,6 +461,7 @@ struct autofs_point { unsigned int mounts_signaled; /* Submount signals task complete */ struct list_head mounts; /* List of autofs mounts at current level */ unsigned int submount; /* Is this a submount */ + unsigned int shutdown; /* Shutdown notification */ unsigned int submnt_count; /* Number of submounts */ struct list_head submounts; /* List of child submounts */ }; diff --git a/lib/master.c b/lib/master.c index c001d20..ed82131 100644 --- a/lib/master.c +++ b/lib/master.c @@ -94,6 +94,7 @@ int master_add_autofs_point(struct master_mapent *entry, ap->submount = submount; INIT_LIST_HEAD(&ap->mounts); INIT_LIST_HEAD(&ap->submounts); + ap->shutdown = 0; status = pthread_mutex_init(&ap->state_mutex, NULL); if (status) { @@ -968,6 +969,7 @@ void master_notify_state_change(struct master *master, int sig) if (ap->state != ST_SHUTDOWN_PENDING && ap->state != ST_SHUTDOWN_FORCE) { next = ST_SHUTDOWN_PENDING; + ap->shutdown = 1; nextstate(state_pipe, next); } break; @@ -1180,9 +1182,7 @@ int master_mount_mounts(struct master *master, time_t age, int readall) continue; } - master_source_writelock(this); lookup_close_lookup(ap); - master_source_unlock(this); cache_readlock(nc); ne = cache_lookup_distinct(nc, this->path);