diff --git a/daemon/automount.c b/daemon/automount.c index 086affb..68bf1d3 100644 --- a/daemon/automount.c +++ b/daemon/automount.c @@ -369,6 +369,18 @@ int count_mounts(unsigned logopt, const char *path, dev_t dev) static void check_rm_dirs(struct autofs_point *ap, const char *path, int incl) { + /* + * If we're a submount the kernel can't know we're trying to + * shutdown and so cannot block processes walking into the + * mount point directory. If this is the call to umount_multi() + * made during shutdown (incl == 0) we have to leave any mount + * point directories in place so we can recover if needed. The + * umount itself will clean these directories up for us + * automagically. + */ + if (!incl && ap->submount) + return; + if ((!ap->ghost) || (ap->state == ST_SHUTDOWN_PENDING || ap->state == ST_SHUTDOWN_FORCE || @@ -390,8 +402,6 @@ static void update_map_cache(struct autofs_point *ap, const char *path) else key = path; - pthread_cleanup_push(master_source_lock_cleanup, ap->entry); - master_source_readlock(ap->entry); map = ap->entry->maps; while (map) { struct mapent *me = NULL; @@ -413,7 +423,6 @@ static void update_map_cache(struct autofs_point *ap, const char *path) map = map->next; } - pthread_cleanup_pop(1); return; } @@ -918,38 +927,22 @@ static int get_pkt(struct autofs_point *ap, union autofs_v5_packet_union *pkt) } if (fds[1].revents & POLLIN) { - enum states next_state, post_state; + enum states next_state; size_t read_size = sizeof(next_state); int state_pipe; - next_state = post_state = ST_INVAL; + next_state = ST_INVAL; - state_mutex_lock(ap); + st_mutex_lock(); state_pipe = ap->state_pipe[0]; if (fullread(state_pipe, &next_state, read_size)) { - state_mutex_unlock(ap); + st_mutex_unlock(); continue; } - if (next_state != ST_INVAL && next_state != ap->state) { - if (next_state != ST_SHUTDOWN) - post_state = next_state; - else - ap->state = ST_SHUTDOWN; - } - - state_mutex_unlock(ap); - - if (post_state != ST_INVAL) { - if (post_state == ST_SHUTDOWN_PENDING || - post_state == ST_SHUTDOWN_FORCE) { - alarm_delete(ap); - st_remove_tasks(ap); - } - st_add_task(ap, post_state); - } + st_mutex_unlock(); if (next_state == ST_SHUTDOWN) return -1; @@ -985,11 +978,14 @@ int do_expire(struct autofs_point *ap, const char *name, int namelen) info(ap->logopt, "expiring path %s", buf); + pthread_cleanup_push(master_source_lock_cleanup, ap->entry); + master_source_readlock(ap->entry); ret = umount_multi(ap, buf, 1); if (ret == 0) info(ap->logopt, "expired %s", buf); else warn(ap->logopt, "couldn't complete expire of %s", buf); + pthread_cleanup_pop(1); return ret; } @@ -1069,7 +1065,7 @@ static int mount_autofs(struct autofs_point *ap) if (status < 0) return -1; - ap->state = ST_READY; + st_add_task(ap, ST_READY); return 0; } @@ -1423,44 +1419,6 @@ static void return_start_status(void *arg) fatal(status); } -static void mutex_operation_wait(pthread_mutex_t *mutex) -{ - int status; - - /* - * Unlock a mutex, but wait for a pending operation - * if one is in progress - */ - status = pthread_mutex_trylock(mutex); - if (status) { - if (status == EBUSY) { - /* Mutex locked - do we own it */ - status = pthread_mutex_unlock(mutex); - if (status) { - if (status != EPERM) - fatal(status); - } else - return; - - status = pthread_mutex_lock(mutex); - if (status) - fatal(status); - } else - fatal(status); - - /* Operation complete, release it */ - status = pthread_mutex_unlock(mutex); - if (status) - fatal(status); - } else { - status = pthread_mutex_unlock(mutex); - if (status) - fatal(status); - } - - return; -} - int handle_mounts_startup_cond_init(struct startup_cond *suc) { int status; @@ -1526,22 +1484,25 @@ static void handle_mounts_cleanup(void *arg) if (!submount && strcmp(ap->path, "/-") && ap->dir_created) clean = 1; - /* If we have been canceled then we may hold the state mutex. */ - mutex_operation_wait(&ap->state_mutex); + if (submount) { + /* We are finishing up */ + ap->parent->submnt_count--; + list_del_init(&ap->mounts); + } - alarm_delete(ap); - st_remove_tasks(ap); + master_remove_mapent(ap->entry); + master_source_unlock(ap->entry); - umount_autofs(ap, 1); + if (submount) { + mounts_mutex_unlock(ap->parent); + master_source_unlock(ap->parent->entry); + } + master_mutex_unlock(); destroy_logpri_fifo(ap); - master_signal_submount(ap, MASTER_SUBMNT_JOIN); - master_remove_mapent(ap->entry); master_free_mapent_sources(ap->entry, 1); master_free_mapent(ap->entry); - sched_yield(); - if (clean) { if (rmdir(path) == -1) { char *estr = strerror_r(errno, buf, MAX_ERR_BUF); @@ -1572,8 +1533,6 @@ void *handle_mounts(void *arg) pthread_cleanup_push(return_start_status, suc); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); - state_mutex_lock(ap); - status = pthread_mutex_lock(&suc->mutex); if (status) { logerr("failed to lock startup condition mutex!"); @@ -1583,7 +1542,6 @@ void *handle_mounts(void *arg) if (mount_autofs(ap) < 0) { crit(ap->logopt, "mount of %s failed!", ap->path); suc->status = 1; - state_mutex_unlock(ap); umount_autofs(ap, 1); pthread_setcancelstate(cancel_state, NULL); pthread_exit(NULL); @@ -1600,56 +1558,70 @@ void *handle_mounts(void *arg) if (!ap->submount && ap->exp_timeout) alarm_add(ap, ap->exp_runfreq + rand() % ap->exp_runfreq); - pthread_cleanup_push(handle_mounts_cleanup, ap); pthread_setcancelstate(cancel_state, NULL); - state_mutex_unlock(ap); - while (ap->state != ST_SHUTDOWN) { if (handle_packet(ap)) { - int ret, result; + int ret, cur_state; + + /* + * If we're a submount we need to ensure our parent + * doesn't try to mount us again until our shutdown + * is complete and that any outstanding mounts are + * completed before we try to shutdown. + */ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); + + master_mutex_lock(); + + if (ap->submount) { + master_source_writelock(ap->parent->entry); + mounts_mutex_lock(ap->parent); + } + + master_source_writelock(ap->entry); + + if (ap->state != ST_SHUTDOWN) { + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); + /* Return to ST_READY is done immediately */ + st_add_task(ap, ST_READY); + master_source_unlock(ap->entry); + if (ap->submount) { + mounts_mutex_unlock(ap->parent); + master_source_unlock(ap->parent->entry); + } + + master_mutex_unlock(); + + pthread_setcancelstate(cur_state, NULL); + continue; + } + + alarm_delete(ap); + st_remove_tasks(ap); + st_wait_task(ap, ST_ANY, 0); - state_mutex_lock(ap); /* * For a direct mount map all mounts have already gone - * by the time we get here. + * by the time we get here and since we only ever + * umount direct mounts at shutdown there is no need + * to check for possible recovery. */ if (ap->type == LKP_DIRECT) { - status = 1; - state_mutex_unlock(ap); + umount_autofs(ap, 1); break; } /* - * If the ioctl fails assume the kernel doesn't have - * AUTOFS_IOC_ASKUMOUNT and just continue. + * If umount_autofs returns non-zero it wasn't able + * to complete the umount and has left the mount intact + * so we can continue. This can happen if a lookup + * occurs while we're trying to umount. */ - ret = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &result); - if (ret == -1) { - state_mutex_unlock(ap); + ret = umount_autofs(ap, 1); + if (!ret) break; - } - - /* OK to exit */ - 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 */ warn(ap->logopt, @@ -1657,14 +1629,22 @@ void *handle_mounts(void *arg) ap->path); if (!ap->submount) alarm_add(ap, ap->exp_runfreq); - nextstate(ap->state_pipe[1], ST_READY); + /* Return to ST_READY is done immediately */ + st_add_task(ap, ST_READY); + master_source_unlock(ap->entry); + if (ap->submount) { + mounts_mutex_unlock(ap->parent); + master_source_unlock(ap->parent->entry); + } + + master_mutex_unlock(); + + pthread_setcancelstate(cur_state, NULL); - state_mutex_unlock(ap); } } - pthread_cleanup_pop(1); - sched_yield(); + handle_mounts_cleanup(ap); return NULL; } diff --git a/daemon/direct.c b/daemon/direct.c index a3869a5..334a4b6 100644 --- a/daemon/direct.c +++ b/daemon/direct.c @@ -216,8 +216,6 @@ int umount_autofs_direct(struct autofs_point *ap) mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/"); pthread_cleanup_push(mnts_cleanup, mnts); - pthread_cleanup_push(master_source_lock_cleanup, ap->entry); - master_source_readlock(ap->entry); nc = ap->entry->master->nc; cache_readlock(nc); pthread_cleanup_push(cache_lock_cleanup, nc); @@ -244,7 +242,6 @@ int umount_autofs_direct(struct autofs_point *ap) } pthread_cleanup_pop(1); pthread_cleanup_pop(1); - pthread_cleanup_pop(1); return 0; } @@ -572,9 +569,10 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me) return 1; } else if (!status) { if (ap->state != ST_SHUTDOWN_FORCE) { - error(ap->logopt, - "ask umount returned busy for %s", - me->key); + if (ap->shutdown) + error(ap->logopt, + "ask umount returned busy for %s", + me->key); return 1; } else { me->ioctlfd = -1; @@ -904,7 +902,10 @@ void *expire_proc_direct(void *arg) * All direct mounts must be present in the map * entry cache. */ + pthread_cleanup_push(master_source_lock_cleanup, ap->entry); + master_source_readlock(ap->entry); me = lookup_source_mapent(ap, next->path, LKP_DISTINCT); + pthread_cleanup_pop(1); if (!me) continue; @@ -1110,6 +1111,8 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di struct pending_args *mt; char buf[MAX_ERR_BUF]; pthread_t thid; + struct timespec wait; + struct timeval now; int status, state; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); @@ -1124,7 +1127,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di * and since it got mounted we have to trust that * there is an entry in the cache. */ - master_source_readlock(ap->entry); + master_source_writelock(ap->entry); map = ap->entry->maps; while (map) { mc = map->mc; @@ -1135,7 +1138,6 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di cache_unlock(mc); map = map->next; } - master_source_unlock(ap->entry); if (!me) { /* @@ -1144,10 +1146,28 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di */ crit(ap->logopt, "can't find map entry for (%lu,%lu)", (unsigned long) pkt->dev, (unsigned long) pkt->ino); + cache_unlock(mc); + master_source_unlock(ap->entry); pthread_setcancelstate(state, NULL); return 1; } + /* Can't expire it if it isn't mounted */ + if (me->ioctlfd == -1) { + int ioctlfd = open(me->key, O_RDONLY); + if (ioctlfd == -1) { + crit(ap->logopt, "can't open ioctlfd for %s", + me->key); + pthread_setcancelstate(state, NULL); + return 1; + } + send_ready(ap->logopt, ioctlfd, pkt->wait_queue_token); + close(ioctlfd); + cache_unlock(mc); + master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + return 0; + } mt = malloc(sizeof(struct pending_args)); if (!mt) { @@ -1155,6 +1175,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di error(ap->logopt, "malloc: %s", estr); send_fail(ap->logopt, me->ioctlfd, pkt->wait_queue_token); cache_unlock(mc); + master_source_unlock(ap->entry); pthread_setcancelstate(state, NULL); return 1; } @@ -1184,6 +1205,7 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di error(ap->logopt, "expire thread create failed"); send_fail(ap->logopt, mt->ioctlfd, pkt->wait_queue_token); cache_unlock(mc); + master_source_unlock(ap->entry); expire_mutex_unlock(NULL); pending_cond_destroy(mt); free_pending_args(mt); @@ -1192,14 +1214,18 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di } cache_unlock(mc); + master_source_unlock(ap->entry); pthread_cleanup_push(expire_mutex_unlock, NULL); pthread_setcancelstate(state, NULL); mt->signaled = 0; while (!mt->signaled) { + gettimeofday(&now, NULL); + wait.tv_sec = now.tv_sec + 2; + wait.tv_nsec = now.tv_usec * 1000; status = pthread_cond_wait(&mt->cond, &ea_mutex); - if (status) + if (status && status != ETIMEDOUT) fatal(status); } @@ -1263,6 +1289,9 @@ static void *do_mount_direct(void *arg) if (status == -1) { error(ap->logopt, "can't stat direct mount trigger %s", mt.name); + send_fail(ap->logopt, + mt.ioctlfd, mt.wait_queue_token); + close(mt.ioctlfd); pthread_setcancelstate(state, NULL); pthread_exit(NULL); } @@ -1272,6 +1301,8 @@ static void *do_mount_direct(void *arg) error(ap->logopt, "direct trigger not valid or already mounted %s", mt.name); + send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); + close(mt.ioctlfd); pthread_setcancelstate(state, NULL); pthread_exit(NULL); } @@ -1290,19 +1321,12 @@ static void *do_mount_direct(void *arg) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); if (status) { struct mapent *me; - int real_mount, set_fd; - cache_readlock(mt.mc); + cache_writelock(mt.mc); me = cache_lookup_distinct(mt.mc, mt.name); - real_mount = is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL); - set_fd = (real_mount || me->multi == me); - cache_unlock(mt.mc); - if (set_fd) { + if (me) me->ioctlfd = mt.ioctlfd; - send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); - } else { - send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); - close(mt.ioctlfd); - } + send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); + cache_unlock(mt.mc); info(ap->logopt, "mounted %s", mt.name); } else { send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token); @@ -1325,11 +1349,21 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ struct pending_args *mt; char buf[MAX_ERR_BUF]; int status = 0; + struct timespec wait; + struct timeval now; int ioctlfd, len, cl_flags, state; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); - master_source_readlock(ap->entry); + /* + * If our parent is a direct or offset mount that has been + * covered by a mount and another lookup occurs after the + * mount but before the device and inode are set in the + * cache entry we will not be able to find the mapent. So + * we must take the source writelock to ensure the parent + * has mount is complete before we look for the entry. + */ + master_source_writelock(ap->entry); map = ap->entry->maps; while (map) { /* @@ -1349,7 +1383,6 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ cache_unlock(mc); map = map->next; } - master_source_unlock(ap->entry); if (!me) { /* @@ -1358,6 +1391,8 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ */ logerr("can't find map entry for (%lu,%lu)", (unsigned long) pkt->dev, (unsigned long) pkt->ino); + cache_unlock(mc); + master_source_unlock(ap->entry); pthread_setcancelstate(state, NULL); return 1; } @@ -1371,6 +1406,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ if (ioctlfd == -1) { cache_unlock(mc); + master_source_unlock(ap->entry); pthread_setcancelstate(state, NULL); crit(ap->logopt, "failed to create ioctl fd for %s", me->key); /* TODO: how do we clear wait q in kernel ?? */ @@ -1386,12 +1422,11 @@ 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->shutdown || - ap->state == ST_SHUTDOWN_FORCE || - ap->state == ST_SHUTDOWN) { + if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) { send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); close(ioctlfd); cache_unlock(mc); + master_source_unlock(ap->entry); pthread_setcancelstate(state, NULL); return 1; } @@ -1402,6 +1437,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); close(ioctlfd); cache_unlock(mc); + master_source_unlock(ap->entry); pthread_setcancelstate(state, NULL); return 1; } @@ -1413,6 +1449,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); close(ioctlfd); cache_unlock(mc); + master_source_unlock(ap->entry); pthread_setcancelstate(state, NULL); return 1; } @@ -1447,6 +1484,7 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); close(ioctlfd); cache_unlock(mc); + master_source_unlock(ap->entry); mount_mutex_unlock(mt); pending_cond_destroy(mt); pending_mutex_destroy(mt); @@ -1456,6 +1494,8 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ } cache_unlock(mc); + master_source_unlock(ap->entry); + pthread_cleanup_push(free_pending_args, mt); pthread_cleanup_push(pending_mutex_destroy, mt); pthread_cleanup_push(pending_cond_destroy, mt); @@ -1464,8 +1504,11 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ mt->signaled = 0; while (!mt->signaled) { - status = pthread_cond_wait(&mt->cond, &mt->mutex); - if (status) + gettimeofday(&now, NULL); + wait.tv_sec = now.tv_sec + 2; + wait.tv_nsec = now.tv_usec * 1000; + status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait); + if (status && status != ETIMEDOUT) fatal(status); } diff --git a/daemon/indirect.c b/daemon/indirect.c index 3922f3f..17bed3e 100644 --- a/daemon/indirect.c +++ b/daemon/indirect.c @@ -230,11 +230,8 @@ int mount_autofs_indirect(struct autofs_point *ap) return 0; } -int umount_autofs_indirect(struct autofs_point *ap) +static void close_mount_fds(struct autofs_point *ap) { - char buf[MAX_ERR_BUF]; - int ret, rv, retries; - /* * Since submounts look after themselves the parent never knows * it needs to close the ioctlfd for offset mounts so we have @@ -244,6 +241,25 @@ int umount_autofs_indirect(struct autofs_point *ap) if (ap->submount) lookup_source_close_ioctlfd(ap->parent, ap->path); + close(ap->state_pipe[0]); + close(ap->state_pipe[1]); + ap->state_pipe[0] = -1; + ap->state_pipe[1] = -1; + + if (ap->pipefd >= 0) + close(ap->pipefd); + + if (ap->kpipefd >= 0) + close(ap->kpipefd); + + return; +} + +int umount_autofs_indirect(struct autofs_point *ap) +{ + char buf[MAX_ERR_BUF]; + int ret, rv, retries; + /* If we are trying to shutdown make sure we can umount */ rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret); if (rv == -1) { @@ -251,24 +267,20 @@ int umount_autofs_indirect(struct autofs_point *ap) logerr("ioctl failed: %s", estr); return 1; } else if (!ret) { +#if defined(ENABLE_IGNORE_BUSY_MOUNTS) || defined(ENABLE_FORCED_SHUTDOWN) + if (!ap->shutdown) + return 1; error(ap->logopt, "ask umount returned busy %s", ap->path); +#else return 1; +#endif } - ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0); + if (ap->shutdown) + ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0); + close(ap->ioctlfd); ap->ioctlfd = -1; - close(ap->state_pipe[0]); - close(ap->state_pipe[1]); - ap->state_pipe[0] = -1; - ap->state_pipe[1] = -1; - - if (ap->pipefd >= 0) - close(ap->pipefd); - - if (ap->kpipefd >= 0) - close(ap->kpipefd); - sched_yield(); retries = UMOUNT_RETRIES; @@ -285,24 +297,61 @@ int umount_autofs_indirect(struct autofs_point *ap) case EINVAL: error(ap->logopt, "mount point %s does not exist", ap->path); + close_mount_fds(ap); return 0; break; case EBUSY: - error(ap->logopt, + debug(ap->logopt, "mount point %s is in use", ap->path); - if (ap->state == ST_SHUTDOWN_FORCE) + if (ap->state == ST_SHUTDOWN_FORCE) { + close_mount_fds(ap); goto force_umount; - else - return 0; + } else { + int cl_flags; + /* + * If the umount returns EBUSY there may be + * a mount request in progress so we need to + * recover unless we have been explicitly + * asked to shutdown and configure option + * ENABLE_IGNORE_BUSY_MOUNTS is enabled. + */ +#ifdef ENABLE_IGNORE_BUSY_MOUNTS + if (ap->shutdown) { + close_mount_fds(ap); + return 0; + } +#endif + ap->ioctlfd = open(ap->path, O_RDONLY); + if (ap->ioctlfd < 0) { + warn(ap->logopt, + "could not recover autofs path %s", + ap->path); + close_mount_fds(ap); + return 0; + } + + if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) != -1) { + cl_flags |= FD_CLOEXEC; + fcntl(ap->ioctlfd, F_SETFD, cl_flags); + } + } break; case ENOTDIR: error(ap->logopt, "mount point is not a directory"); + close_mount_fds(ap); return 0; break; } return 1; } + /* + * We have successfully umounted the mount so we now close + * the descriptors. The kernel end of the kernel pipe will + * have been put during the umount super block cleanup. + */ + close_mount_fds(ap); + force_umount: if (rv != 0) { warn(ap->logopt, @@ -439,9 +488,12 @@ void *expire_proc_indirect(void *arg) * Otherwise it's a top level indirect mount (possibly * with offsets in it) and we use the usual ioctlfd. */ + pthread_cleanup_push(master_source_lock_cleanup, ap->entry); + master_source_readlock(ap->entry); me = lookup_source_mapent(ap, next->path, LKP_DISTINCT); if (!me && ind_key) me = lookup_source_mapent(ap, ind_key, LKP_NORMAL); + pthread_cleanup_pop(1); if (!me) continue; @@ -586,6 +638,8 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_ struct pending_args *mt; char buf[MAX_ERR_BUF]; pthread_t thid; + struct timespec wait; + struct timeval now; int status, state; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); @@ -632,8 +686,11 @@ int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_ mt->signaled = 0; while (!mt->signaled) { - status = pthread_cond_wait(&mt->cond, &ea_mutex); - if (status) + gettimeofday(&now, NULL); + wait.tv_sec = now.tv_sec + 2; + wait.tv_nsec = now.tv_usec * 1000; + status = pthread_cond_timedwait(&mt->cond, &ea_mutex, &wait); + if (status && status != ETIMEDOUT) fatal(status); } @@ -735,6 +792,8 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin pthread_t thid; char buf[MAX_ERR_BUF]; struct pending_args *mt; + struct timespec wait; + struct timeval now; int status, state; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); @@ -743,9 +802,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->shutdown || - ap->state == ST_SHUTDOWN_FORCE || - ap->state == ST_SHUTDOWN) { + if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) { send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); pthread_setcancelstate(state, NULL); return 0; @@ -802,8 +859,11 @@ int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missin mt->signaled = 0; while (!mt->signaled) { - status = pthread_cond_wait(&mt->cond, &mt->mutex); - if (status) + gettimeofday(&now, NULL); + wait.tv_sec = now.tv_sec + 2; + wait.tv_nsec = now.tv_usec * 1000; + status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait); + if (status && status != ETIMEDOUT) fatal(status); } diff --git a/daemon/lookup.c b/daemon/lookup.c index 2277623..85ac519 100644 --- a/daemon/lookup.c +++ b/daemon/lookup.c @@ -935,16 +935,10 @@ 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; } @@ -1122,7 +1116,6 @@ struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, un struct mapent_cache *mc; struct mapent *me = NULL; - master_source_readlock(entry); map = entry->maps; while (map) { mc = map->mc; @@ -1136,7 +1129,6 @@ struct mapent *lookup_source_mapent(struct autofs_point *ap, const char *key, un cache_unlock(mc); map = map->next; } - master_source_unlock(entry); return me; } @@ -1149,8 +1141,6 @@ int lookup_source_close_ioctlfd(struct autofs_point *ap, const char *key) struct mapent *me; int ret = 0; - pthread_cleanup_push(master_source_lock_cleanup, entry); - master_source_readlock(entry); map = entry->maps; while (map) { mc = map->mc; @@ -1168,7 +1158,6 @@ int lookup_source_close_ioctlfd(struct autofs_point *ap, const char *key) cache_unlock(mc); map = map->next; } - pthread_cleanup_pop(1); return ret; } diff --git a/daemon/state.c b/daemon/state.c index 5804707..122177c 100644 --- a/daemon/state.c +++ b/daemon/state.c @@ -37,19 +37,19 @@ static LIST_HEAD(state_queue); static void st_set_thid(struct autofs_point *, pthread_t); static void st_set_done(struct autofs_point *ap); -#define st_mutex_lock() \ -do { \ - int status = pthread_mutex_lock(&mutex); \ - if (status) \ - fatal(status); \ -} while (0) - -#define st_mutex_unlock() \ -do { \ - int status = pthread_mutex_unlock(&mutex); \ - if (status) \ - fatal(status); \ -} while (0) +void st_mutex_lock(void) +{ + int status = pthread_mutex_lock(&mutex); + if (status) + fatal(status); +} + +void st_mutex_unlock(void) +{ + int status = pthread_mutex_unlock(&mutex); + if (status) + fatal(status); +} int do_mount_autofs_direct(struct autofs_point *, struct mnt_list *, struct mapent *); @@ -96,21 +96,19 @@ void expire_cleanup(void *arg) pthread_t thid = pthread_self(); struct expire_args *ec; struct autofs_point *ap; - int statefd, success; + int success; enum states next = ST_INVAL; ec = (struct expire_args *) arg; ap = ec->ap; success = ec->status; - state_mutex_lock(ap); + st_mutex_lock(); debug(ap->logopt, "got thid %lu path %s stat %d", (unsigned long) thid, ap->path, success); - statefd = ap->state_pipe[1]; - /* Check to see if expire process finished */ if (thid == ap->exp_thread) { int rv, idle; @@ -199,11 +197,11 @@ void expire_cleanup(void *arg) } if (next != ST_INVAL) - nextstate(statefd, next); + __st_add_task(ap, next); st_set_done(ap); - state_mutex_unlock(ap); + st_mutex_unlock(); return; } @@ -216,9 +214,6 @@ static unsigned int st_ready(struct autofs_point *ap) ap->shutdown = 0; ap->state = ST_READY; - if (ap->submount) - master_signal_submount(ap, MASTER_SUBMNT_CONTINUE); - return 1; } @@ -333,18 +328,18 @@ static void do_readmap_cleanup(void *arg) ra = (struct readmap_args *) arg; ap = ra->ap; - ap->readmap_thread = 0; - state_mutex_lock(ap); + st_mutex_lock(); - nextstate(ap->state_pipe[1], ST_READY); + ap->readmap_thread = 0; + st_ready(ap); st_set_done(ap); - state_mutex_unlock(ap); - if (!ap->submount) alarm_add(ap, ap->exp_runfreq); + st_mutex_unlock(); + free(ra); return; @@ -499,10 +494,8 @@ static unsigned int st_readmap(struct autofs_point *ap) ra = malloc(sizeof(struct readmap_args)); if (!ra) { error(ap->logopt, "failed to malloc reamap cond struct"); - state_mutex_lock(ap); - nextstate(ap->state_pipe[1], ST_READY); - state_mutex_unlock(ap); /* It didn't work: return to ready */ + st_ready(ap); if (!ap->submount) alarm_add(ap, ap->exp_runfreq); return 0; @@ -528,10 +521,8 @@ static unsigned int st_readmap(struct autofs_point *ap) error(ap->logopt, "read map thread create failed"); st_readmap_cleanup(ra); free(ra); - state_mutex_lock(ap); - nextstate(ap->state_pipe[1], ST_READY); - state_mutex_unlock(ap); /* It didn't work: return to ready */ + st_ready(ap); if (!ap->submount) alarm_add(ap, ap->exp_runfreq); return 0; @@ -570,7 +561,7 @@ static unsigned int st_prepare_shutdown(struct autofs_point *ap) /* It didn't work: return to ready */ if (!ap->submount) alarm_add(ap, ap->exp_runfreq); - nextstate(ap->state_pipe[1], ST_READY); + st_ready(ap); return 0; case EXP_STARTED: @@ -596,7 +587,7 @@ static unsigned int st_force_shutdown(struct autofs_point *ap) /* It didn't work: return to ready */ if (!ap->submount) alarm_add(ap, ap->exp_runfreq); - nextstate(ap->state_pipe[1], ST_READY); + st_ready(ap); return 0; case EXP_STARTED: @@ -605,6 +596,18 @@ static unsigned int st_force_shutdown(struct autofs_point *ap) return 0; } +static unsigned int st_shutdown(struct autofs_point *ap) +{ + debug(ap->logopt, "state %d path %s", ap->state, ap->path); + + assert(ap->state == ST_SHUTDOWN_PENDING || ap->state == ST_SHUTDOWN_FORCE); + + ap->state = ST_SHUTDOWN; + nextstate(ap->state_pipe[1], ST_SHUTDOWN); + + return 0; +} + static unsigned int st_prune(struct autofs_point *ap) { debug(ap->logopt, "state %d path %s", ap->state, ap->path); @@ -617,7 +620,7 @@ static unsigned int st_prune(struct autofs_point *ap) case EXP_PARTIAL: if (!ap->submount) alarm_add(ap, ap->exp_runfreq); - nextstate(ap->state_pipe[1], ST_READY); + st_ready(ap); return 0; case EXP_STARTED: @@ -638,7 +641,7 @@ static unsigned int st_expire(struct autofs_point *ap) case EXP_PARTIAL: if (!ap->submount) alarm_add(ap, ap->exp_runfreq); - nextstate(ap->state_pipe[1], ST_READY); + st_ready(ap); return 0; case EXP_STARTED: @@ -665,43 +668,35 @@ static struct state_queue *st_alloc_task(struct autofs_point *ap, enum states st return task; } -/* Insert alarm entry on ordered list. */ -int st_add_task(struct autofs_point *ap, enum states state) +/* + * Insert alarm entry on ordered list. + * State queue mutex and ap state mutex, in that order, must be held. + */ +int __st_add_task(struct autofs_point *ap, enum states state) { struct list_head *head; struct list_head *p, *q; struct state_queue *new; - enum states ap_state; unsigned int empty = 1; int status; /* Task termination marker, poke state machine */ if (state == ST_READY) { - state_mutex_lock(ap); st_ready(ap); - state_mutex_unlock(ap); - - st_mutex_lock(); signaled = 1; status = pthread_cond_signal(&cond); if (status) fatal(status); - st_mutex_unlock(); - return 1; } - state_mutex_lock(ap); - ap_state = ap->state; - if (ap_state == ST_SHUTDOWN) { - state_mutex_unlock(ap); + if (ap->state == ST_SHUTDOWN) return 1; - } - state_mutex_unlock(ap); - st_mutex_lock(); + if (state == ST_SHUTDOWN) + return st_shutdown(ap); head = &state_queue; @@ -718,8 +713,8 @@ int st_add_task(struct autofs_point *ap, enum states state) /* Don't add duplicate tasks */ if ((task->state == state && !task->done) || - (ap_state == ST_SHUTDOWN_PENDING || - ap_state == ST_SHUTDOWN_FORCE)) + (ap->state == ST_SHUTDOWN_PENDING || + ap->state == ST_SHUTDOWN_FORCE)) break; /* No pending tasks */ @@ -736,8 +731,8 @@ int st_add_task(struct autofs_point *ap, enum states state) p_task = list_entry(q, struct state_queue, pending); if (p_task->state == state || - (ap_state == ST_SHUTDOWN_PENDING || - ap_state == ST_SHUTDOWN_FORCE)) + (ap->state == ST_SHUTDOWN_PENDING || + ap->state == ST_SHUTDOWN_FORCE)) goto done; } @@ -760,11 +755,24 @@ done: if (status) fatal(status); + return 1; +} + +int st_add_task(struct autofs_point *ap, enum states state) +{ + int ret; + + st_mutex_lock(); + ret = __st_add_task(ap, state); st_mutex_unlock(); - return 1; + return ret; } +/* + * Remove state queue tasks for ap. + * State queue mutex and ap state mutex, in that order, must be held. + */ void st_remove_tasks(struct autofs_point *ap) { struct list_head *head; @@ -772,14 +780,10 @@ void st_remove_tasks(struct autofs_point *ap) struct state_queue *task, *waiting; int status; - st_mutex_lock(); - head = &state_queue; - if (list_empty(head)) { - st_mutex_unlock(); + if (list_empty(head)) return; - } p = head->next; while (p != head) { @@ -816,12 +820,107 @@ void st_remove_tasks(struct autofs_point *ap) if (status) fatal(status); + return; +} + +static int st_task_active(struct autofs_point *ap, enum states state) +{ + struct list_head *head; + struct list_head *p, *q; + struct state_queue *task, *waiting; + unsigned int active = 0; + + st_mutex_lock(); + + head = &state_queue; + + list_for_each(p, head) { + task = list_entry(p, struct state_queue, list); + + if (task->ap != ap) + continue; + + if (task->state == state) { + active = 1; + break; + } + + if (state == ST_ANY) { + active = 1; + break; + } + + list_for_each(q, &task->pending) { + waiting = list_entry(q, struct state_queue, pending); + + if (waiting->state == state) { + active = 1; + break; + } + + if (state == ST_ANY) { + active = 1; + break; + } + } + } + st_mutex_unlock(); - return; + return active; +} + +int st_wait_task(struct autofs_point *ap, enum states state, unsigned int seconds) +{ + unsigned int wait = 0; + unsigned int duration = 0; + int ret = 0; + while (1) { + struct timespec t = { 0, 200000000 }; + struct timespec r; + + while (nanosleep(&t, &r) == -1 && errno == EINTR) + memcpy(&t, &r, sizeof(struct timespec)); + + if (wait++ == 4) { + wait = 0; + duration++; + } + + if (!st_task_active(ap, state)) { + ret = 1; + break; + } + + if (seconds && duration >= seconds) + break; + } + + return ret; } +int st_wait_state(struct autofs_point *ap, enum states state) +{ + while (1) { + struct timespec t = { 0, 200000000 }; + struct timespec r; + + while (nanosleep(&t, &r) == -1 && errno == EINTR) + memcpy(&t, &r, sizeof(struct timespec)); + + st_mutex_lock(); + if (ap->state == state) { + st_mutex_unlock(); + return 1; + } + st_mutex_unlock(); + } + + return 0; +} + + static int run_state_task(struct state_queue *task) { struct autofs_point *ap; @@ -831,8 +930,6 @@ static int run_state_task(struct state_queue *task) ap = task->ap; next_state = task->state; - state_mutex_lock(ap); - state = ap->state; if (next_state != state) { @@ -862,8 +959,6 @@ static int run_state_task(struct state_queue *task) } } - state_mutex_unlock(ap); - return ret; } @@ -888,8 +983,6 @@ static void st_set_done(struct autofs_point *ap) struct list_head *p, *head; struct state_queue *task; - st_mutex_lock(); - head = &state_queue; list_for_each(p, head) { task = list_entry(p, struct state_queue, list); @@ -899,8 +992,6 @@ static void st_set_done(struct autofs_point *ap) } } - st_mutex_unlock(); - return; } diff --git a/include/automount.h b/include/automount.h index 1a20cd9..8ff24a7 100644 --- a/include/automount.h +++ b/include/automount.h @@ -399,7 +399,6 @@ struct autofs_point { unsigned logopt; /* Per map logging */ pthread_t exp_thread; /* Thread that is expiring */ pthread_t readmap_thread; /* Thread that is reading maps */ - pthread_mutex_t state_mutex; /* Protect state changes */ enum states state; /* Current state */ int state_pipe[2]; /* State change router pipe */ unsigned dir_created; /* Directory created for this mount? */ @@ -407,8 +406,6 @@ struct autofs_point { * host from which to mount */ struct autofs_point *parent; /* Owner of mounts list for submount */ pthread_mutex_t mounts_mutex; /* Protect mount lists */ - pthread_cond_t mounts_cond; /* Submounts condition variable */ - 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 */ @@ -446,20 +443,6 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ void rm_unwanted(unsigned logopt, const char *path, int incl, dev_t dev); int count_mounts(unsigned logopt, const char *path, dev_t dev); -#define state_mutex_lock(ap) \ -do { \ - int _st_lock = pthread_mutex_lock(&ap->state_mutex); \ - if (_st_lock) \ - fatal(_st_lock); \ -} while(0) - -#define state_mutex_unlock(ap) \ -do{ \ - int _st_unlock = pthread_mutex_unlock(&ap->state_mutex); \ - if (_st_unlock) \ - fatal(_st_unlock); \ -} while (0) - #define mounts_mutex_lock(ap) \ do { \ int _m_lock = pthread_mutex_lock(&ap->mounts_mutex); \ diff --git a/include/master.h b/include/master.h index 5f10d1f..86ae045 100644 --- a/include/master.h +++ b/include/master.h @@ -20,10 +20,6 @@ #ifndef MASTER_H #define MASTER_H -#define MASTER_SUBMNT_WAIT 0 -#define MASTER_SUBMNT_CONTINUE 1 -#define MASTER_SUBMNT_JOIN 2 - struct map_source { char *type; char *format; @@ -104,7 +100,6 @@ struct master *master_new(const char *, unsigned int, unsigned int); int master_read_master(struct master *, time_t, int); int master_submount_list_empty(struct autofs_point *ap); int master_notify_submount(struct autofs_point *, const char *path, enum states); -void master_signal_submount(struct autofs_point *, unsigned int); void master_notify_state_change(struct master *, int); int master_mount_mounts(struct master *, time_t, int); extern inline unsigned int master_get_logopt(void); diff --git a/include/state.h b/include/state.h index 8aed234..d7349d9 100644 --- a/include/state.h +++ b/include/state.h @@ -38,7 +38,8 @@ * */ enum states { - ST_INVAL = -1, + ST_ANY = -2, + ST_INVAL, ST_INIT, ST_READY, ST_EXPIRE, @@ -81,12 +82,18 @@ struct readmap_args { time_t now; /* Time when map is read */ }; +void st_mutex_lock(void); +void st_mutex_unlock(void); + void expire_cleanup(void *); void expire_proc_cleanup(void *); void nextstate(int, enum states); int st_add_task(struct autofs_point *, enum states); +int __st_add_task(struct autofs_point *, enum states); void st_remove_tasks(struct autofs_point *); +int st_wait_task(struct autofs_point *, enum states, unsigned int); +int st_wait_state(struct autofs_point *ap, enum states state); int st_start_handler(void); #endif diff --git a/lib/alarm.c b/lib/alarm.c index 6a70ed1..1e32291 100755 --- a/lib/alarm.c +++ b/lib/alarm.c @@ -178,7 +178,6 @@ static void *alarm_handler(void *arg) head = &alarms; while (1) { - if (list_empty(head)) { /* No alarms, wait for one to be added */ status = pthread_cond_wait(&cond, &mutex); @@ -211,19 +210,8 @@ static void *alarm_handler(void *arg) if (!first->cancel) { struct autofs_point *ap = first->ap; - /* - * We need to unlock the alarm list in case - * some other thread holds the state_mutex - *_lock(ap), and is currently trying to do - * some alarm_* function (i.e if we don't - * unlock, we might deadlock). - */ alarm_unlock(); - - state_mutex_lock(ap); - nextstate(ap->state_pipe[1], ST_EXPIRE); - state_mutex_unlock(ap); - + st_add_task(ap, ST_EXPIRE); alarm_lock(); } free(first); diff --git a/lib/master.c b/lib/master.c index edd3bdc..522b919 100644 --- a/lib/master.c +++ b/lib/master.c @@ -90,41 +90,20 @@ int master_add_autofs_point(struct master_mapent *entry, ap->logopt = logopt; ap->parent = NULL; + ap->thid = 0; ap->submnt_count = 0; 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) { - free(ap->path); - free(ap); - return 0; - } - status = pthread_mutex_init(&ap->mounts_mutex, NULL); if (status) { - status = pthread_mutex_destroy(&ap->state_mutex); - if (status) - fatal(status); free(ap->path); free(ap); return 0; } - status = pthread_cond_init(&ap->mounts_cond, NULL); - if (status) { - status = pthread_mutex_destroy(&ap->mounts_mutex); - if (status) - fatal(status); - status = pthread_mutex_destroy(&ap->state_mutex); - if (status) - fatal(status); - free(ap->path); - free(ap); - return 0; - } entry->ap = ap; return 1; @@ -137,18 +116,10 @@ void master_free_autofs_point(struct autofs_point *ap) if (!ap) return; - status = pthread_mutex_destroy(&ap->state_mutex); - if (status) - fatal(status); - status = pthread_mutex_destroy(&ap->mounts_mutex); if (status) fatal(status); - status = pthread_cond_destroy(&ap->mounts_cond); - if (status) - fatal(status); - free(ap->path); free(ap); } @@ -295,11 +266,9 @@ struct map_source *master_find_map_source(struct master_mapent *entry, { struct map_source *source = NULL; - master_mutex_lock(); - + master_source_readlock(entry); source = __master_find_map_source(entry, type, format, argc, argv); - - master_mutex_unlock(); + master_source_unlock(entry); return source; } @@ -519,13 +488,7 @@ void send_map_update_request(struct autofs_point *ap) if (!need_update) return; - status = pthread_mutex_lock(&ap->state_mutex); - if (status) - fatal(status); - nextstate(ap->state_pipe[1], ST_READMAP); - status = pthread_mutex_unlock(&ap->state_mutex); - if (status) - fatal(status); + st_add_task(ap, ST_READMAP); return; } @@ -695,17 +658,13 @@ void master_remove_mapent(struct master_mapent *entry) if (entry->ap->submount) return; - master_mutex_lock(); if (!list_empty(&entry->list)) list_del_init(&entry->list); - master_mutex_unlock(); return; } void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_cache) { - master_source_writelock(entry); - if (entry->maps) { struct map_source *m, *n; @@ -718,8 +677,6 @@ void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_c entry->maps = NULL; } - master_source_unlock(entry); - return; } @@ -827,10 +784,9 @@ int master_submount_list_empty(struct autofs_point *ap) int master_notify_submount(struct autofs_point *ap, const char *path, enum states state) { struct list_head *head, *p; - struct autofs_point *this; - pthread_t thid; + struct autofs_point *this = NULL; size_t plen = strlen(path); - int status, ret = 1; + int ret = 1; mounts_mutex_lock(ap); @@ -869,33 +825,25 @@ int master_notify_submount(struct autofs_point *ap, const char *path, enum state /* Now we have a submount to expire */ - state_mutex_lock(this); + st_mutex_lock(); if (this->state == ST_SHUTDOWN) { - state_mutex_unlock(this); + this = NULL; + st_mutex_unlock(); break; } - nextstate(this->state_pipe[1], state); + this->shutdown = ap->shutdown; - state_mutex_unlock(this); + __st_add_task(this, state); - thid = this->thid; - ap->mounts_signaled = MASTER_SUBMNT_WAIT; - while (ap->mounts_signaled == MASTER_SUBMNT_WAIT) { - status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex); - if (status) - fatal(status); - } + st_mutex_unlock(); + mounts_mutex_unlock(ap); - if (ap->mounts_signaled == MASTER_SUBMNT_JOIN) { - status = pthread_join(thid, NULL); - if (status) - fatal(status); - } else - ret = 0; + st_wait_task(this, state, 0); + + return ret; - break; } mounts_mutex_unlock(ap); @@ -903,38 +851,12 @@ int master_notify_submount(struct autofs_point *ap, const char *path, enum state return ret; } -void master_signal_submount(struct autofs_point *ap, unsigned int join) -{ - int status; - - if (!ap->parent || !ap->submount) - return; - - mounts_mutex_lock(ap->parent); - - ap->parent->mounts_signaled = join; - - if (join == MASTER_SUBMNT_JOIN) { - /* We are finishing up */ - ap->parent->submnt_count--; - list_del(&ap->mounts); - } - - status = pthread_cond_signal(&ap->parent->mounts_cond); - if (status) - fatal(status); - - mounts_mutex_unlock(ap->parent); - - return; -} - void master_notify_state_change(struct master *master, int sig) { struct master_mapent *entry; struct autofs_point *ap; struct list_head *p; - int state_pipe, cur_state; + int cur_state; unsigned int logopt; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); @@ -948,13 +870,11 @@ void master_notify_state_change(struct master *master, int sig) ap = entry->ap; logopt = ap->logopt; - state_mutex_lock(ap); + st_mutex_lock(); if (ap->state == ST_SHUTDOWN) goto next; - state_pipe = ap->state_pipe[1]; - switch (sig) { case SIGTERM: case SIGINT: @@ -962,7 +882,7 @@ void master_notify_state_change(struct master *master, int sig) ap->state != ST_SHUTDOWN_FORCE) { next = ST_SHUTDOWN_PENDING; ap->shutdown = 1; - nextstate(state_pipe, next); + __st_add_task(ap, next); } break; #ifdef ENABLE_FORCED_SHUTDOWN @@ -970,14 +890,15 @@ void master_notify_state_change(struct master *master, int sig) if (ap->state != ST_SHUTDOWN_FORCE && ap->state != ST_SHUTDOWN_PENDING) { next = ST_SHUTDOWN_FORCE; - nextstate(state_pipe, next); + ap->shutdown = 1; + __st_add_task(ap, next); } break; #endif case SIGUSR1: assert(ap->state == ST_READY); next = ST_PRUNE; - nextstate(state_pipe, next); + __st_add_task(ap, next); break; } next: @@ -986,7 +907,7 @@ next: "sig %d switching %s from %d to %d", sig, ap->path, ap->state, next); - state_mutex_unlock(ap); + st_mutex_unlock(); } master_mutex_unlock(); @@ -1024,7 +945,6 @@ static int master_do_mount(struct master_mapent *entry) handle_mounts_startup_cond_destroy(&suc); return 0; } - entry->thid = thid; while (!suc.done) { status = pthread_cond_wait(&suc.cond, &suc.mutex); @@ -1037,45 +957,18 @@ static int master_do_mount(struct master_mapent *entry) handle_mounts_startup_cond_destroy(&suc); return 0; } + entry->thid = thid; handle_mounts_startup_cond_destroy(&suc); return 1; } -static void shutdown_entry(struct master_mapent *entry) -{ - int state_pipe; - struct autofs_point *ap; - struct stat st; - int ret; - - ap = entry->ap; - - debug(ap->logopt, "%s", entry->path); - - state_mutex_lock(ap); - - state_pipe = ap->state_pipe[1]; - - ret = fstat(state_pipe, &st); - if (ret == -1) - goto next; - - nextstate(state_pipe, ST_SHUTDOWN_PENDING); -next: - state_mutex_unlock(ap); - - return; -} - static void check_update_map_sources(struct master_mapent *entry, int readall) { struct map_source *source, *last; - int state_pipe, map_stale = 0; struct autofs_point *ap; - struct stat st; - int ret; + int map_stale = 0; if (readall) map_stale = 1; @@ -1128,17 +1021,8 @@ static void check_update_map_sources(struct master_mapent *entry, int readall) master_source_unlock(entry); /* The map sources have changed */ - if (map_stale) { - state_mutex_lock(ap); - - state_pipe = entry->ap->state_pipe[1]; - - ret = fstat(state_pipe, &st); - if (ret != -1) - nextstate(state_pipe, ST_READMAP); - - state_mutex_unlock(ap); - } + if (map_stale) + st_add_task(ap, ST_READMAP); return; } @@ -1169,17 +1053,19 @@ int master_mount_mounts(struct master *master, time_t age, int readall) /* A master map entry has gone away */ if (this->age < age) { - shutdown_entry(this); + st_add_task(ap, ST_SHUTDOWN_PENDING); continue; } + master_source_writelock(ap->entry); lookup_close_lookup(ap); + master_source_unlock(ap->entry); cache_readlock(nc); ne = cache_lookup_distinct(nc, this->path); if (ne && this->age > ne->age) { cache_unlock(nc); - shutdown_entry(this); + st_add_task(ap, ST_SHUTDOWN_PENDING); continue; } nested = cache_partial_match(nc, this->path); @@ -1195,7 +1081,7 @@ int master_mount_mounts(struct master *master, time_t age, int readall) check_update_map_sources(this, readall); - state_mutex_lock(ap); + st_mutex_lock(); state_pipe = this->ap->state_pipe[1]; @@ -1203,7 +1089,7 @@ int master_mount_mounts(struct master *master, time_t age, int readall) ret = fstat(state_pipe, &st); save_errno = errno; - state_mutex_unlock(ap); + st_mutex_unlock(); if (ret == -1 && save_errno == EBADF) if (!master_do_mount(this)) { diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c index 6f66564..d6cbda8 100644 --- a/modules/mount_autofs.c +++ b/modules/mount_autofs.c @@ -242,7 +242,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, master_free_mapent(entry); return 1; } - nap->thid = thid; while (!suc.done) { status = pthread_cond_wait(&suc.cond, &suc.mutex); @@ -264,6 +263,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, master_free_mapent(entry); return 1; } + nap->thid = thid; ap->submnt_count++; list_add(&nap->mounts, &ap->submounts);