autofs-5.0.1 - library reload fix update From: Ian Kent <raven@themaw.net> We still have a problem with libxml2 being unloaded before its thread specific data destructor is called. This is due to the main thread exiting (closing the handle we hold open to prevent this) before all the mount handling threads have actually completed. This patch makes the mount handling threads joinable (and joins with them as they exit) to ensure that the mount handling threads have completed before allowing the main thread to complete. --- daemon/automount.c | 50 ++++++++++++++++++++++++++++++++++++------------- daemon/direct.c | 7 +++--- daemon/indirect.c | 7 +++--- daemon/state.c | 7 +++--- include/master.h | 3 ++ lib/master.c | 36 +++++++++++++++++++++++++++++++---- modules/mount_autofs.c | 4 +-- 7 files changed, 86 insertions(+), 28 deletions(-) --- autofs-5.0.1.orig/daemon/automount.c +++ autofs-5.0.1/daemon/automount.c @@ -64,8 +64,9 @@ static int st_stat = 0; static int *pst_stat = &st_stat; static pthread_t state_mach_thid; -/* Attribute to create detached thread */ -pthread_attr_t thread_attr; +/* Attributes for creating detached and joinable threads */ +pthread_attr_t th_attr; +pthread_attr_t th_attr_detached; struct master_readmap_cond mrc = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, NULL, 0, 0, 0, 0}; @@ -1212,7 +1213,7 @@ static pthread_t do_signals(struct maste if (status) fatal(status); - status = pthread_create(&thid, &thread_attr, do_notify_state, &r_sig); + status = pthread_create(&thid, &th_attr_detached, do_notify_state, &r_sig); if (status) { error(master->logopt, "mount state notify thread create failed"); @@ -1301,7 +1302,7 @@ static int do_hup_signal(struct master * master->reading = 1; - status = pthread_create(&thid, &thread_attr, do_read_master, NULL); + status = pthread_create(&thid, &th_attr_detached, do_read_master, NULL); if (status) { error(logopt, "master read map thread create failed"); @@ -1347,8 +1348,22 @@ static void *statemachine(void *arg) case SIGTERM: case SIGINT: case SIGUSR2: - if (master_list_empty(master_list)) - return NULL; + master_mutex_lock(); + if (list_empty(&master_list->completed)) { + if (list_empty(&master_list->mounts)) { + master_mutex_unlock(); + return NULL; + } + } else { + if (master_done(master_list)) { + master_mutex_unlock(); + return NULL; + } + master_mutex_unlock(); + break; + } + master_mutex_unlock(); + case SIGUSR1: do_signals(master_list, sig); break; @@ -1467,8 +1482,6 @@ static void handle_mounts_cleanup(void * master_mutex_unlock(); destroy_logpri_fifo(ap); - master_free_mapent_sources(ap->entry, 1); - master_free_mapent(ap->entry); if (clean) { if (rmdir(path) == -1) { @@ -1480,8 +1493,12 @@ static void handle_mounts_cleanup(void * info(logopt, "shut down path %s", path); - /* If we are the last tell the state machine to shutdown */ - if (!submount && master_list_empty(master_list)) + /* + * If we are not a submount send a signal to the signal handler + * so it can join with any completed handle_mounts() threads and + * perform final cleanup. + */ + if (!submount) pthread_kill(state_mach_thid, SIGTERM); return; @@ -2040,7 +2057,14 @@ int main(int argc, char *argv[]) exit(1); } - if (pthread_attr_init(&thread_attr)) { + if (pthread_attr_init(&th_attr)) { + logerr("%s: failed to init thread attribute struct!", + program); + close(start_pipefd[1]); + exit(1); + } + + if (pthread_attr_init(&th_attr_detached)) { logerr("%s: failed to init thread attribute struct!", program); close(start_pipefd[1]); @@ -2048,7 +2072,7 @@ int main(int argc, char *argv[]) } if (pthread_attr_setdetachstate( - &thread_attr, PTHREAD_CREATE_DETACHED)) { + &th_attr_detached, PTHREAD_CREATE_DETACHED)) { logerr("%s: failed to set detached thread attribute!", program); close(start_pipefd[1]); @@ -2057,7 +2081,7 @@ int main(int argc, char *argv[]) #ifdef _POSIX_THREAD_ATTR_STACKSIZE if (pthread_attr_setstacksize( - &thread_attr, PTHREAD_STACK_MIN*128)) { + &th_attr_detached, PTHREAD_STACK_MIN*128)) { logerr("%s: failed to set stack size thread attribute!", program); close(start_pipefd[1]); --- autofs-5.0.1.orig/daemon/direct.c +++ autofs-5.0.1/daemon/direct.c @@ -38,7 +38,8 @@ #include "automount.h" -extern pthread_attr_t thread_attr; +/* Attribute to create detached thread */ +extern pthread_attr_t th_attr_detached; struct mnt_params { char *options; @@ -1177,7 +1178,7 @@ int handle_packet_expire_direct(struct a debug(ap->logopt, "token %ld, name %s", (unsigned long) pkt->wait_queue_token, mt->name); - status = pthread_create(&thid, &thread_attr, do_expire_direct, mt); + status = pthread_create(&thid, &th_attr_detached, do_expire_direct, mt); if (status) { error(ap->logopt, "expire thread create failed"); send_fail(ap->logopt, mt->ioctlfd, pkt->wait_queue_token); @@ -1459,7 +1460,7 @@ int handle_packet_missing_direct(struct mt->gid = pkt->gid; mt->wait_queue_token = pkt->wait_queue_token; - status = pthread_create(&thid, &thread_attr, do_mount_direct, mt); + status = pthread_create(&thid, &th_attr_detached, do_mount_direct, mt); if (status) { error(ap->logopt, "missing mount thread create failed"); send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); --- autofs-5.0.1.orig/daemon/indirect.c +++ autofs-5.0.1/daemon/indirect.c @@ -36,7 +36,8 @@ #include "automount.h" -extern pthread_attr_t thread_attr; +/* Attribute to create detached thread */ +extern pthread_attr_t th_attr_detached; static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -669,7 +670,7 @@ int handle_packet_expire_indirect(struct mt->len = pkt->len; mt->wait_queue_token = pkt->wait_queue_token; - status = pthread_create(&thid, &thread_attr, do_expire_indirect, mt); + status = pthread_create(&thid, &th_attr_detached, do_expire_indirect, mt); if (status) { error(ap->logopt, "expire thread create failed"); send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); @@ -838,7 +839,7 @@ int handle_packet_missing_indirect(struc mt->gid = pkt->gid; mt->wait_queue_token = pkt->wait_queue_token; - status = pthread_create(&thid, &thread_attr, do_mount_indirect, mt); + status = pthread_create(&thid, &th_attr_detached, do_mount_indirect, mt); if (status) { error(ap->logopt, "expire thread create failed"); send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); --- autofs-5.0.1.orig/daemon/state.c +++ autofs-5.0.1/daemon/state.c @@ -16,7 +16,8 @@ #include "automount.h" -extern pthread_attr_t thread_attr; +/* Attribute to create detached thread */ +extern pthread_attr_t th_attr_detached; struct state_queue { pthread_t thid; @@ -292,7 +293,7 @@ static enum expire expire_proc(struct au else expire = expire_proc_direct; - status = pthread_create(&thid, &thread_attr, expire, ea); + status = pthread_create(&thid, &th_attr_detached, expire, ea); if (status) { error(ap->logopt, "expire thread create for %s failed", ap->path); @@ -519,7 +520,7 @@ static unsigned int st_readmap(struct au ra->ap = ap; ra->now = now; - status = pthread_create(&thid, &thread_attr, do_readmap, ra); + status = pthread_create(&thid, &th_attr_detached, do_readmap, ra); if (status) { error(ap->logopt, "read map thread create failed"); st_readmap_cleanup(ra); --- autofs-5.0.1.orig/include/master.h +++ autofs-5.0.1/include/master.h @@ -48,6 +48,7 @@ struct master_mapent { struct map_source *maps; struct autofs_point *ap; struct list_head list; + struct list_head join; }; struct master { @@ -61,6 +62,7 @@ struct master { unsigned int logopt; struct mapent_cache *nc; struct list_head mounts; + struct list_head completed; }; /* From the yacc master map parser */ @@ -109,6 +111,7 @@ void master_notify_state_change(struct m int master_mount_mounts(struct master *, time_t, int); extern inline unsigned int master_get_logopt(void); int master_list_empty(struct master *); +int master_done(struct master *); int master_kill(struct master *); #endif --- autofs-5.0.1.orig/lib/master.c +++ autofs-5.0.1/lib/master.c @@ -32,8 +32,8 @@ struct master *master_list = NULL; extern long global_negative_timeout; -/* Attribute to create detached thread */ -extern pthread_attr_t thread_attr; +/* Attribute to create a joinable thread */ +extern pthread_attr_t th_attr; extern struct startup_cond suc; @@ -703,11 +703,16 @@ void master_add_mapent(struct master *ma void master_remove_mapent(struct master_mapent *entry) { + struct master *master = entry->master; + if (entry->ap->submount) return; - if (!list_empty(&entry->list)) + if (!list_empty(&entry->list)) { list_del_init(&entry->list); + list_add(&entry->join, &master->completed); + } + return; } @@ -785,6 +790,7 @@ struct master *master_new(const char *na master->logopt = master->default_logging; INIT_LIST_HEAD(&master->mounts); + INIT_LIST_HEAD(&master->completed); return master; } @@ -992,7 +998,7 @@ static int master_do_mount(struct master debug(ap->logopt, "mounting %s", entry->path); - status = pthread_create(&thid, &thread_attr, handle_mounts, &suc); + status = pthread_create(&thid, &th_attr, handle_mounts, &suc); if (status) { crit(ap->logopt, "failed to create mount handler thread for %s", @@ -1169,6 +1175,28 @@ int master_list_empty(struct master *mas return res; } +int master_done(struct master *master) +{ + struct list_head *head, *p; + struct master_mapent *entry; + int res = 0; + + head = &master->completed; + p = head->next; + while (p != head) { + entry = list_entry(p, struct master_mapent, join); + p = p->next; + list_del(&entry->join); + pthread_join(entry->thid, NULL); + master_free_mapent_sources(entry, 1); + master_free_mapent(entry); + } + if (list_empty(&master->mounts)) + res = 1; + + return res; +} + inline unsigned int master_get_logopt(void) { return master_list ? master_list->logopt : LOGOPT_NONE; --- autofs-5.0.1.orig/modules/mount_autofs.c +++ autofs-5.0.1/modules/mount_autofs.c @@ -32,7 +32,7 @@ #define MODPREFIX "mount(autofs): " /* Attribute to create detached thread */ -extern pthread_attr_t thread_attr; +extern pthread_attr_t th_attr_detached; extern struct startup_cond suc; int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */ @@ -232,7 +232,7 @@ int mount_mount(struct autofs_point *ap, suc.done = 0; suc.status = 0; - if (pthread_create(&thid, &thread_attr, handle_mounts, &suc)) { + if (pthread_create(&thid, &th_attr_detached, handle_mounts, &suc)) { crit(ap->logopt, MODPREFIX "failed to create mount handler thread for %s",