diff -up autofs-5.0.3/daemon/indirect.c.active-restart autofs-5.0.3/daemon/indirect.c --- autofs-5.0.3/daemon/indirect.c.active-restart 2008-02-25 09:16:05.000000000 +0900 +++ autofs-5.0.3/daemon/indirect.c 2008-02-25 09:16:46.000000000 +0900 @@ -20,6 +20,7 @@ * ----------------------------------------------------------------------- */ #include +#include #include #include #include @@ -32,9 +33,8 @@ #include #include #include +#include #include -#include -#include #include "automount.h" @@ -43,8 +43,6 @@ 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 const unsigned int indirect = AUTOFS_TYPE_INDIRECT; - static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts) { struct mnt_list *this; @@ -90,6 +88,7 @@ static int unlink_mount_tree(struct auto static int do_mount_autofs_indirect(struct autofs_point *ap) { + const char *str_indirect = mount_type_str(indirect); struct ioctl_ops *ops = get_ioctl_ops(); time_t timeout = ap->exp_timeout; char *options = NULL; @@ -98,8 +97,58 @@ static int do_mount_autofs_indirect(stru struct mnt_list *mnts; int ret; - mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 1); - if (mnts) { + ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO; + + if (ops->version) { + char device[AUTOFS_DEVID_LEN]; + struct statfs fst; + int ioctlfd; + dev_t devid; + char *tmp; + + if (!find_mnt_devid(_PROC_MOUNTS, ap->path, device, indirect)) + goto cont; + + devid = strtoul(device, NULL, 0); + + ret = remount_active_mount(ap, NULL, ap->path, devid, indirect, &ioctlfd); + + /* + * The directory must exist since we found a device + * number for the mount above but we can't know if we + * created it or not. However, if we're mounted on an + * autofs fs then we need to cleanup the path anyway. + */ + ap->dir_created = 0; + tmp = strdup(ap->path); + if (tmp) { + if (statfs(dirname(tmp), &fst) != -1) + if (fst.f_type == AUTOFS_SUPER_MAGIC) + ap->dir_created = 1; + free(tmp); + } + + /* + * Either we opened the mount or we're re-reading the map. + * If we opened the mount and ioctlfd is not -1 we have + * a descriptor for the indirect mount so we need to + * record that in the mount point struct. Otherwise we're + * re-reading the map. + */ + if (ret == REMOUNT_SUCCESS || ret == REMOUNT_READ_MAP) { + if (ioctlfd != -1) + ap->ioctlfd = ioctlfd; + return 0; + } + /* + * Since we got the device number above a mount exists so + * any other failure warrants a failure return here. + */ + return -1; + } else { + mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 1); + if (!mnts) + goto cont; ret = unlink_mount_tree(ap, mnts); free_mnt_list(mnts); if (!ret) { @@ -109,7 +158,7 @@ static int do_mount_autofs_indirect(stru goto out_err; } } - +cont: options = make_options_string(ap->path, ap->kpipefd, NULL); if (!options) { error(ap->logopt, "options string error"); @@ -152,29 +201,21 @@ static int do_mount_autofs_indirect(stru options = NULL; - if (ops->open(ap->logopt, &ap->ioctlfd, -1, ap->path, indirect)) { + if (stat(ap->path, &st) == -1) { + error(ap->logopt, + "failed to stat mount %s", ap->path); + goto out_umount; + } + ap->dev = st.st_dev; + + if (ops->open(ap->logopt, &ap->ioctlfd, ap->dev, ap->path, indirect)) { crit(ap->logopt, "failed to create ioctl fd for autofs path %s", ap->path); goto out_umount; } - ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO; - ops->timeout(ap->logopt, ap->ioctlfd, &timeout); - - if (ap->exp_timeout) - info(ap->logopt, - "mounted indirect mount on %s " - "with timeout %u, freq %u seconds", ap->path, - (unsigned int) ap->exp_timeout, - (unsigned int) ap->exp_runfreq); - else - info(ap->logopt, - "mounted indirect mount on %s with timeouts disabled", - ap->path); - - fstat(ap->ioctlfd, &st); - ap->dev = st.st_dev; /* Device number for mount point checks */ + notify_mount_result(ap, ap->path, str_indirect); return 0; @@ -636,15 +677,7 @@ static void *do_mount_indirect(void *arg struct autofs_point *ap; char buf[PATH_MAX + 1]; struct stat st; - struct passwd pw; - struct passwd *ppw = &pw; - struct passwd **pppw = &ppw; - struct group gr; - struct group *pgr; - struct group **ppgr; - char *pw_tmp, *gr_tmp; - struct thread_stdenv_vars *tsv; - int len, tmplen, grplen, status, state; + int len, status, state; mt = (struct pending_args *) arg; @@ -687,125 +720,8 @@ static void *do_mount_indirect(void *arg info(ap->logopt, "attempting to mount entry %s", buf); - /* - * Setup thread specific data values for macro - * substution in map entries during the mount. - * Best effort only as it must go ahead. - */ + set_tsd_user_vars(ap->logopt, mt->uid, mt->gid); - tsv = malloc(sizeof(struct thread_stdenv_vars)); - if (!tsv) - goto cont; - - tsv->uid = mt->uid; - tsv->gid = mt->gid; - - /* Try to get passwd info */ - - tmplen = sysconf(_SC_GETPW_R_SIZE_MAX); - if (tmplen < 0) { - error(ap->logopt, "failed to get buffer size for getpwuid_r"); - free(tsv); - goto cont; - } - - pw_tmp = malloc(tmplen + 1); - if (!pw_tmp) { - error(ap->logopt, "failed to malloc buffer for getpwuid_r"); - free(tsv); - goto cont; - } - - status = getpwuid_r(mt->uid, ppw, pw_tmp, tmplen, pppw); - if (status || !ppw) { - error(ap->logopt, "failed to get passwd info from getpwuid_r"); - free(tsv); - free(pw_tmp); - goto cont; - } - - tsv->user = strdup(pw.pw_name); - if (!tsv->user) { - error(ap->logopt, "failed to malloc buffer for user"); - free(tsv); - free(pw_tmp); - goto cont; - } - - tsv->home = strdup(pw.pw_dir); - if (!tsv->user) { - error(ap->logopt, "failed to malloc buffer for home"); - free(pw_tmp); - free(tsv->user); - free(tsv); - goto cont; - } - - free(pw_tmp); - - /* Try to get group info */ - - grplen = sysconf(_SC_GETGR_R_SIZE_MAX); - if (tmplen < 0) { - error(ap->logopt, "failed to get buffer size for getgrgid_r"); - free(tsv->user); - free(tsv->home); - free(tsv); - goto cont; - } - - gr_tmp = NULL; - tmplen = grplen; - while (1) { - char *tmp = realloc(gr_tmp, tmplen + 1); - if (!tmp) { - error(ap->logopt, "failed to malloc buffer for getgrgid_r"); - if (gr_tmp) - free(gr_tmp); - free(tsv->user); - free(tsv->home); - free(tsv); - goto cont; - } - gr_tmp = tmp; - pgr = &gr; - ppgr = &pgr; - status = getgrgid_r(mt->gid, pgr, gr_tmp, tmplen, ppgr); - if (status != ERANGE) - break; - tmplen += grplen; - } - - if (status || !pgr) { - error(ap->logopt, "failed to get group info from getgrgid_r"); - free(tsv->user); - free(tsv->home); - free(tsv); - free(gr_tmp); - goto cont; - } - - tsv->group = strdup(gr.gr_name); - if (!tsv->group) { - error(ap->logopt, "failed to malloc buffer for group"); - free(tsv->user); - free(tsv->home); - free(tsv); - free(gr_tmp); - goto cont; - } - - free(gr_tmp); - - status = pthread_setspecific(key_thread_stdenv_vars, tsv); - if (status) { - error(ap->logopt, "failed to set stdenv thread var"); - free(tsv->group); - free(tsv->user); - free(tsv->home); - free(tsv); - } -cont: status = lookup_nss_mount(ap, NULL, mt->name, mt->len); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); if (status) { diff -up autofs-5.0.3/daemon/automount.c.active-restart autofs-5.0.3/daemon/automount.c --- autofs-5.0.3/daemon/automount.c.active-restart 2008-02-25 09:16:05.000000000 +0900 +++ autofs-5.0.3/daemon/automount.c 2008-02-25 09:16:46.000000000 +0900 @@ -466,7 +466,7 @@ static int umount_subtree_mounts(struct pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); /* Lock the closest parent nesting point for umount */ - cache_multi_lock(me->parent); + cache_multi_writelock(me->parent); if (umount_multi_triggers(ap, root, me, base)) { warn(ap->logopt, "some offset mounts still present under %s", path); @@ -1412,6 +1412,55 @@ static void mutex_operation_wait(pthread return; } +int handle_mounts_startup_cond_init(struct startup_cond *suc) +{ + int status; + + status = pthread_mutex_init(&suc->mutex, NULL); + if (status) + return status; + + status = pthread_cond_init(&suc->cond, NULL); + if (status) { + status = pthread_mutex_destroy(&suc->mutex); + if (status) + fatal(status); + return status; + } + + status = pthread_mutex_lock(&suc->mutex); + if (status) { + status = pthread_mutex_destroy(&suc->mutex); + if (status) + fatal(status); + status = pthread_cond_destroy(&suc->cond); + if (status) + fatal(status); + } + + return 0; +} + +void handle_mounts_startup_cond_destroy(void *arg) +{ + struct startup_cond *suc = (struct startup_cond *) arg; + int status; + + status = pthread_mutex_unlock(&suc->mutex); + if (status) + fatal(status); + + status = pthread_mutex_destroy(&suc->mutex); + if (status) + fatal(status); + + status = pthread_cond_destroy(&suc->cond); + if (status) + fatal(status); + + return; +} + static void handle_mounts_cleanup(void *arg) { struct autofs_point *ap; @@ -1463,17 +1512,20 @@ static void handle_mounts_cleanup(void * void *handle_mounts(void *arg) { + struct startup_cond *suc; struct autofs_point *ap; int cancel_state, status = 0; - ap = (struct autofs_point *) arg; + suc = (struct startup_cond *) arg; + + ap = suc->ap; - pthread_cleanup_push(return_start_status, &suc); + pthread_cleanup_push(return_start_status, suc); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); state_mutex_lock(ap); - status = pthread_mutex_lock(&suc.mutex); + status = pthread_mutex_lock(&suc->mutex); if (status) { logerr("failed to lock startup condition mutex!"); fatal(status); @@ -1481,7 +1533,7 @@ void *handle_mounts(void *arg) if (mount_autofs(ap) < 0) { crit(ap->logopt, "mount of %s failed!", ap->path); - suc.status = 1; + suc->status = 1; state_mutex_unlock(ap); umount_autofs(ap, 1); pthread_setcancelstate(cancel_state, NULL); @@ -1491,7 +1543,7 @@ void *handle_mounts(void *arg) if (ap->ghost && ap->type != LKP_DIRECT) info(ap->logopt, "ghosting enabled"); - suc.status = 0; + suc->status = 0; pthread_cleanup_pop(1); /* We often start several automounters at the same time. Add some @@ -1948,7 +2000,9 @@ int main(int argc, char *argv[]) if (!query_kproto_ver() || get_kver_major() < 5) { fprintf(stderr, - "%s: kernel protocol version 5.00 or above required.\n", + "%s: test mount forbidden or " + "incorrect kernel protocol version, " + "kernel protocol version 5.00 or above required.\n", program); exit(1); } diff -up autofs-5.0.3/daemon/direct.c.active-restart autofs-5.0.3/daemon/direct.c --- autofs-5.0.3/daemon/direct.c.active-restart 2008-02-25 09:16:05.000000000 +0900 +++ autofs-5.0.3/daemon/direct.c 2008-02-25 09:16:46.000000000 +0900 @@ -20,6 +20,7 @@ * ----------------------------------------------------------------------- */ #include +#include #include #include #include @@ -35,16 +36,11 @@ #include #include #include -#include -#include #include "automount.h" extern pthread_attr_t thread_attr; -static const unsigned int direct = AUTOFS_TYPE_DIRECT; -static const unsigned int offset = AUTOFS_TYPE_OFFSET; - struct mnt_params { char *options; }; @@ -287,15 +283,11 @@ static int unlink_mount_tree(struct auto return ret; } -int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me) +static int unlink_active_mounts(struct autofs_point *ap, + struct mnt_list *mnts, struct mapent *me) { struct ioctl_ops *ops = get_ioctl_ops(); - struct mnt_params *mp; - time_t timeout = ap->exp_timeout; - struct stat st; - int status, ret, ioctlfd; struct list_head list; - const char *map_name; INIT_LIST_HEAD(&list); @@ -313,7 +305,7 @@ int do_mount_autofs_direct(struct autofs error(ap->logopt, "failed to create ioctl fd for %s", me->key); - return 0; + return 1; } ops->timeout(ap->logopt, ioctlfd, &tout); @@ -321,22 +313,99 @@ int do_mount_autofs_direct(struct autofs if (save_ioctlfd == -1) ops->close(ap->logopt, ioctlfd); - return 0; + return 1; } if (!unlink_mount_tree(ap, &list)) { debug(ap->logopt, "already mounted as other than autofs " "or failed to unlink entry in tree"); - return -1; + return 0; } } + return 1; +} - if (me->ioctlfd != -1) { - error(ap->logopt, "active direct mount %s", me->key); - return -1; - } +int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me) +{ + const char *str_direct = mount_type_str(direct); + struct ioctl_ops *ops = get_ioctl_ops(); + struct mnt_params *mp; + time_t timeout = ap->exp_timeout; + struct stat st; + int status, ret, ioctlfd; + const char *map_name; + + /* Calculate the timeouts */ + ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO; + + if (ops->version) { + char device[AUTOFS_DEVID_LEN]; + struct statfs fst; + dev_t devid; + char *tmp; + + /* Mount in mount table */ + if (!tree_find_mnt_devid(mnts, me->key, device, direct)) + goto cont; + + devid = strtoul(device, NULL, 0); + + ret = remount_active_mount(ap, me->mc, + me->key, devid, direct, + &ioctlfd); + + /* + * The directory must exist since we found a device + * number for the mount above but we can't know if we + * created it or not. However, if we're mounted on an + * autofs fs then we need to cleanup the path anyway. + */ + me->dir_created = 0; + tmp = strdup(me->key); + if (tmp) { + if (statfs(dirname(tmp), &fst) != -1) + if (fst.f_type == AUTOFS_SUPER_MAGIC) + me->dir_created = 1; + free(tmp); + } + + /* + * Either we opened the mount or we're re-reading the map. + * If we opened the mount and ioctlfd is not -1 we have an + * active mount so we need to record the descriptor in the + * cache entry. Otherwise there is no active mount or we're + * re-reading the map. + */ + if (ret == REMOUNT_SUCCESS || ret == REMOUNT_READ_MAP) { + if (ioctlfd != -1) + me->ioctlfd = ioctlfd; + return 0; + } + + /* + * Since we got the device number above a mount exists so + * any other failure warrants a failure return here. + */ + goto out_err; + } else { + /* + * A return of 1 indicates we're re-reading the map + * or we successfully unlinked the mount tree if it + * there was one. A return of zero inducates we + * failed to unlink the mount tree so we have to + * return a failure. + */ + ret = unlink_active_mounts(ap, mnts, me); + if (ret == 0) + return -1; + if (me->ioctlfd != -1) { + error(ap->logopt, "active direct mount %s", me->key); + return -1; + } + } +cont: status = pthread_once(&key_mnt_params_once, key_mnt_params_init); if (status) fatal(status); @@ -388,44 +457,27 @@ int do_mount_autofs_direct(struct autofs goto out_err; } - ops->open(ap->logopt, &ioctlfd, -1, me->key, direct); + if (stat(me->key, &st) == -1) { + error(ap->logopt, + "failed to stat direct mount trigger %s", me->key); + goto out_umount; + } + + ops->open(ap->logopt, &ioctlfd, st.st_dev, me->key, direct); if (ioctlfd < 0) { crit(ap->logopt, "failed to create ioctl fd for %s", me->key); goto out_umount; } - /* Calculate the timeouts */ - ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO; - ops->timeout(ap->logopt, ioctlfd, &timeout); - - if (ap->exp_timeout) - info(ap->logopt, - "mounted direct mount on %s " - "with timeout %u, freq %u seconds", me->key, - (unsigned int) ap->exp_timeout, - (unsigned int) ap->exp_runfreq); - else - info(ap->logopt, - "mounted direct mount on %s with timeouts disabled", - me->key); - - ret = fstat(ioctlfd, &st); - if (ret == -1) { - error(ap->logopt, - "failed to stat direct mount trigger %s", me->key); - goto out_close; - } + notify_mount_result(ap, me->key, str_direct); cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino); - ops->close(ap->logopt, ioctlfd); debug(ap->logopt, "mounted trigger %s", me->key); return 0; -out_close: - ops->close(ap->logopt, ioctlfd); out_umount: /* TODO: maybe force umount (-l) */ umount(me->key); @@ -462,8 +514,6 @@ int mount_autofs_direct(struct autofs_po 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); map = ap->entry->maps; while (map) { /* @@ -476,8 +526,6 @@ int mount_autofs_direct(struct autofs_po } mc = map->mc; - pthread_cleanup_push(cache_lock_cleanup, mc); - cache_readlock(mc); me = cache_enumerate(mc, NULL); while (me) { ne = cache_lookup_distinct(nc, me->key); @@ -505,12 +553,10 @@ int mount_autofs_direct(struct autofs_po me = cache_enumerate(mc, me); } - pthread_cleanup_pop(1); map = map->next; } pthread_cleanup_pop(1); pthread_cleanup_pop(1); - pthread_cleanup_pop(1); return 0; } @@ -627,6 +673,7 @@ force_umount: int mount_autofs_offset(struct autofs_point *ap, struct mapent *me) { + const char *str_offset = mount_type_str(offset); struct ioctl_ops *ops = get_ioctl_ops(); char buf[MAX_ERR_BUF]; struct mnt_params *mp; @@ -635,18 +682,68 @@ int mount_autofs_offset(struct autofs_po int ioctlfd, status, ret; const char *type, *map_name = NULL; - if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) { - if (ap->state != ST_READMAP) - warn(ap->logopt, - "trigger %s already mounted", me->key); - return 0; - } + if (ops->version) { + char device[AUTOFS_DEVID_LEN]; + struct statfs fst; + dev_t devid; + char *tmp; - if (me->ioctlfd != -1) { - error(ap->logopt, "active offset mount %s", me->key); - return -1; - } + /* If we can find it it's mounted */ + if (!find_mnt_devid(_PROC_MOUNTS, me->key, device, offset)) + goto cont; + + devid = strtoul(device, NULL, 0); + + ret = remount_active_mount(ap, me->mc, + me->key, devid, offset, + &ioctlfd); + + /* + * The directory must exist since we found a device + * number for the mount above but we can't know if we + * created it or not. However, if we're mounted on an + * autofs fs then we need to cleanup the path anyway. + */ + me->dir_created = 0; + tmp = strdup(me->key); + if (tmp) { + if (statfs(dirname(tmp), &fst) != -1) + if (fst.f_type == AUTOFS_SUPER_MAGIC) + me->dir_created = 1; + free(tmp); + } + + /* + * Either we opened the mount or we're re-reading the map. + * If we opened the mount and ioctlfd is not -1 we have an + * active mount so we need to record the descriptor in the + * cache entry. Otherwise there is no active mount or we're + * re-reading the map. + */ + if (ret == REMOUNT_SUCCESS || ret == REMOUNT_READ_MAP) { + if (ioctlfd != -1) + me->ioctlfd = ioctlfd; + return 0; + } + /* + * Since we got the device number above a mount exists so + * any other failure warrants a failure return here. + */ + goto out_err; + } else { + if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) { + if (ap->state != ST_READMAP) + warn(ap->logopt, + "trigger %s already mounted", me->key); + return 0; + } + if (me->ioctlfd != -1) { + error(ap->logopt, "active offset mount %s", me->key); + return -1; + } + } +cont: status = pthread_once(&key_mnt_params_once, key_mnt_params_init); if (status) fatal(status); @@ -670,7 +767,7 @@ int mount_autofs_offset(struct autofs_po } if (!mp->options) { - mp->options = make_options_string(ap->path, ap->kpipefd, "offset"); + mp->options = make_options_string(ap->path, ap->kpipefd, str_offset); if (!mp->options) return 0; } @@ -724,34 +821,28 @@ int mount_autofs_offset(struct autofs_po map_name = me->mc->map->argv[0]; ret = mount(map_name, me->key, "autofs", MS_MGC_VAL, mp->options); - if (ret) { - crit(ap->logopt, "failed to mount autofs path %s", me->key); - goto out_err; - } - if (ret != 0) { crit(ap->logopt, "failed to mount autofs offset trigger %s", me->key); goto out_err; } - ops->open(ap->logopt, &ioctlfd, -1, me->key, offset); - if (ioctlfd < 0) { - crit(ap->logopt, "failed to create ioctl fd for %s", me->key); - goto out_umount; - } - - ops->timeout(ap->logopt, ioctlfd, &timeout); - - ret = fstat(ioctlfd, &st); + ret = stat(me->key, &st); if (ret == -1) { error(ap->logopt, "failed to stat direct mount trigger %s", me->key); goto out_close; } - cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino); + ops->open(ap->logopt, &ioctlfd, st.st_dev, me->key, offset); + if (ioctlfd < 0) { + crit(ap->logopt, "failed to create ioctl fd for %s", me->key); + goto out_umount; + } + ops->timeout(ap->logopt, ioctlfd, &timeout); + notify_mount_result(ap, me->key, str_offset); + cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino); ops->close(ap->logopt, ioctlfd); debug(ap->logopt, "mounted trigger %s", me->key); @@ -1072,7 +1163,6 @@ int handle_packet_expire_direct(struct a return 1; } - mt = malloc(sizeof(struct pending_args)); if (!mt) { char *estr = strerror_r(errno, buf, MAX_ERR_BUF); @@ -1155,15 +1245,6 @@ static void *do_mount_direct(void *arg) struct ioctl_ops *ops = get_ioctl_ops(); struct pending_args *mt; struct autofs_point *ap; - struct passwd pw; - struct passwd *ppw = &pw; - struct passwd **pppw = &ppw; - struct group gr; - struct group *pgr; - struct group **ppgr; - char *pw_tmp, *gr_tmp; - struct thread_stdenv_vars *tsv; - int tmplen, grplen; struct stat st; int status, state; @@ -1209,126 +1290,8 @@ static void *do_mount_direct(void *arg) info(ap->logopt, "attempting to mount entry %s", mt->name); - /* - * Setup thread specific data values for macro - * substution in map entries during the mount. - * Best effort only as it must go ahead. - */ + set_tsd_user_vars(ap->logopt, mt->uid, mt->gid); - tsv = malloc(sizeof(struct thread_stdenv_vars)); - if (!tsv) - goto cont; - - tsv->uid = mt->uid; - tsv->gid = mt->gid; - - /* Try to get passwd info */ - - tmplen = sysconf(_SC_GETPW_R_SIZE_MAX); - if (tmplen < 0) { - error(ap->logopt, "failed to get buffer size for getpwuid_r"); - free(tsv); - goto cont; - } - - pw_tmp = malloc(tmplen + 1); - if (!pw_tmp) { - error(ap->logopt, "failed to malloc buffer for getpwuid_r"); - free(tsv); - goto cont; - } - - status = getpwuid_r(mt->uid, ppw, pw_tmp, tmplen, pppw); - if (status || !ppw) { - error(ap->logopt, "failed to get passwd info from getpwuid_r"); - free(tsv); - free(pw_tmp); - goto cont; - } - - tsv->user = strdup(pw.pw_name); - if (!tsv->user) { - error(ap->logopt, "failed to malloc buffer for user"); - free(tsv); - free(pw_tmp); - goto cont; - } - - tsv->home = strdup(pw.pw_dir); - if (!tsv->user) { - error(ap->logopt, "failed to malloc buffer for home"); - free(pw_tmp); - free(tsv->user); - free(tsv); - goto cont; - } - - free(pw_tmp); - - /* Try to get group info */ - - grplen = sysconf(_SC_GETGR_R_SIZE_MAX); - if (tmplen < 0) { - error(ap->logopt, "failed to get buffer size for getgrgid_r"); - free(tsv->user); - free(tsv->home); - free(tsv); - goto cont; - } - - gr_tmp = NULL; - tmplen = grplen; - while (1) { - char *tmp = realloc(gr_tmp, tmplen + 1); - if (!tmp) { - error(ap->logopt, "failed to malloc buffer for getgrgid_r"); - if (gr_tmp) - free(gr_tmp); - free(tsv->user); - free(tsv->home); - free(tsv); - goto cont; - } - gr_tmp = tmp; - pgr = &gr; - ppgr = &pgr; - status = getgrgid_r(mt->gid, pgr, gr_tmp, tmplen, ppgr); - if (status != ERANGE) - break; - tmplen += grplen; - } - - if (status || !pgr) { - error(ap->logopt, "failed to get group info from getgrgid_r"); - free(tsv->user); - free(tsv->home); - free(tsv); - free(gr_tmp); - goto cont; - } - - tsv->group = strdup(gr.gr_name); - if (!tsv->group) { - error(ap->logopt, "failed to malloc buffer for group"); - free(tsv->user); - free(tsv->home); - free(tsv); - free(gr_tmp); - goto cont; - } - - free(gr_tmp); - - status = pthread_setspecific(key_thread_stdenv_vars, tsv); - if (status) { - error(ap->logopt, "failed to set stdenv thread var"); - free(tsv->group); - free(tsv->user); - free(tsv->home); - free(tsv); - } - -cont: status = lookup_nss_mount(ap, NULL, mt->name, strlen(mt->name)); /* * Direct mounts are always a single mount. If it fails there's diff -up autofs-5.0.3/daemon/lookup.c.active-restart autofs-5.0.3/daemon/lookup.c --- autofs-5.0.3/daemon/lookup.c.active-restart 2008-02-25 09:16:05.000000000 +0900 +++ autofs-5.0.3/daemon/lookup.c 2008-02-25 09:16:46.000000000 +0900 @@ -898,7 +898,8 @@ int lookup_nss_mount(struct autofs_point map = map->next; } - send_map_update_request(ap); + if (ap->state != ST_INIT) + send_map_update_request(ap); pthread_cleanup_pop(1); return !result; diff -up autofs-5.0.3/include/parse_subs.h.active-restart autofs-5.0.3/include/parse_subs.h --- autofs-5.0.3/include/parse_subs.h.active-restart 2008-01-14 13:39:16.000000000 +0900 +++ autofs-5.0.3/include/parse_subs.h 2008-02-25 09:16:46.000000000 +0900 @@ -27,8 +27,5 @@ int strmcmp(const char *, const char *, char *dequote(const char *, int, unsigned int); int span_space(const char *, unsigned int); char *sanitize_path(const char *, int, unsigned int, unsigned int); -int umount_ent(struct autofs_point *, const char *); -int mount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *); -int umount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *); #endif diff -up autofs-5.0.3/include/automount.h.active-restart autofs-5.0.3/include/automount.h --- autofs-5.0.3/include/automount.h.active-restart 2008-02-25 09:16:05.000000000 +0900 +++ autofs-5.0.3/include/automount.h 2008-02-25 09:16:46.000000000 +0900 @@ -29,6 +29,7 @@ #include "log.h" #include "rpc_subs.h" #include "parse_subs.h" +#include "mounts.h" #include "dev-ioctl-lib.h" #ifdef WITH_DMALLOC @@ -71,10 +72,6 @@ int load_autofs4_module(void); #define SMB_SUPER_MAGIC 0x0000517BL #define CIFS_MAGIC_NUMBER 0xFF534D42L -#define AUTOFS_TYPE_INDIRECT 0x0001 -#define AUTOFS_TYPE_DIRECT 0x0002 -#define AUTOFS_TYPE_OFFSET 0x0004 - /* This sould be enough for at least 20 host aliases */ #define HOST_ENT_BUF_SIZE 2048 @@ -146,7 +143,7 @@ struct mapent_cache { struct mapent { struct mapent *next; struct list_head ino_index; - pthread_mutex_t multi_mutex; + pthread_rwlock_t multi_rwlock; struct list_head multi_list; struct mapent_cache *mc; struct map_source *source; @@ -189,7 +186,8 @@ int cache_add_offset(struct mapent_cache int cache_set_parents(struct mapent *mm); int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age); int cache_delete(struct mapent_cache *mc, const char *key); -void cache_multi_lock(struct mapent *me); +void cache_multi_readlock(struct mapent *me); +void cache_multi_writelock(struct mapent *me); void cache_multi_unlock(struct mapent *me); int cache_delete_offset_list(struct mapent_cache *mc, const char *key); void cache_release(struct map_source *map); @@ -328,62 +326,6 @@ int cat_path(char *buf, size_t len, cons int ncat_path(char *buf, size_t len, const char *dir, const char *base, size_t blen); -/* mount table utilities */ - -#define MNTS_ALL 0x0001 -#define MNTS_REAL 0x0002 -#define MNTS_AUTOFS 0x0004 - -struct mnt_list { - char *path; - char *fs_name; - char *fs_type; - char *opts; - pid_t owner; - /* - * List operations ie. get_mnt_list. - */ - struct mnt_list *next; - /* - * Tree operations ie. tree_make_tree, - * tree_get_mnt_list etc. - */ - struct mnt_list *left; - struct mnt_list *right; - struct list_head self; - struct list_head list; - struct list_head entries; - struct list_head sublist; - /* - * Offset mount handling ie. add_ordered_list - * and get_offset. - */ - struct list_head ordered; -}; - -unsigned int query_kproto_ver(void); -unsigned int get_kver_major(void); -unsigned int get_kver_minor(void); -char *make_options_string(char *path, int kernel_pipefd, char *extra); -char *make_mnt_name_string(char *path); -struct mnt_list *get_mnt_list(const char *table, const char *path, int include); -struct mnt_list *reverse_mnt_list(struct mnt_list *list); -void free_mnt_list(struct mnt_list *list); -int contained_in_local_fs(const char *path); -int is_mounted(const char *table, const char *path, unsigned int type); -int has_fstab_option(const char *opt); -int find_mnt_devid(const char *table, const char *path, char *devid, unsigned int type); -char *get_offset(const char *prefix, char *offset, - struct list_head *head, struct list_head **pos); -void add_ordered_list(struct mnt_list *ent, struct list_head *head); -void tree_free_mnt_tree(struct mnt_list *tree); -struct mnt_list *tree_make_mnt_tree(const char *table, const char *path); -int tree_get_mnt_list(struct mnt_list *mnts, struct list_head *list, const char *path, int include); -int tree_get_mnt_sublist(struct mnt_list *mnts, struct list_head *list, const char *path, int include); -int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char *path); -int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type); -int tree_find_mnt_devid(struct mnt_list *mnts, const char *path, char *devid, unsigned int type); - /* Core automount definitions */ #define MNT_DETACH 0x00000002 /* Just detach from the tree */ @@ -391,10 +333,14 @@ int tree_find_mnt_devid(struct mnt_list struct startup_cond { pthread_mutex_t mutex; pthread_cond_t cond; + struct autofs_point *ap; unsigned int done; unsigned int status; }; +int handle_mounts_startup_cond_init(struct startup_cond *suc); +void handle_mounts_startup_cond_destroy(void *arg); + struct master_readmap_cond { pthread_mutex_t mutex; pthread_cond_t cond; diff -up autofs-5.0.3/modules/mount_ext2.c.active-restart autofs-5.0.3/modules/mount_ext2.c --- autofs-5.0.3/modules/mount_ext2.c.active-restart 2008-01-14 13:39:16.000000000 +0900 +++ autofs-5.0.3/modules/mount_ext2.c 2008-02-25 09:16:46.000000000 +0900 @@ -84,8 +84,9 @@ int mount_mount(struct autofs_point *ap, existed = 0; if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { - error(ap->logopt, - MODPREFIX "warning: %s is already mounted", fullpath); + info(ap->logopt, MODPREFIX + "%s is already mounted or is bieng re-mounted", + fullpath); return 0; } diff -up autofs-5.0.3/modules/mount_generic.c.active-restart autofs-5.0.3/modules/mount_generic.c --- autofs-5.0.3/modules/mount_generic.c.active-restart 2008-01-14 13:39:16.000000000 +0900 +++ autofs-5.0.3/modules/mount_generic.c 2008-02-25 09:16:46.000000000 +0900 @@ -83,8 +83,9 @@ int mount_mount(struct autofs_point *ap, existed = 0; if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { - error(ap->logopt, - MODPREFIX "warning: %s is already mounted", fullpath); + info(ap->logopt, MODPREFIX + "%s is already mounted or is being re-mounted", + fullpath); return 0; } diff -up autofs-5.0.3/modules/mount_autofs.c.active-restart autofs-5.0.3/modules/mount_autofs.c --- autofs-5.0.3/modules/mount_autofs.c.active-restart 2008-01-14 13:39:16.000000000 +0900 +++ autofs-5.0.3/modules/mount_autofs.c 2008-02-25 09:16:46.000000000 +0900 @@ -46,6 +46,7 @@ int mount_mount(struct autofs_point *ap, int name_len, const char *what, const char *fstype, const char *c_options, void *context) { + struct startup_cond suc; pthread_t thid; char *fullpath; const char **argv; @@ -216,27 +217,26 @@ int mount_mount(struct autofs_point *ap, mounts_mutex_lock(ap); - status = pthread_mutex_lock(&suc.mutex); - if (status) { - crit(ap->logopt, - MODPREFIX "failed to lock startup condition mutex!"); + if (handle_mounts_startup_cond_init(&suc)) { + crit(ap->logopt, MODPREFIX + "failed to init startup cond for mount %s", entry->path); + mounts_mutex_unlock(ap); cache_release(source); master_free_mapent(entry); return 1; } + suc.ap = nap; suc.done = 0; suc.status = 0; - if (pthread_create(&thid, NULL, handle_mounts, nap)) { + if (pthread_create(&thid, NULL, handle_mounts, &suc)) { crit(ap->logopt, MODPREFIX "failed to create mount handler thread for %s", fullpath); mounts_mutex_unlock(ap); - status = pthread_mutex_unlock(&suc.mutex); - if (status) - fatal(status); + handle_mounts_startup_cond_destroy(&suc); cache_release(source); master_free_mapent(entry); return 1; @@ -247,7 +247,7 @@ int mount_mount(struct autofs_point *ap, status = pthread_cond_wait(&suc.cond, &suc.mutex); if (status) { mounts_mutex_unlock(ap); - pthread_mutex_unlock(&suc.mutex); + handle_mounts_startup_cond_destroy(&suc); fatal(status); } } @@ -256,9 +256,7 @@ int mount_mount(struct autofs_point *ap, crit(ap->logopt, MODPREFIX "failed to create submount for %s", fullpath); mounts_mutex_unlock(ap); - status = pthread_mutex_unlock(&suc.mutex); - if (status) - fatal(status); + handle_mounts_startup_cond_destroy(&suc); master_free_mapent(entry); return 1; } @@ -266,12 +264,9 @@ int mount_mount(struct autofs_point *ap, ap->submnt_count++; list_add(&nap->mounts, &ap->submounts); + handle_mounts_startup_cond_destroy(&suc); mounts_mutex_unlock(ap); - status = pthread_mutex_unlock(&suc.mutex); - if (status) - fatal(status); - return 0; } diff -up autofs-5.0.3/modules/mount_nfs.c.active-restart autofs-5.0.3/modules/mount_nfs.c --- autofs-5.0.3/modules/mount_nfs.c.active-restart 2008-02-25 09:16:05.000000000 +0900 +++ autofs-5.0.3/modules/mount_nfs.c 2008-02-25 09:16:46.000000000 +0900 @@ -198,10 +198,10 @@ int mount_mount(struct autofs_point *ap, char *loc, *port_opt = NULL; if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { - error(ap->logopt, - MODPREFIX - "warning: %s is already mounted", fullpath); - break; + info(ap->logopt, MODPREFIX + "%s is already mounted or is being re-mounted", fullpath); + free_host_list(&hosts); + return 0; } /* diff -up autofs-5.0.3/modules/parse_sun.c.active-restart autofs-5.0.3/modules/parse_sun.c --- autofs-5.0.3/modules/parse_sun.c.active-restart 2008-01-14 13:39:16.000000000 +0900 +++ autofs-5.0.3/modules/parse_sun.c 2008-02-25 09:16:46.000000000 +0900 @@ -968,8 +968,6 @@ static int mount_subtree_offsets(struct if (!mm) return 0; - cache_multi_lock(me->parent); - m_key = mm->key; if (*m_key == '/') { @@ -999,8 +997,6 @@ static int mount_subtree_offsets(struct return -1; } - cache_multi_unlock(me->parent); - return ret; } @@ -1197,7 +1193,7 @@ int parse_mount(struct autofs_point *ap, * us to fail on the check for duplicate offsets in * we don't know when submounts go away. */ - cache_multi_lock(me); + cache_multi_writelock(me); cache_delete_offset_list(mc, name); cache_multi_unlock(me); } @@ -1220,7 +1216,7 @@ int parse_mount(struct autofs_point *ap, } pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); - cache_multi_lock(me); + cache_multi_writelock(me); /* It's a multi-mount; deal with it */ do { char *path, *myoptions, *loc; @@ -1296,6 +1292,10 @@ int parse_mount(struct autofs_point *ap, */ cache_set_parents(me); + /* Added multi-mount cache entries, down grade lock */ + cache_multi_unlock(me); + cache_multi_readlock(me); + /* Mount root offset if it exists */ ro = cache_lookup_offset("/", "/", strlen(m_root), &me->multi_list); if (ro) { @@ -1468,10 +1468,14 @@ mount_it: cache_readlock(mc); me = cache_lookup_distinct(mc, name); if (me) { - int ret = mount_subtree_offsets(ap, mc, me); + int ret; + + cache_multi_readlock(me->parent); + ret = mount_subtree_offsets(ap, mc, me); /* Convert fail on nonstrict, non-empty multi-mount to success */ if (rv < 0 && ret > 0) rv = 0; + cache_multi_unlock(me->parent); } cache_unlock(mc); pthread_setcancelstate(cur_state, NULL); diff -up autofs-5.0.3/modules/mount_bind.c.active-restart autofs-5.0.3/modules/mount_bind.c --- autofs-5.0.3/modules/mount_bind.c.active-restart 2008-01-14 13:39:16.000000000 +0900 +++ autofs-5.0.3/modules/mount_bind.c 2008-02-25 09:16:46.000000000 +0900 @@ -126,8 +126,8 @@ int mount_mount(struct autofs_point *ap, existed = 0; if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { - error(ap->logopt, - MODPREFIX "warning: %s is already mounted", + info(ap->logopt, MODPREFIX + "%s is already mounted or is being re-mounted", fullpath); return 0; } diff -up autofs-5.0.3/lib/parse_subs.c.active-restart autofs-5.0.3/lib/parse_subs.c --- autofs-5.0.3/lib/parse_subs.c.active-restart 2008-01-14 13:39:16.000000000 +0900 +++ autofs-5.0.3/lib/parse_subs.c 2008-02-25 09:16:46.000000000 +0900 @@ -18,10 +18,7 @@ #include #include #include -#include -#include #include -#include #include "automount.h" /* @@ -304,220 +301,3 @@ char *sanitize_path(const char *path, in return s_path; } -int umount_ent(struct autofs_point *ap, const char *path) -{ - struct stat st; - struct statfs fs; - int sav_errno; - int status, is_smbfs = 0; - int ret, rv = 1; - - ret = statfs(path, &fs); - if (ret == -1) { - warn(ap->logopt, "could not stat fs of %s", path); - is_smbfs = 0; - } else { - int cifsfs = fs.f_type == (__SWORD_TYPE) CIFS_MAGIC_NUMBER; - int smbfs = fs.f_type == (__SWORD_TYPE) SMB_SUPER_MAGIC; - is_smbfs = (cifsfs | smbfs) ? 1 : 0; - } - - status = lstat(path, &st); - sav_errno = errno; - - if (status < 0) - warn(ap->logopt, "lstat of %s failed with %d", path, status); - - /* - * lstat failed and we're an smbfs fs returning an error that is not - * EIO or EBADSLT or the lstat failed so it's a bad path. Return - * a fail. - * - * EIO appears to correspond to an smb mount that has gone away - * and EBADSLT relates to CD changer not responding. - */ - if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) { - rv = spawn_umount(ap->logopt, path, NULL); - } else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) { - rv = spawn_umount(ap->logopt, path, NULL); - } - - /* We are doing a forced shutcwdown down so unlink busy mounts */ - if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) { - ret = stat(path, &st); - if (ret == -1 && errno == ENOENT) { - warn(ap->logopt, "mount point does not exist"); - return 0; - } - - if (ret == 0 && !S_ISDIR(st.st_mode)) { - warn(ap->logopt, "mount point is not a directory"); - return 0; - } - - if (ap->state == ST_SHUTDOWN_FORCE) { - info(ap->logopt, "forcing umount of %s", path); - rv = spawn_umount(ap->logopt, "-l", path, NULL); - } - - /* - * Verify that we actually unmounted the thing. This is a - * belt and suspenders approach to not eating user data. - * We have seen cases where umount succeeds, but there is - * still a file system mounted on the mount point. How - * this happens has not yet been determined, but we want to - * make sure to return failure here, if that is the case, - * so that we do not try to call rmdir_path on the - * directory. - */ - if (!rv && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { - crit(ap->logopt, - "the umount binary reported that %s was " - "unmounted, but there is still something " - "mounted on this path.", path); - rv = -1; - } - } - - return rv; -} - -int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) -{ - char path[PATH_MAX + 1]; - char *offset = path; - struct mapent *oe; - struct list_head *pos = NULL; - unsigned int fs_path_len; - unsigned int mounted; - int start; - - fs_path_len = strlen(root) + strlen(base); - if (fs_path_len > PATH_MAX) - return -1; - - strcpy(path, root); - strcat(path, base); - - mounted = 0; - start = strlen(root); - offset = cache_get_offset(base, offset, start, &me->multi_list, &pos); - while (offset) { - int plen = fs_path_len + strlen(offset); - - if (plen > PATH_MAX) { - warn(ap->logopt, "path loo long"); - goto cont; - } - - oe = cache_lookup_offset(base, offset, start, &me->multi_list); - if (!oe) - goto cont; - - debug(ap->logopt, "mount offset %s", oe->key); - - if (mount_autofs_offset(ap, oe) < 0) - warn(ap->logopt, "failed to mount offset"); - else - mounted++; -cont: - offset = cache_get_offset(base, - offset, start, &me->multi_list, &pos); - } - - return mounted; -} - -int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) -{ - char path[PATH_MAX + 1]; - char *offset; - struct mapent *oe; - struct list_head *mm_root, *pos; - const char o_root[] = "/"; - const char *mm_base; - int left, start; - - left = 0; - start = strlen(root); - - mm_root = &me->multi->multi_list; - - if (!base) - mm_base = o_root; - else - mm_base = base; - - pos = NULL; - offset = path; - - /* Make sure "none" of the offsets have an active mount. */ - while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) { - char *oe_base; - - oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); - /* root offset is a special case */ - if (!oe || (strlen(oe->key) - start) == 1) - continue; - - /* - * Check for and umount subtree offsets resulting from - * nonstrict mount fail. - */ - oe_base = oe->key + strlen(root); - left += umount_multi_triggers(ap, root, oe, oe_base); - - if (oe->ioctlfd != -1) - left++; - } - - if (left) - return left; - - pos = NULL; - offset = path; - - /* Make sure "none" of the offsets have an active mount. */ - while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) { - oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); - /* root offset is a special case */ - if (!oe || (strlen(oe->key) - start) == 1) - continue; - - debug(ap->logopt, "umount offset %s", oe->key); - - if (umount_autofs_offset(ap, oe)) { - warn(ap->logopt, "failed to umount offset"); - left++; - } - } - - if (!left && me->multi == me) { - struct mapent_cache *mc = me->mc; - int status; - - /* - * Special case. - * If we can't umount the root container then we can't - * delete the offsets from the cache and we need to put - * the offset triggers back. - */ - if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) { - info(ap->logopt, "unmounting dir = %s", root); - if (umount_ent(ap, root)) { - if (!mount_multi_triggers(ap, root, me, "/")) - warn(ap->logopt, - "failed to remount offset triggers"); - return left++; - } - } - - /* We're done - clean out the offsets */ - status = cache_delete_offset_list(mc, me->key); - if (status != CHE_OK) - warn(ap->logopt, "couldn't delete offset list"); - } - - return left; -} - diff -up autofs-5.0.3/lib/mounts.c.active-restart autofs-5.0.3/lib/mounts.c --- autofs-5.0.3/lib/mounts.c.active-restart 2008-02-25 09:16:05.000000000 +0900 +++ autofs-5.0.3/lib/mounts.c 2008-02-25 09:16:46.000000000 +0900 @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * mounts.c - module for Linux automount mount table lookup functions + * mounts.c - module for mount utilities. * * Copyright 2002-2005 Ian Kent - All Rights Reserved * @@ -23,12 +23,21 @@ #include #include #include +#include +#include +#include +#include #include "automount.h" #define MAX_OPTIONS_LEN 80 #define MAX_MNT_NAME_LEN 30 +const unsigned int indirect = AUTOFS_TYPE_INDIRECT; +const unsigned int direct = AUTOFS_TYPE_DIRECT; +const unsigned int offset = AUTOFS_TYPE_OFFSET; +const unsigned int type_count = 3; + static const char options_template[] = "fd=%d,pgrp=%u,minproto=5,maxproto=%d"; static const char options_template_extra[] = "fd=%d,pgrp=%u,minproto=5,maxproto=%d,%s"; static const char mnt_name_template[] = "automount(pid%u)"; @@ -466,7 +475,7 @@ int has_fstab_option(const char *opt) * super block when searching for the mount. */ int find_mnt_devid(const char *table, - const char *path, char *devid, unsigned int type) + const char *path, char *devid, const unsigned int type) { struct mntent *mnt; struct mntent mnt_wrk; @@ -1070,3 +1079,528 @@ int tree_find_mnt_devid(struct mnt_list return 1; } +void set_tsd_user_vars(unsigned int logopt, uid_t uid, gid_t gid) +{ + struct thread_stdenv_vars *tsv; + struct passwd pw; + struct passwd *ppw = &pw; + struct passwd **pppw = &ppw; + struct group gr; + struct group *pgr; + struct group **ppgr; + char *pw_tmp, *gr_tmp; + int status, tmplen, grplen; + + /* + * Setup thread specific data values for macro + * substution in map entries during the mount. + * Best effort only as it must go ahead. + */ + + tsv = malloc(sizeof(struct thread_stdenv_vars)); + if (!tsv) { + error(logopt, "failed alloc tsv storage"); + return; + } + + tsv->uid = uid; + tsv->gid = gid; + + /* Try to get passwd info */ + + tmplen = sysconf(_SC_GETPW_R_SIZE_MAX); + if (tmplen < 0) { + error(logopt, "failed to get buffer size for getpwuid_r"); + goto free_tsv; + } + + pw_tmp = malloc(tmplen + 1); + if (!pw_tmp) { + error(logopt, "failed to malloc buffer for getpwuid_r"); + goto free_tsv; + } + + status = getpwuid_r(uid, ppw, pw_tmp, tmplen, pppw); + if (status || !ppw) { + error(logopt, "failed to get passwd info from getpwuid_r"); + free(pw_tmp); + goto free_tsv; + } + + tsv->user = strdup(pw.pw_name); + if (!tsv->user) { + error(logopt, "failed to malloc buffer for user"); + free(pw_tmp); + goto free_tsv; + } + + tsv->home = strdup(pw.pw_dir); + if (!tsv->user) { + error(logopt, "failed to malloc buffer for home"); + free(pw_tmp); + goto free_tsv_user; + } + + free(pw_tmp); + + /* Try to get group info */ + + grplen = sysconf(_SC_GETGR_R_SIZE_MAX); + if (tmplen < 0) { + error(logopt, "failed to get buffer size for getgrgid_r"); + goto free_tsv_home; + } + + gr_tmp = NULL; + tmplen = grplen; + while (1) { + char *tmp = realloc(gr_tmp, tmplen + 1); + if (!tmp) { + error(logopt, "failed to malloc buffer for getgrgid_r"); + if (gr_tmp) + free(gr_tmp); + goto free_tsv_home; + } + gr_tmp = tmp; + pgr = &gr; + ppgr = &pgr; + status = getgrgid_r(gid, pgr, gr_tmp, tmplen, ppgr); + if (status != ERANGE) + break; + tmplen += grplen; + } + + if (status || !pgr) { + error(logopt, "failed to get group info from getgrgid_r"); + free(gr_tmp); + goto free_tsv_home; + } + + tsv->group = strdup(gr.gr_name); + if (!tsv->group) { + error(logopt, "failed to malloc buffer for group"); + free(gr_tmp); + goto free_tsv_home; + } + + free(gr_tmp); + + status = pthread_setspecific(key_thread_stdenv_vars, tsv); + if (status) { + error(logopt, "failed to set stdenv thread var"); + goto free_tsv_group; + } + + return; + +free_tsv_group: + free(tsv->group); +free_tsv_home: + free(tsv->home); +free_tsv_user: + free(tsv->user); +free_tsv: + free(tsv); + return; +} + +const char *mount_type_str(const unsigned int type) +{ + static const char *str_type[] = { + "direct", + "indirect", + "offset" + }; + unsigned int pos, i; + + for (pos = 0, i = type; pos < type_count; i >>= 1, pos++) + if (i & 0x1) + break; + + return (pos == type_count ? NULL : str_type[pos]); +} + +void notify_mount_result(struct autofs_point *ap, + const char *path, const char *type) +{ + if (ap->exp_timeout) + info(ap->logopt, + "mounted %s on %s with timeout %u, freq %u seconds", + type, path, + (unsigned int) ap->exp_timeout, + (unsigned int) ap->exp_runfreq); + else + info(ap->logopt, + "mounted %s on %s with timeouts disabled", + type, path); + + return; +} + +static int do_remount_direct(struct autofs_point *ap, int fd, const char *path) +{ + struct ioctl_ops *ops = get_ioctl_ops(); + uid_t uid; + gid_t gid; + int ret; + + ops->requestor(ap->logopt, fd, path, &uid, &gid); + if (uid != -1 && gid != -1) + set_tsd_user_vars(ap->logopt, uid, gid); + + ret = lookup_nss_mount(ap, NULL, path, strlen(path)); + if (ret) + info(ap->logopt, "re-mounted %s", path); + else + info(ap->logopt, "failed to re-mount %s", path); + + return ret; +} + +static int do_remount_indirect(struct autofs_point *ap, int fd, const char *path) +{ + struct ioctl_ops *ops = get_ioctl_ops(); + struct dirent **de; + char buf[PATH_MAX + 1]; + uid_t uid; + gid_t gid; + unsigned int mounted; + int n, size; + + n = scandir(path, &de, 0, alphasort); + if (n < 0) + return -1; + + size = sizeof(buf); + + while (n--) { + int ret, len; + + if (strcmp(de[n]->d_name, ".") == 0 || + strcmp(de[n]->d_name, "..") == 0) { + free(de[n]); + continue; + } + + ret = cat_path(buf, size, path, de[n]->d_name); + if (!ret) { + do { + free(de[n]); + } while (n--); + free(de); + return -1; + } + + ops->ismountpoint(ap->logopt, fd, buf, &mounted); + if (!mounted) { + free(de[n]); + continue; + } + + ops->requestor(ap->logopt, fd, buf, &uid, &gid); + if (uid != -1 && gid != -1) + set_tsd_user_vars(ap->logopt, uid, gid); + + len = strlen(de[n]->d_name); + + ret = lookup_nss_mount(ap, NULL, de[n]->d_name, len); + if (ret) + info(ap->logopt, "re-mounted %s", buf); + else + info(ap->logopt, "failed to re-mount %s", buf); + + free(de[n]); + } + free(de); + + return 0; +} + +int remount_active_mount(struct autofs_point *ap, struct mapent_cache *mc, + const char *path, dev_t devid, const unsigned int type, + int *ioctlfd) +{ + struct ioctl_ops *ops = get_ioctl_ops(); + time_t timeout = ap->exp_timeout; + const char *str_type = mount_type_str(type); + unsigned int mounted; + struct stat st; + int fd; + + *ioctlfd = -1; + + /* Open failed, no mount present */ + ops->open(ap->logopt, &fd, devid, path, type); + if (fd == -1) + return REMOUNT_OPEN_FAIL; + + /* Re-reading the map, set timeout and return */ + if (ap->state == ST_READMAP) { + ops->timeout(ap->logopt, fd, &timeout); + ops->close(ap->logopt, fd); + return REMOUNT_READ_MAP; + } + + /* Mounted so set pipefd and timeout etc. */ + ops->catatonic(ap->logopt, fd); + ops->setpipefd(ap->logopt, fd, ap->kpipefd); + ops->timeout(ap->logopt, fd, &timeout); + if (fstat(fd, &st) == -1) { + error(ap->logopt, + "failed to stat %s mount %s", str_type, path); + ops->close(ap->logopt, fd); + return REMOUNT_STAT_FAIL; + } + ap->dev = st.st_dev; + if (mc) + cache_set_ino_index(mc, path, st.st_dev, st.st_ino); + notify_mount_result(ap, path, str_type); + + debug(ap->logopt, "re-connected to mount %s", path); + + *ioctlfd = fd; + + /* Any mounts on or below? */ + ops->ismountpoint(ap->logopt, fd, path, &mounted); + if (!mounted) { + /* + * If we're an indirect mount we pass back the fd. + * But if were a direct or offset mount with no active + * mount we don't retain an open file descriptor. + */ + if (type == direct) { + ops->close(ap->logopt, fd); + *ioctlfd = -1; + } + } else { + /* + * What can I do if we can't remount the existing + * mount(s) (possibly a partial failure), everything + * following will be broken? + */ + if (type == indirect) + do_remount_indirect(ap, fd, path); + else + do_remount_direct(ap, fd, path); + } + + return REMOUNT_SUCCESS; +} + +int umount_ent(struct autofs_point *ap, const char *path) +{ + struct stat st; + struct statfs fs; + int sav_errno; + int status, is_smbfs = 0; + int ret, rv = 1; + + ret = statfs(path, &fs); + if (ret == -1) { + warn(ap->logopt, "could not stat fs of %s", path); + is_smbfs = 0; + } else { + int cifsfs = fs.f_type == (__SWORD_TYPE) CIFS_MAGIC_NUMBER; + int smbfs = fs.f_type == (__SWORD_TYPE) SMB_SUPER_MAGIC; + is_smbfs = (cifsfs | smbfs) ? 1 : 0; + } + + status = lstat(path, &st); + sav_errno = errno; + + if (status < 0) + warn(ap->logopt, "lstat of %s failed with %d", path, status); + + /* + * lstat failed and we're an smbfs fs returning an error that is not + * EIO or EBADSLT or the lstat failed so it's a bad path. Return + * a fail. + * + * EIO appears to correspond to an smb mount that has gone away + * and EBADSLT relates to CD changer not responding. + */ + if (!status && (S_ISDIR(st.st_mode) && st.st_dev != ap->dev)) { + rv = spawn_umount(ap->logopt, path, NULL); + } else if (is_smbfs && (sav_errno == EIO || sav_errno == EBADSLT)) { + rv = spawn_umount(ap->logopt, path, NULL); + } + + /* We are doing a forced shutcwdown down so unlink busy mounts */ + if (rv && (ap->state == ST_SHUTDOWN_FORCE || ap->state == ST_SHUTDOWN)) { + ret = stat(path, &st); + if (ret == -1 && errno == ENOENT) { + warn(ap->logopt, "mount point does not exist"); + return 0; + } + + if (ret == 0 && !S_ISDIR(st.st_mode)) { + warn(ap->logopt, "mount point is not a directory"); + return 0; + } + + if (ap->state == ST_SHUTDOWN_FORCE) { + info(ap->logopt, "forcing umount of %s", path); + rv = spawn_umount(ap->logopt, "-l", path, NULL); + } + + /* + * Verify that we actually unmounted the thing. This is a + * belt and suspenders approach to not eating user data. + * We have seen cases where umount succeeds, but there is + * still a file system mounted on the mount point. How + * this happens has not yet been determined, but we want to + * make sure to return failure here, if that is the case, + * so that we do not try to call rmdir_path on the + * directory. + */ + if (!rv && is_mounted(_PATH_MOUNTED, path, MNTS_REAL)) { + crit(ap->logopt, + "the umount binary reported that %s was " + "unmounted, but there is still something " + "mounted on this path.", path); + rv = -1; + } + } + + return rv; +} + +int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) +{ + char path[PATH_MAX + 1]; + char *offset = path; + struct mapent *oe; + struct list_head *pos = NULL; + unsigned int fs_path_len; + unsigned int mounted; + int start; + + fs_path_len = strlen(root) + strlen(base); + if (fs_path_len > PATH_MAX) + return -1; + + strcpy(path, root); + strcat(path, base); + + mounted = 0; + start = strlen(root); + offset = cache_get_offset(base, offset, start, &me->multi_list, &pos); + while (offset) { + int plen = fs_path_len + strlen(offset); + + if (plen > PATH_MAX) { + warn(ap->logopt, "path loo long"); + goto cont; + } + + oe = cache_lookup_offset(base, offset, start, &me->multi_list); + if (!oe) + goto cont; + + debug(ap->logopt, "mount offset %s", oe->key); + + if (mount_autofs_offset(ap, oe) < 0) + warn(ap->logopt, "failed to mount offset"); + else + mounted++; +cont: + offset = cache_get_offset(base, + offset, start, &me->multi_list, &pos); + } + + return mounted; +} + +int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) +{ + char path[PATH_MAX + 1]; + char *offset; + struct mapent *oe; + struct list_head *mm_root, *pos; + const char o_root[] = "/"; + const char *mm_base; + int left, start; + + left = 0; + start = strlen(root); + + mm_root = &me->multi->multi_list; + + if (!base) + mm_base = o_root; + else + mm_base = base; + + pos = NULL; + offset = path; + + /* Make sure "none" of the offsets have an active mount. */ + while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) { + char *oe_base; + + oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); + /* root offset is a special case */ + if (!oe || (strlen(oe->key) - start) == 1) + continue; + + /* + * Check for and umount subtree offsets resulting from + * nonstrict mount fail. + */ + oe_base = oe->key + strlen(root); + left += umount_multi_triggers(ap, root, oe, oe_base); + + if (oe->ioctlfd != -1) + left++; + } + + if (left) + return left; + + pos = NULL; + offset = path; + + /* Make sure "none" of the offsets have an active mount. */ + while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) { + oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); + /* root offset is a special case */ + if (!oe || (strlen(oe->key) - start) == 1) + continue; + + debug(ap->logopt, "umount offset %s", oe->key); + + if (umount_autofs_offset(ap, oe)) { + warn(ap->logopt, "failed to umount offset"); + left++; + } + } + + if (!left && me->multi == me) { + struct mapent_cache *mc = me->mc; + int status; + + /* + * Special case. + * If we can't umount the root container then we can't + * delete the offsets from the cache and we need to put + * the offset triggers back. + */ + if (is_mounted(_PATH_MOUNTED, root, MNTS_REAL)) { + info(ap->logopt, "unmounting dir = %s", root); + if (umount_ent(ap, root)) { + if (!mount_multi_triggers(ap, root, me, "/")) + warn(ap->logopt, + "failed to remount offset triggers"); + return left++; + } + } + + /* We're done - clean out the offsets */ + status = cache_delete_offset_list(mc, me->key); + if (status != CHE_OK) + warn(ap->logopt, "couldn't delete offset list"); + } + + return left; +} + diff -up autofs-5.0.3/lib/cache.c.active-restart autofs-5.0.3/lib/cache.c --- autofs-5.0.3/lib/cache.c.active-restart 2008-01-14 13:39:16.000000000 +0900 +++ autofs-5.0.3/lib/cache.c 2008-02-25 09:16:46.000000000 +0900 @@ -111,14 +111,29 @@ void cache_lock_cleanup(void *arg) return; } -void cache_multi_lock(struct mapent *me) +void cache_multi_readlock(struct mapent *me) { int status; if (!me) return; - status = pthread_mutex_lock(&me->multi_mutex); + status = pthread_rwlock_rdlock(&me->multi_rwlock); + if (status) { + logmsg("mapent cache multi mutex lock failed"); + fatal(status); + } + return; +} + +void cache_multi_writelock(struct mapent *me) +{ + int status; + + if (!me) + return; + + status = pthread_rwlock_wrlock(&me->multi_rwlock); if (status) { logmsg("mapent cache multi mutex lock failed"); fatal(status); @@ -133,7 +148,7 @@ void cache_multi_unlock(struct mapent *m if (!me) return; - status = pthread_mutex_unlock(&me->multi_mutex); + status = pthread_rwlock_unlock(&me->multi_rwlock); if (status) { logmsg("mapent cache multi mutex unlock failed"); fatal(status); @@ -553,8 +568,9 @@ int cache_add(struct mapent_cache *mc, s me->ioctlfd = -1; me->dev = (dev_t) -1; me->ino = (ino_t) -1; + me->dir_created = 0; - status = pthread_mutex_init(&me->multi_mutex, NULL); + status = pthread_rwlock_init(&me->multi_rwlock, NULL); if (status) fatal(status); @@ -760,7 +776,7 @@ int cache_delete(struct mapent_cache *mc goto done; } pred->next = me->next; - status = pthread_mutex_destroy(&me->multi_mutex); + status = pthread_rwlock_destroy(&me->multi_rwlock); if (status) fatal(status); ino_index_lock(mc); @@ -784,7 +800,7 @@ int cache_delete(struct mapent_cache *mc goto done; } mc->hash[hashval] = me->next; - status = pthread_mutex_destroy(&me->multi_mutex); + status = pthread_rwlock_destroy(&me->multi_rwlock); if (status) fatal(status); ino_index_lock(mc); diff -up autofs-5.0.3/lib/master.c.active-restart autofs-5.0.3/lib/master.c --- autofs-5.0.3/lib/master.c.active-restart 2008-02-25 09:16:05.000000000 +0900 +++ autofs-5.0.3/lib/master.c 2008-02-25 09:16:46.000000000 +0900 @@ -997,28 +997,31 @@ next: static int master_do_mount(struct master_mapent *entry) { + struct startup_cond suc; struct autofs_point *ap; pthread_t thid; int status; - status = pthread_mutex_lock(&suc.mutex); - if (status) - fatal(status); + ap = entry->ap; + + if (handle_mounts_startup_cond_init(&suc)) { + crit(ap->logopt, + "failed to init startup cond for mount %s", entry->path); + return 0; + } + suc.ap = ap; suc.done = 0; suc.status = 0; - ap = entry->ap; - debug(ap->logopt, "mounting %s", entry->path); - if (pthread_create(&thid, &thread_attr, handle_mounts, ap)) { + status = pthread_create(&thid, &thread_attr, handle_mounts, &suc); + if (status) { crit(ap->logopt, "failed to create mount handler thread for %s", entry->path); - status = pthread_mutex_unlock(&suc.mutex); - if (status) - fatal(status); + handle_mounts_startup_cond_destroy(&suc); return 0; } entry->thid = thid; @@ -1031,15 +1034,11 @@ static int master_do_mount(struct master if (suc.status) { error(ap->logopt, "failed to startup mount"); - status = pthread_mutex_unlock(&suc.mutex); - if (status) - fatal(status); + handle_mounts_startup_cond_destroy(&suc); return 0; } - status = pthread_mutex_unlock(&suc.mutex); - if (status) - fatal(status); + handle_mounts_startup_cond_destroy(&suc); return 1; } diff -up autofs-5.0.3/CHANGELOG.active-restart autofs-5.0.3/CHANGELOG --- autofs-5.0.3/CHANGELOG.active-restart 2008-02-25 09:16:05.000000000 +0900 +++ autofs-5.0.3/CHANGELOG 2008-02-25 09:16:46.000000000 +0900 @@ -9,6 +9,7 @@ - fix expire working harder than needed. - fix unlink of mount tree incorrectly causing autofs mount fail. - add miscellaneous device node interface library. +- use miscellaneous device node, if available, for active restart. 14/01/2008 autofs-5.0.3 -----------------------