autofs-5.0.3 - fix incorrect pthreads condition handling for expire requests. From: Ian Kent Occassionally, when starting an expire thread we can attempt to use the structure for parameter communication after it has been freed. This patch resolves this issue. --- CHANGELOG | 1 + daemon/direct.c | 40 +++++++++++++++++++++------------------- daemon/indirect.c | 28 +++++++++++++++------------- 3 files changed, 37 insertions(+), 32 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9869245..db793d3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,7 @@ - wait submount expire thread completion. - add missing uris list locking. - fix segv during library re-open. +- fix incorrect pthreads condition handling for expire requests. 14/01/2008 autofs-5.0.3 ----------------------- diff --git a/daemon/direct.c b/daemon/direct.c index 5b02dcf..0fcab7f 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -1033,55 +1033,53 @@ static void expire_mutex_unlock(void *arg) static void *do_expire_direct(void *arg) { - struct pending_args *mt; + struct pending_args *args, mt; struct autofs_point *ap; size_t len; int status, state; - mt = (struct pending_args *) arg; + args = (struct pending_args *) arg; status = pthread_mutex_lock(&ea_mutex); if (status) fatal(status); - ap = mt->ap; + memcpy(&mt, args, sizeof(struct pending_args)); - mt->signaled = 1; - status = pthread_cond_signal(&mt->cond); + ap = mt.ap; + + args->signaled = 1; + status = pthread_cond_signal(&args->cond); if (status) fatal(status); expire_mutex_unlock(NULL); - pthread_cleanup_push(free_pending_args, mt); - pthread_cleanup_push(pending_cond_destroy, mt); - pthread_cleanup_push(expire_send_fail, mt); + pthread_cleanup_push(expire_send_fail, &mt); - len = _strlen(mt->name, KEY_MAX_LEN); + len = _strlen(mt.name, KEY_MAX_LEN); if (!len) { - warn(ap->logopt, "direct key path too long %s", mt->name); + warn(ap->logopt, "direct key path too long %s", mt.name); /* TODO: force umount ?? */ pthread_exit(NULL); } - status = do_expire(ap, mt->name, len); + status = do_expire(ap, mt.name, len); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); if (status) - send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token); + send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token); else { struct mapent *me; - cache_readlock(mt->mc); - me = cache_lookup_distinct(mt->mc, mt->name); + cache_readlock(mt.mc); + me = cache_lookup_distinct(mt.mc, mt.name); me->ioctlfd = -1; - cache_unlock(mt->mc); - send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token); - close(mt->ioctlfd); + cache_unlock(mt.mc); + send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); + close(mt.ioctlfd); } pthread_setcancelstate(state, NULL); pthread_cleanup_pop(0); - pthread_cleanup_pop(1); - pthread_cleanup_pop(1); return NULL; } @@ -1198,6 +1196,8 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di cache_unlock(mc); master_source_unlock(ap->entry); + pthread_cleanup_push(free_pending_args, mt); + pthread_cleanup_push(pending_cond_destroy, mt); pthread_cleanup_push(expire_mutex_unlock, NULL); pthread_setcancelstate(state, NULL); @@ -1212,6 +1212,8 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di } pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); return 0; } diff --git a/daemon/indirect.c b/daemon/indirect.c index 168d915..90f8f63 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -596,40 +596,38 @@ static void expire_mutex_unlock(void *arg) static void *do_expire_indirect(void *arg) { - struct pending_args *mt; + struct pending_args *args, mt; struct autofs_point *ap; int status, state; - mt = (struct pending_args *) arg; + args = (struct pending_args *) arg; status = pthread_mutex_lock(&ea_mutex); if (status) fatal(status); - ap = mt->ap; + memcpy(&mt, args, sizeof(struct pending_args)); + + ap = mt.ap; - mt->signaled = 1; - status = pthread_cond_signal(&mt->cond); + args->signaled = 1; + status = pthread_cond_signal(&args->cond); if (status) fatal(status); expire_mutex_unlock(NULL); - pthread_cleanup_push(free_pending_args, mt); - pthread_cleanup_push(pending_cond_destroy, mt); - pthread_cleanup_push(expire_send_fail, mt); + pthread_cleanup_push(expire_send_fail, &mt); - status = do_expire(mt->ap, mt->name, mt->len); + status = do_expire(mt.ap, mt.name, mt.len); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); if (status) - send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token); + send_fail(ap->logopt, ap->ioctlfd, mt.wait_queue_token); else - send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token); + send_ready(ap->logopt, ap->ioctlfd, mt.wait_queue_token); pthread_setcancelstate(state, NULL); pthread_cleanup_pop(0); - pthread_cleanup_pop(1); - pthread_cleanup_pop(1); return NULL; } @@ -682,6 +680,8 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_ return 1; } + pthread_cleanup_push(free_pending_args, mt); + pthread_cleanup_push(pending_cond_destroy, mt); pthread_cleanup_push(expire_mutex_unlock, NULL); pthread_setcancelstate(state, NULL); @@ -696,6 +696,8 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_ } pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); return 0; }