diff --git a/CHANGELOG b/CHANGELOG index 78a4cf8..b6e30c4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -33,6 +33,7 @@ - fix directory cleanup on expire. - fix task cancelation at shutdown. - fix included map wild card key lookup. +- fix task cancelation at shutdown (more). 13/7/2006 autofs-5.0.1 rc1 -------------------------- diff --git a/daemon/automount.c b/daemon/automount.c index 8195349..343fd68 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -391,9 +391,12 @@ static int umount_subtree_mounts(struct left = 0; + pthread_cleanup_push(cache_lock_cleanup, mc); + if (me->multi) { char *root, *base; size_t ap_len; + int cur_state; ap_len = strlen(ap->path); @@ -411,6 +414,7 @@ static int umount_subtree_mounts(struct else base = me->key + strlen(root); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); /* Lock the closest parent nesting point for umount */ cache_multi_lock(me->parent); if (umount_multi_triggers(ap, root, me, base)) { @@ -419,9 +423,10 @@ static int umount_subtree_mounts(struct left++; } cache_multi_unlock(me->parent); + pthread_setcancelstate(cur_state, NULL); } - cache_unlock(mc); + pthread_cleanup_pop(1); if (left || is_autofs_fs) return left; @@ -616,8 +621,10 @@ static int get_pkt(struct autofs_point * if (post_state != ST_INVAL) { if (post_state == ST_SHUTDOWN_PENDING || - post_state == ST_SHUTDOWN_FORCE) + post_state == ST_SHUTDOWN_FORCE) { + alarm_delete(ap); st_remove_tasks(ap); + } st_add_task(ap, post_state); } @@ -947,7 +954,7 @@ static int do_hup_signal(struct master * static void *statemachine(void *arg) { sigset_t signalset; - int sig, status; + int sig; sigfillset(&signalset); sigdelset(&signalset, SIGCHLD); @@ -956,20 +963,9 @@ static void *statemachine(void *arg) while (1) { sigwait(&signalset, &sig); - status = pthread_mutex_lock(&master_mutex); - if (status) - fatal(status); - if (list_empty(&master_list->mounts)) { - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); + if (master_list_empty(master_list)) return NULL; - } - - status = pthread_mutex_unlock(&master_mutex); - if (status) - fatal(status); switch (sig) { case SIGTERM: @@ -1068,6 +1064,9 @@ static void handle_mounts_cleanup(void * /* If we have been canceled then we may hold the state mutex. */ mutex_operation_wait(&ap->state_mutex); + alarm_delete(ap); + st_remove_tasks(ap); + umount_autofs(ap, 1); master_signal_submount(ap, MASTER_SUBMNT_JOIN); @@ -1117,6 +1116,7 @@ void *handle_mounts(void *arg) suc.status = 1; state_mutex_unlock(ap); umount_autofs(ap, 1); + pthread_setcancelstate(cancel_state, NULL); pthread_exit(NULL); } @@ -1132,7 +1132,7 @@ void *handle_mounts(void *arg) alarm_add(ap, ap->exp_runfreq + rand() % ap->exp_runfreq); pthread_cleanup_push(handle_mounts_cleanup, ap); - pthread_setcancelstate(cancel_state, &cancel_state); + pthread_setcancelstate(cancel_state, NULL); state_mutex_unlock(ap); diff --git a/daemon/direct.c b/daemon/direct.c index b08cbdd..9a1cd59 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -758,7 +758,12 @@ static int expire_direct(int ioctlfd, co nanosleep(&tm, NULL); } - return (retries >= 0); + if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) { + if (!ret) + return 0; + } + + return 1; } static void mnts_cleanup(void *arg) @@ -770,7 +775,7 @@ static void mnts_cleanup(void *arg) void *expire_proc_direct(void *arg) { - struct mnt_list *mnts, *next; + struct mnt_list *mnts = NULL, *next; struct expire_args *ea; struct autofs_point *ap; struct mapent *me = NULL; @@ -786,7 +791,7 @@ void *expire_proc_direct(void *arg) ap = ea->ap; now = ea->when; - ea->status = 1; + ea->status = -1; ea->signaled = 1; status = pthread_cond_signal(&ea->cond); @@ -807,8 +812,8 @@ void *expire_proc_direct(void *arg) left = 0; /* Get a list of real mounts and expire them if possible */ - mnts = get_mnt_list(_PROC_MOUNTS, "/", 0); pthread_cleanup_push(mnts_cleanup, mnts); + mnts = get_mnt_list(_PROC_MOUNTS, "/", 0); for (next = mnts; next; next = next->next) { if (!strcmp(next->fs_type, "autofs")) { /* @@ -828,6 +833,9 @@ void *expire_proc_direct(void *arg) continue; } + if (ap->state == ST_EXPIRE || ap->state == ST_PRUNE) + pthread_testcancel(); + /* * All direct mounts must be present in the map * entry cache. @@ -857,7 +865,9 @@ void *expire_proc_direct(void *arg) ea->status = left; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); pthread_cleanup_pop(1); + pthread_setcancelstate(cur_state, NULL); return NULL; } @@ -1361,6 +1371,7 @@ int handle_packet_missing_direct(struct cache_unlock(mc); pthread_cleanup_push(pending_cleanup, mt); + pthread_setcancelstate(state, NULL); mt->signaled = 0; while (!mt->signaled) { diff --git a/daemon/indirect.c b/daemon/indirect.c index cff4f1c..38d0b7a 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -399,7 +399,12 @@ static int expire_indirect(struct autofs nanosleep(&tm, NULL); } - return (retries >= 0); + if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) { + if (!ret) + return 0; + } + + return 1; } static void mnts_cleanup(void *arg) @@ -413,7 +418,7 @@ void *expire_proc_indirect(void *arg) { struct autofs_point *ap; struct mapent *me = NULL; - struct mnt_list *mnts, *next; + struct mnt_list *mnts = NULL, *next; struct expire_args *ea; unsigned int now; int offsets, submnts, count; @@ -428,7 +433,7 @@ void *expire_proc_indirect(void *arg) ap = ea->ap; now = ea->when; - ea->status = 1; + ea->status = -1; ea->signaled = 1; status = pthread_cond_signal(&ea->cond); @@ -449,8 +454,8 @@ void *expire_proc_indirect(void *arg) left = 0; /* Get a list of real mounts and expire them if possible */ - mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0); pthread_cleanup_push(mnts_cleanup, mnts); + mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0); for (next = mnts; next; next = next->next) { char *ind_key; int ret; @@ -468,6 +473,9 @@ void *expire_proc_indirect(void *arg) continue; } + if (ap->state == ST_EXPIRE || ap->state == ST_PRUNE) + pthread_testcancel(); + /* * If the mount corresponds to an offset trigger then * the key is the path, otherwise it's the last component. @@ -554,7 +562,9 @@ void *expire_proc_indirect(void *arg) ea->status = left; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); pthread_cleanup_pop(1); + pthread_setcancelstate(cur_state, NULL); return NULL; } diff --git a/daemon/state.c b/daemon/state.c index 47fee39..526725b 100644 --- a/daemon/state.c +++ b/daemon/state.c @@ -98,14 +98,12 @@ void expire_cleanup(void *arg) struct autofs_point *ap; int statefd; enum states next = ST_INVAL; - int success, ret, cur_state; + int success, ret; ea = (struct expire_args *) arg; ap = ea->ap; success = ea->status; - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); - state_mutex_lock(ap); debug(ap->logopt, @@ -179,8 +177,6 @@ #endif free(ea); - pthread_setcancelstate(cur_state, NULL); - return; } @@ -602,12 +598,31 @@ static unsigned int st_expire(struct aut return 0; } +static struct state_queue *st_alloc_task(struct autofs_point *ap, enum states state) +{ + struct state_queue *task; + + task = malloc(sizeof(struct state_queue)); + if (!task) + return NULL; + memset(task, 0, sizeof(struct state_queue)); + + task->ap = ap; + task->state = state; + + INIT_LIST_HEAD(&task->list); + INIT_LIST_HEAD(&task->pending); + + return task; +} + /* Insert alarm entry on ordered list. */ int st_add_task(struct autofs_point *ap, enum states state) { struct list_head *head; - struct list_head *p; + struct list_head *p, *q; struct state_queue *new; + enum states ap_state; unsigned int empty = 1; int status; @@ -630,23 +645,13 @@ int st_add_task(struct autofs_point *ap, } state_mutex_lock(ap); - if (ap->state == ST_SHUTDOWN) { + ap_state = ap->state; + if (ap_state == ST_SHUTDOWN) { state_mutex_unlock(ap); return 1; } state_mutex_unlock(ap); - new = malloc(sizeof(struct state_queue)); - if (!new) - return 0; - memset(new, 0, sizeof(struct state_queue)); - - new->ap = ap; - new->state = state; - - INIT_LIST_HEAD(&new->list); - INIT_LIST_HEAD(&new->pending); - st_mutex_lock(); head = &state_queue; @@ -657,15 +662,48 @@ int st_add_task(struct autofs_point *ap, task = list_entry(p, struct state_queue, list); - if (task->ap == ap) { - empty = 0; - list_add_tail(&new->pending, &task->pending); + if (task->ap != ap) + continue; + + empty = 0; + + /* Don't add duplicate shutdown tasks */ + if (task->state == state && + (ap_state == ST_SHUTDOWN_PENDING || + ap_state == ST_SHUTDOWN_FORCE)) break; + + /* No pending tasks */ + if (list_empty(&task->pending)) { + new = st_alloc_task(ap, state); + if (new) + list_add_tail(&new->pending, &task->pending); + goto done; + } + + list_for_each(q, &task->pending) { + struct state_queue *p_task; + + p_task = list_entry(q, struct state_queue, pending); + + if (p_task->state == state && + (ap_state == ST_SHUTDOWN_PENDING || + ap_state == ST_SHUTDOWN_FORCE)) + goto done; } + + new = st_alloc_task(ap, state); + if (new) + list_add_tail(&new->pending, &task->pending); +done: + break; } - if (empty) - list_add(&new->list, head); + if (empty) { + new = st_alloc_task(ap, state); + if (new) + list_add(&new->list, head); + } /* Added task, encourage state machine */ signaled = 1; @@ -715,8 +753,12 @@ void st_remove_tasks(struct autofs_point waiting = list_entry(q, struct state_queue, pending); q = q->next; - list_del(&waiting->pending); - free(waiting); + /* Don't remove existing shutdown task */ + if (waiting->state != ST_SHUTDOWN_PENDING && + waiting->state != ST_SHUTDOWN_FORCE) { + list_del(&waiting->pending); + free(waiting); + } } } @@ -735,7 +777,7 @@ static int run_state_task(struct state_q { struct autofs_point *ap; enum states next_state, state; - unsigned long ret = 1; + unsigned long ret = 0; ap = task->ap; next_state = task->state; @@ -767,7 +809,6 @@ static int run_state_task(struct state_q break; default: - ret = 0; error(ap->logopt, "bad next state %d", next_state); } } @@ -825,12 +866,7 @@ static void *st_queue_handler(void *arg) task = list_entry(p, struct state_queue, list); p = p->next; -/* - debug(LOGOPT_NONE, - "task %p ap %p state %d next %d busy %d", - task, task->ap, task->ap->state, - task->state, task->busy); -*/ + task->busy = 1; ret = run_state_task(task); @@ -861,12 +897,7 @@ static void *st_queue_handler(void *arg) task = list_entry(p, struct state_queue, list); p = p->next; -/* - debug(LOGOPT_NONE, - "task %p ap %p state %d next %d busy %d", - task, task->ap, task->ap->state, - task->state, task->busy); -*/ + if (!task->busy) { /* Start a new task */ task->busy = 1; diff --git a/include/automount.h b/include/automount.h index 6153f71..1f4fc6b 100644 --- a/include/automount.h +++ b/include/automount.h @@ -123,7 +123,7 @@ #define CHE_DUPLICATE 0x0020 #define HASHSIZE 77 #define NEGATIVE_TIMEOUT 10 -#define UMOUNT_RETRIES 6 +#define UMOUNT_RETRIES 8 #define EXPIRE_RETRIES 3 struct mapent_cache { diff --git a/lib/master.c b/lib/master.c index 1d66542..a411459 100644 --- a/lib/master.c +++ b/lib/master.c @@ -724,8 +724,8 @@ int master_read_master(struct master *ma master_mutex_lock(); if (list_empty(&master->mounts)) { - error(LOGOPT_ANY, "no mounts in table"); master_mutex_unlock(); + error(LOGOPT_ANY, "no mounts in table"); return 0; } @@ -856,8 +856,9 @@ void master_notify_state_change(struct m struct master_mapent *entry; struct autofs_point *ap; struct list_head *p; - int state_pipe; + int state_pipe, cur_state; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); master_mutex_lock(); list_for_each(p, &master->mounts) { @@ -907,6 +908,7 @@ next: } master_mutex_unlock(); + pthread_setcancelstate(cur_state, NULL); return; } @@ -1065,7 +1067,9 @@ static void check_update_map_sources(str int master_mount_mounts(struct master *master, time_t age, int readall) { struct list_head *p, *head; + int cur_state; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); master_mutex_lock(); head = &master->mounts; @@ -1109,6 +1113,7 @@ int master_mount_mounts(struct master *m } master_mutex_unlock(); + pthread_setcancelstate(cur_state, NULL); return 1; } diff --git a/modules/lookup_file.c b/modules/lookup_file.c index 3588129..1bfdeed 100644 --- a/modules/lookup_file.c +++ b/modules/lookup_file.c @@ -1010,7 +1010,7 @@ int lookup_mount(struct autofs_point *ap cache_readlock(mc); me = cache_lookup(mc, key); - if (me && me->mapent) { + if (me && me->mapent && *me->mapent) { pthread_cleanup_push(cache_lock_cleanup, mc); mapent_len = strlen(me->mapent); mapent = alloca(mapent_len + 1); diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c index c0ced9e..b63539e 100644 --- a/modules/lookup_ldap.c +++ b/modules/lookup_ldap.c @@ -1648,7 +1648,7 @@ int lookup_mount(struct autofs_point *ap cache_readlock(mc); me = cache_lookup(mc, key); - if (me && me->mapent) { + if (me && me->mapent && *me->mapent) { mapent_len = strlen(me->mapent); mapent = alloca(mapent_len + 1); strcpy(mapent, me->mapent); diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c index b0fe4a6..683ec6c 100644 --- a/modules/lookup_nisplus.c +++ b/modules/lookup_nisplus.c @@ -514,7 +514,7 @@ int lookup_mount(struct autofs_point *ap cache_readlock(mc); me = cache_lookup(mc, key); - if (me && me->mapent) { + if (me && me->mapent && *me->mapent) { mapent_len = strlen(me->mapent); mapent = alloca(mapent_len + 1); strcpy(mapent, me->mapent); diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c index 275610a..8dfb9c0 100644 --- a/modules/lookup_yp.c +++ b/modules/lookup_yp.c @@ -598,7 +598,7 @@ int lookup_mount(struct autofs_point *ap cache_readlock(mc); me = cache_lookup(mc, key); - if (me && me->mapent) { + if (me && me->mapent && *me->mapent) { mapent_len = strlen(me->mapent); mapent = alloca(mapent_len + 1); strcpy(mapent, me->mapent);