unchanged: --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ - allow syntax "--timeout " for backward compatibility. - make masked_match independent of hostname for exports comparison. - fix file handle leak in nsswitch parser. +- fix memory leak in mount and expire request processing. 1/9/2006 autofs-5.0.1 rc2 ------------------------- diff -u b/daemon/direct.c b/daemon/direct.c --- b/daemon/direct.c +++ b/daemon/direct.c @@ -50,6 +50,9 @@ pthread_key_t key_mnt_offset_params; pthread_once_t key_mnt_params_once = PTHREAD_ONCE_INIT; +static pthread_mutex_t ma_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER; + static void key_mnt_params_destroy(void *arg) { struct mnt_params *mp; @@ -797,6 +800,7 @@ { struct mnt_list *mnts = NULL, *next; struct expire_args *ea; + struct expire_args ec; struct autofs_point *ap; struct mapent *me = NULL; unsigned int now; @@ -809,26 +813,21 @@ if (status) fatal(status); - ap = ea->ap; + ap = ec.ap = ea->ap; now = ea->when; - ea->status = -1; + ec.status = -1; ea->signaled = 1; status = pthread_cond_signal(&ea->cond); - if (status) { - error(ap->logopt, "failed to signal expire condition"); - status = pthread_mutex_unlock(&ea->mutex); - if (status) - fatal(status); - pthread_exit(NULL); - } - - pthread_cleanup_push(expire_cleanup, ea); + if (status) + fatal(status); status = pthread_mutex_unlock(&ea->mutex); if (status) fatal(status); + pthread_cleanup_push(expire_cleanup, &ec); + left = 0; /* Get a list of real mounts and expire them if possible */ @@ -883,7 +882,7 @@ } pthread_cleanup_pop(1); - ea->status = left; + ec.status = left; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); pthread_cleanup_pop(1); @@ -892,24 +891,15 @@ return NULL; } -void pending_cleanup(void *arg) +static void pending_cond_destroy(void *arg) { struct pending_args *mt; int status; mt = (struct pending_args *) arg; - - status = pthread_mutex_unlock(&mt->mutex); - if (status) - fatal(status); - status = pthread_cond_destroy(&mt->cond); if (status) fatal(status); - - status = pthread_mutex_destroy(&mt->mutex); - if (status) - fatal(status); } static void expire_send_fail(void *arg) @@ -918,6 +908,19 @@ send_fail(mt->ioctlfd, mt->wait_queue_token); } +static void free_pending_args(void *arg) +{ + struct pending_args *mt = arg; + free(mt); +} + +static void expire_mutex_unlock(void *arg) +{ + int status = pthread_mutex_unlock(&ea_mutex); + if (status) + fatal(status); +} + static void *do_expire_direct(void *arg) { struct pending_args *mt; @@ -927,9 +930,7 @@ mt = (struct pending_args *) arg; - pthread_cleanup_push(expire_send_fail, mt); - - status = pthread_mutex_lock(&mt->mutex); + status = pthread_mutex_lock(&ea_mutex); if (status) fatal(status); @@ -940,9 +941,11 @@ if (status) fatal(status); - status = pthread_mutex_unlock(&mt->mutex); - 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); len = _strlen(mt->name, KEY_MAX_LEN); if (!len) { @@ -967,6 +970,9 @@ pthread_setcancelstate(state, NULL); pthread_cleanup_pop(0); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + return NULL; } @@ -1027,15 +1033,11 @@ return 1; } - status = pthread_mutex_init(&mt->mutex, NULL); - if (status) - fatal(status); - status = pthread_cond_init(&mt->cond, NULL); if (status) fatal(status); - status = pthread_mutex_lock(&mt->mutex); + status = pthread_mutex_lock(&ea_mutex); if (status) fatal(status); @@ -1054,26 +1056,29 @@ status = pthread_create(&thid, &thread_attr, do_expire_direct, mt); if (status) { error(ap->logopt, "expire thread create failed"); - free(mt); send_fail(mt->ioctlfd, pkt->wait_queue_token); cache_unlock(mc); - pending_cleanup(mt); + expire_mutex_unlock(NULL); + pending_cond_destroy(mt); + free_pending_args(mt); pthread_setcancelstate(state, NULL); return 1; } cache_unlock(mc); - pthread_cleanup_push(pending_cleanup, mt); + + pthread_cleanup_push(expire_mutex_unlock, NULL); pthread_setcancelstate(state, NULL); mt->signaled = 0; while (!mt->signaled) { - status = pthread_cond_wait(&mt->cond, &mt->mutex); + status = pthread_cond_wait(&mt->cond, &ea_mutex); if (status) fatal(status); } pthread_cleanup_pop(1); + return 0; } @@ -1084,6 +1089,13 @@ close(mt->ioctlfd); } +static void mount_mutex_unlock(void *arg) +{ + int status = pthread_mutex_unlock(&ma_mutex); + if (status) + fatal(status); +} + static void *do_mount_direct(void *arg) { struct pending_args *mt; @@ -1102,7 +1114,7 @@ mt = (struct pending_args *) arg; - status = pthread_mutex_lock(&mt->mutex); + status = pthread_mutex_lock(&ma_mutex); if (status) fatal(status); @@ -1113,11 +1125,12 @@ if (status) fatal(status); - status = pthread_mutex_unlock(&mt->mutex); - if (status) - fatal(status); + mount_mutex_unlock(NULL); + pthread_cleanup_push(free_pending_args, mt); + pthread_cleanup_push(pending_cond_destroy, mt); pthread_cleanup_push(mount_send_fail, mt); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); status = fstat(mt->ioctlfd, &st); @@ -1271,6 +1284,9 @@ pthread_setcancelstate(state, NULL); pthread_cleanup_pop(0); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + return NULL; } @@ -1353,23 +1369,19 @@ pthread_setcancelstate(state, NULL); return 1; } - - status = pthread_mutex_init(&mt->mutex, NULL); - if (status) - fatal(status); + memset(mt, 0, sizeof(struct pending_args)); status = pthread_cond_init(&mt->cond, NULL); if (status) fatal(status); - status = pthread_mutex_lock(&mt->mutex); + status = pthread_mutex_lock(&ma_mutex); if (status) fatal(status); mt->ap = ap; mt->ioctlfd = ioctlfd; mt->mc = mc; - /* TODO: check length here */ strcpy(mt->name, me->key); mt->dev = me->dev; mt->type = NFY_MOUNT; @@ -1380,22 +1392,23 @@ status = pthread_create(&thid, &thread_attr, do_mount_direct, mt); if (status) { error(ap->logopt, "missing mount thread create failed"); - free(mt); send_fail(ioctlfd, pkt->wait_queue_token); close(ioctlfd); cache_unlock(mc); - pending_cleanup(mt); + mount_mutex_unlock(NULL); + pending_cond_destroy(mt); + free_pending_args(mt); pthread_setcancelstate(state, NULL); return 1; } cache_unlock(mc); - pthread_cleanup_push(pending_cleanup, mt); + pthread_cleanup_push(mount_mutex_unlock, NULL); pthread_setcancelstate(state, NULL); mt->signaled = 0; while (!mt->signaled) { - status = pthread_cond_wait(&mt->cond, &mt->mutex); + status = pthread_cond_wait(&mt->cond, &ma_mutex); if (status) fatal(status); } diff -u b/daemon/indirect.c b/daemon/indirect.c --- b/daemon/indirect.c +++ b/daemon/indirect.c @@ -40,6 +40,9 @@ extern pthread_attr_t thread_attr; +static pthread_mutex_t ma_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER; + static int autofs_init_indirect(struct autofs_point *ap) { int pipefd[2]; @@ -419,6 +422,7 @@ struct mapent *me = NULL; struct mnt_list *mnts = NULL, *next; struct expire_args *ea; + struct expire_args ec; unsigned int now; int offsets, submnts, count; int ioctlfd, cur_state; @@ -430,26 +434,21 @@ if (status) fatal(status); - ap = ea->ap; + ap = ec.ap = ea->ap; now = ea->when; - ea->status = -1; + ec.status = -1; ea->signaled = 1; status = pthread_cond_signal(&ea->cond); - if (status) { - error(ap->logopt, "failed to signal expire condition"); - status = pthread_mutex_unlock(&ea->mutex); - if (status) - fatal(status); - pthread_exit(NULL); - } - - pthread_cleanup_push(expire_cleanup, ea); + if (status) + fatal(status); status = pthread_mutex_unlock(&ea->mutex); if (status) fatal(status); + pthread_cleanup_push(expire_cleanup, &ec); + left = 0; /* Get a list of real mounts and expire them if possible */ @@ -559,7 +558,7 @@ msg("mount still busy %s", ap->path); } - ea->status = left; + ec.status = left; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); pthread_cleanup_pop(1); @@ -568,8 +567,16 @@ return NULL; } -/* See direct.c */ -extern void pending_cleanup(void *); +static void pending_cond_destroy(void *arg) +{ + struct pending_args *mt; + int status; + + mt = (struct pending_args *) arg; + status = pthread_cond_destroy(&mt->cond); + if (status) + fatal(status); +} static void expire_send_fail(void *arg) { @@ -577,6 +584,19 @@ send_fail(mt->ap->ioctlfd, mt->wait_queue_token); } +static void free_pending_args(void *arg) +{ + struct pending_args *mt = arg; + free(mt); +} + +static void expire_mutex_unlock(void *arg) +{ + int status = pthread_mutex_unlock(&ea_mutex); + if (status) + fatal(status); +} + static void *do_expire_indirect(void *arg) { struct pending_args *mt; @@ -585,7 +605,7 @@ mt = (struct pending_args *) arg; - status = pthread_mutex_lock(&mt->mutex); + status = pthread_mutex_lock(&ea_mutex); if (status) fatal(status); @@ -596,10 +616,10 @@ if (status) fatal(status); - status = pthread_mutex_unlock(&mt->mutex); - 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); status = do_expire(mt->ap, mt->name, mt->len); @@ -611,6 +631,8 @@ pthread_setcancelstate(state, NULL); pthread_cleanup_pop(0); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); return NULL; } @@ -636,15 +658,11 @@ return 1; } - status = pthread_mutex_init(&mt->mutex, NULL); - if (status) - fatal(status); - status = pthread_cond_init(&mt->cond, NULL); if (status) fatal(status); - status = pthread_mutex_lock(&mt->mutex); + status = pthread_mutex_lock(&ea_mutex); if (status) fatal(status); @@ -658,18 +676,19 @@ if (status) { error(ap->logopt, "expire thread create failed"); send_fail(ap->ioctlfd, pkt->wait_queue_token); - free(mt); - pending_cleanup(mt); + expire_mutex_unlock(NULL); + pending_cond_destroy(mt); + free_pending_args(mt); pthread_setcancelstate(state, NULL); return 1; } - pthread_cleanup_push(pending_cleanup, mt); + pthread_cleanup_push(expire_mutex_unlock, NULL); pthread_setcancelstate(state, NULL); mt->signaled = 0; while (!mt->signaled) { - status = pthread_cond_wait(&mt->cond, &mt->mutex); + status = pthread_cond_wait(&mt->cond, &ea_mutex); if (status) fatal(status); } @@ -685,6 +704,13 @@ send_fail(mt->ap->ioctlfd, mt->wait_queue_token); } +static void mount_mutex_unlock(void *arg) +{ + int status = pthread_mutex_unlock(&ma_mutex); + if (status) + fatal(status); +} + static void *do_mount_indirect(void *arg) { struct pending_args *mt; @@ -703,7 +729,7 @@ mt = (struct pending_args *) arg; - status = pthread_mutex_lock(&mt->mutex); + status = pthread_mutex_lock(&ma_mutex); if (status) fatal(status); @@ -715,16 +741,17 @@ if (status) fatal(status); - status = pthread_mutex_unlock(&mt->mutex); - if (status) - fatal(status); + mount_mutex_unlock(NULL); + + pthread_cleanup_push(free_pending_args, mt); + pthread_cleanup_push(pending_cond_destroy, mt); + pthread_cleanup_push(mount_send_fail, mt); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); len = ncat_path(buf, sizeof(buf), ap->path, mt->name, mt->len); if (!len) { crit(ap->logopt, "path to be mounted is to long"); - send_fail(ap->ioctlfd, mt->wait_queue_token); pthread_setcancelstate(state, NULL); pthread_exit(NULL); } @@ -733,12 +760,10 @@ if (status != -1 && !(S_ISDIR(st.st_mode) && st.st_dev == mt->dev)) { error(ap->logopt, "indirect trigger not valid or already mounted %s", buf); - send_fail(ap->ioctlfd, mt->wait_queue_token); pthread_setcancelstate(state, NULL); pthread_exit(NULL); } - pthread_cleanup_push(mount_send_fail, mt); pthread_setcancelstate(state, NULL); msg("attempting to mount entry %s", buf); @@ -862,6 +887,9 @@ pthread_setcancelstate(state, NULL); pthread_cleanup_pop(0); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + return NULL; } @@ -894,16 +922,13 @@ pthread_setcancelstate(state, NULL); return 1; } - - status = pthread_mutex_init(&mt->mutex, NULL); - if (status) - fatal(status); + memset(mt, 0, sizeof(struct pending_args)); status = pthread_cond_init(&mt->cond, NULL); if (status) fatal(status); - status = pthread_mutex_lock(&mt->mutex); + status = pthread_mutex_lock(&ma_mutex); if (status) fatal(status); @@ -920,18 +945,19 @@ if (status) { error(ap->logopt, "expire thread create failed"); send_fail(ap->ioctlfd, pkt->wait_queue_token); - free(mt); - pending_cleanup(mt); + mount_mutex_unlock(NULL); + pending_cond_destroy(mt); + free_pending_args(mt); pthread_setcancelstate(state, NULL); return 1; } - pthread_cleanup_push(pending_cleanup, mt); + pthread_cleanup_push(mount_mutex_unlock, NULL); pthread_setcancelstate(state, NULL); mt->signaled = 0; while (!mt->signaled) { - status = pthread_cond_wait(&mt->cond, &mt->mutex); + status = pthread_cond_wait(&mt->cond, &ma_mutex); if (status) fatal(status); } unchanged: --- a/daemon/state.c +++ b/daemon/state.c @@ -94,14 +94,14 @@ void nextstate(int statefd, enum states void expire_cleanup(void *arg) { pthread_t thid = pthread_self(); - struct expire_args *ea; + struct expire_args *ec; struct autofs_point *ap; int statefd, success; enum states next = ST_INVAL; - ea = (struct expire_args *) arg; - ap = ea->ap; - success = ea->status; + ec = (struct expire_args *) arg; + ap = ec->ap; + success = ec->status; state_mutex_lock(ap); @@ -190,8 +190,6 @@ #endif state_mutex_unlock(ap); - free(ea); - return; } @@ -242,6 +240,8 @@ void expire_proc_cleanup(void *arg) if (status) fatal(status); + free(ea); + return; }