From e6cf324f87156e269fc6383e8c856c55979425d4 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Feb 25 2008 00:40:55 +0000 Subject: - fix expire calling kernel more often 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. - device node and active restart fixes. - update is_mounted to use device node ioctl, if available. --- diff --git a/autofs-5.0.3-active-restart.patch b/autofs-5.0.3-active-restart.patch new file mode 100644 index 0000000..6bdb36c --- /dev/null +++ b/autofs-5.0.3-active-restart.patch @@ -0,0 +1,2254 @@ +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 + ----------------------- diff --git a/autofs-5.0.3-device-node-and-active-restart-fixes.patch b/autofs-5.0.3-device-node-and-active-restart-fixes.patch new file mode 100644 index 0000000..3f660f1 --- /dev/null +++ b/autofs-5.0.3-device-node-and-active-restart-fixes.patch @@ -0,0 +1,134 @@ +diff --git a/include/dev-ioctl-lib.h b/include/dev-ioctl-lib.h +index 5851c4c..007d7a6 100644 +--- a/include/dev-ioctl-lib.h ++++ b/include/dev-ioctl-lib.h +@@ -26,7 +26,7 @@ + + #define CONTROL_DEVICE "/dev/autofs" + +-#define DEV_IOCTL_IS_MOUNTED 0x0001 ++#define DEV_IOCTL_IS_MOUNTPOINT 0x0001 + #define DEV_IOCTL_IS_AUTOFS 0x0002 + #define DEV_IOCTL_IS_OTHER 0x0004 + +diff --git a/include/mounts.h b/include/mounts.h +index ca7dee9..679a508 100644 +--- a/include/mounts.h ++++ b/include/mounts.h +@@ -65,7 +65,7 @@ struct mnt_list { + 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_options_string(char *path, int kernel_pipefd, const 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); +diff --git a/lib/dev-ioctl-lib.c b/lib/dev-ioctl-lib.c +index 8d4be77..719747f 100644 +--- a/lib/dev-ioctl-lib.c ++++ b/lib/dev-ioctl-lib.c +@@ -698,11 +698,18 @@ static int ioctl_askumount(unsigned int logopt, + /* + * Check if the given path is a mountpoint. + * +- * The path is considered a mountpoint if it is itself a mountpoint +- * or contains a mount, such as a multi-mount without a root mount. +- * In addition, if the path is itself a mountpoint we return whether +- * the mounted file system is an autofs filesystem or other file +- * system. ++ * If we supply a file descriptor of an autofs mount we're ++ * looking for a specific mount. In this case the path is ++ * considered a mountpoint if it is itself a mountpoint or ++ * contains a mount, such as a multi-mount without a root ++ * mount. ++ * ++ * If we don't supply a file descriptor then we just want ++ * to know if the given path is an autofs mount point or ++ * is mounted within an autofs filesystem. ++ * ++ * In both cases we get an indication of whether the path ++ * is a mount point and the super magic of the top mount. + */ + static int dev_ioctl_ismountpoint(unsigned int logopt, + int ioctlfd, const char *path, +@@ -731,7 +738,7 @@ static int dev_ioctl_ismountpoint(unsigned int logopt, + } + + if (param->arg1) { +- *mountpoint = DEV_IOCTL_IS_MOUNTED; ++ *mountpoint = DEV_IOCTL_IS_MOUNTPOINT; + + if (param->arg2) { + if (param->arg2 == AUTOFS_SUPER_MAGIC) +diff --git a/lib/mounts.c b/lib/mounts.c +index 959fe99..ba49099 100644 +--- a/lib/mounts.c ++++ b/lib/mounts.c +@@ -129,7 +129,7 @@ unsigned int get_kver_minor(void) + /* + * Make common autofs mount options string + */ +-char *make_options_string(char *path, int pipefd, char *extra) ++char *make_options_string(char *path, int pipefd, const char *extra) + { + char *options; + int len; +@@ -1207,8 +1207,8 @@ free_tsv: + const char *mount_type_str(const unsigned int type) + { + static const char *str_type[] = { +- "direct", + "indirect", ++ "direct", + "offset" + }; + unsigned int pos, i; +@@ -1225,13 +1225,13 @@ void notify_mount_result(struct autofs_point *ap, + { + if (ap->exp_timeout) + info(ap->logopt, +- "mounted %s on %s with timeout %u, freq %u seconds", ++ "mounted %s mount 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", ++ "mounted %s mount on %s with timeouts disabled", + type, path); + + return; +diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c +index 1a9bef2..d493cde 100644 +--- a/modules/mount_nfs.c ++++ b/modules/mount_nfs.c +@@ -173,6 +173,13 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + len = sprintf(fullpath, "%s", root); + fullpath[len] = '\0'; + ++ if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { ++ info(ap->logopt, MODPREFIX ++ "%s is already mounted or is being re-mounted", fullpath); ++ free_host_list(&hosts); ++ return 0; ++ } ++ + debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath); + + status = mkdir_path(fullpath, 0555); +@@ -197,13 +204,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int + while (this) { + char *loc, *port_opt = NULL; + +- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { +- info(ap->logopt, MODPREFIX +- "%s is already mounted or is being re-mounted", fullpath); +- free_host_list(&hosts); +- return 0; +- } +- + /* + * If the "port" option is specified, then we don't want + * a bind mount. Use the "port" option if you want to diff --git a/autofs-5.0.3-device-node-control.patch b/autofs-5.0.3-device-node-control.patch new file mode 100644 index 0000000..d9c24b3 --- /dev/null +++ b/autofs-5.0.3-device-node-control.patch @@ -0,0 +1,2422 @@ +diff -up autofs-5.0.3/daemon/indirect.c.device-node-control autofs-5.0.3/daemon/indirect.c +--- autofs-5.0.3/daemon/indirect.c.device-node-control 2008-02-25 08:58:46.000000000 +0900 ++++ autofs-5.0.3/daemon/indirect.c 2008-02-25 09:03:12.000000000 +0900 +@@ -43,6 +43,8 @@ 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; +@@ -88,19 +90,20 @@ static int unlink_mount_tree(struct auto + + static int do_mount_autofs_indirect(struct autofs_point *ap) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + time_t timeout = ap->exp_timeout; + char *options = NULL; + const char *type, *map_name = NULL; + struct stat st; + struct mnt_list *mnts; +- int cl_flags, ret; ++ int ret; + + mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 1); + if (mnts) { + ret = unlink_mount_tree(ap, mnts); + free_mnt_list(mnts); + if (!ret) { +- debug(ap->logopt, ++ error(ap->logopt, + "already mounted as other than autofs " + "or failed to unlink entry in tree"); + goto out_err; +@@ -108,8 +111,10 @@ static int do_mount_autofs_indirect(stru + } + + options = make_options_string(ap->path, ap->kpipefd, NULL); +- if (!options) ++ if (!options) { ++ error(ap->logopt, "options string error"); + goto out_err; ++ } + + /* In case the directory doesn't exist, try to mkdir it */ + if (mkdir_path(ap->path, 0555) < 0) { +@@ -147,22 +152,15 @@ static int do_mount_autofs_indirect(stru + + options = NULL; + +- /* Root directory for ioctl()'s */ +- ap->ioctlfd = open(ap->path, O_RDONLY); +- if (ap->ioctlfd < 0) { ++ if (ops->open(ap->logopt, &ap->ioctlfd, -1, ap->path, indirect)) { + crit(ap->logopt, + "failed to create ioctl fd for autofs path %s", ap->path); + goto out_umount; + } + +- if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) != -1) { +- cl_flags |= FD_CLOEXEC; +- fcntl(ap->ioctlfd, F_SETFD, cl_flags); +- } +- + ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO; + +- ioctl(ap->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout); ++ ops->timeout(ap->logopt, ap->ioctlfd, &timeout); + + if (ap->exp_timeout) + info(ap->logopt, +@@ -235,8 +233,10 @@ int mount_autofs_indirect(struct autofs_ + + int umount_autofs_indirect(struct autofs_point *ap) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + char buf[MAX_ERR_BUF]; +- int ret, rv, retries; ++ int rv, retries; ++ unsigned int ret; + + /* + * Since submounts look after themselves the parent never knows +@@ -248,7 +248,7 @@ int umount_autofs_indirect(struct autofs + lookup_source_close_ioctlfd(ap->parent, ap->path); + + /* If we are trying to shutdown make sure we can umount */ +- rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret); ++ rv = ops->askumount(ap->logopt, ap->ioctlfd, &ret); + if (rv == -1) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + logerr("ioctl failed: %s", estr); +@@ -258,8 +258,8 @@ int umount_autofs_indirect(struct autofs + return 1; + } + +- ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0); +- close(ap->ioctlfd); ++ ops->catatonic(ap->logopt, ap->ioctlfd); ++ ops->close(ap->logopt, ap->ioctlfd); + ap->ioctlfd = -1; + close(ap->state_pipe[0]); + close(ap->state_pipe[1]); +@@ -320,48 +320,6 @@ force_umount: + return rv; + } + +-static int expire_indirect(struct autofs_point *ap, int ioctlfd, const char *path, unsigned int when) +-{ +- char buf[MAX_ERR_BUF]; +- int ret, retries; +- struct stat st; +- +- if (fstat(ioctlfd, &st) == -1) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- debug(ap->logopt, "fstat failed: %s", estr); +- return 0; +- } +- +- retries = (count_mounts(ap->logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES; +- +- while (retries--) { +- struct timespec tm = {0, 100000000}; +- +- /* Ggenerate expire message for the mount. */ +- ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when); +- if (ret == -1) { +- /* Mount has gone away */ +- if (errno == EBADF || errno == EINVAL) +- return 1; +- +- /* +- * Other than EAGAIN is an expire error so continue. +- * Kernel will try the next mount. +- */ +- if (errno == EAGAIN) +- break; +- } +- nanosleep(&tm, NULL); +- } +- +- if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) { +- if (!ret) +- return 0; +- } +- +- return 1; +-} +- + static void mnts_cleanup(void *arg) + { + struct mnt_list *mnts = (struct mnt_list *) arg; +@@ -371,6 +329,7 @@ static void mnts_cleanup(void *arg) + + void *expire_proc_indirect(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct autofs_point *ap; + struct mapent *me = NULL; + struct mnt_list *mnts = NULL, *next; +@@ -458,8 +417,8 @@ void *expire_proc_indirect(void *arg) + debug(ap->logopt, "expire %s", next->path); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); +- ret = expire_indirect(ap, ioctlfd, next->path, now); +- if (!ret) ++ ret = ops->expire(ap->logopt, ioctlfd, next->path, now); ++ if (ret) + left++; + pthread_setcancelstate(cur_state, NULL); + } +@@ -472,8 +431,8 @@ void *expire_proc_indirect(void *arg) + */ + if (mnts) { + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); +- ret = expire_indirect(ap, ap->ioctlfd, ap->path, now); +- if (!ret) ++ ret = ops->expire(ap->logopt, ap->ioctlfd, ap->path, now); ++ if (ret) + left++; + pthread_setcancelstate(cur_state, NULL); + } +@@ -495,8 +454,8 @@ void *expire_proc_indirect(void *arg) + pthread_cleanup_pop(1); + + if (submnts) +- debug(ap->logopt, +- "%d submounts remaining in %s", submnts, ap->path); ++ info(ap->logopt, ++ "%d submounts remaining in %s", submnts, ap->path); + + /* + * EXPIRE_MULTI is synchronous, so we can be sure (famous last +@@ -527,8 +486,11 @@ static void pending_cond_destroy(void *a + + static void expire_send_fail(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct pending_args *mt = arg; +- send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token); ++ struct autofs_point *ap = mt->ap; ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, mt->wait_queue_token, -ENOENT); + } + + static void free_pending_args(void *arg) +@@ -546,6 +508,7 @@ static void expire_mutex_unlock(void *ar + + static void *do_expire_indirect(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct pending_args *mt; + struct autofs_point *ap; + int status, state; +@@ -572,9 +535,11 @@ static void *do_expire_indirect(void *ar + status = do_expire(mt->ap, mt->name, mt->len); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + if (status) +- send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token); ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, mt->wait_queue_token, -status); + else +- send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token); ++ ops->send_ready(ap->logopt, ++ ap->ioctlfd, mt->wait_queue_token); + pthread_setcancelstate(state, NULL); + + pthread_cleanup_pop(0); +@@ -586,6 +551,7 @@ static void *do_expire_indirect(void *ar + + int handle_packet_expire_indirect(struct autofs_point *ap, autofs_packet_expire_indirect_t *pkt) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct pending_args *mt; + char buf[MAX_ERR_BUF]; + pthread_t thid; +@@ -600,7 +566,8 @@ int handle_packet_expire_indirect(struct + if (!mt) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + logerr("malloc: %s", estr); +- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, pkt->wait_queue_token, -ENOMEM); + pthread_setcancelstate(state, NULL); + return 1; + } +@@ -622,7 +589,8 @@ int handle_packet_expire_indirect(struct + status = pthread_create(&thid, &thread_attr, do_expire_indirect, mt); + if (status) { + error(ap->logopt, "expire thread create failed"); +- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, pkt->wait_queue_token, -status); + expire_mutex_unlock(NULL); + pending_cond_destroy(mt); + free_pending_args(mt); +@@ -647,8 +615,11 @@ int handle_packet_expire_indirect(struct + + static void mount_send_fail(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct pending_args *mt = arg; +- send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token); ++ struct autofs_point *ap = mt->ap; ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, mt->wait_queue_token, -ENOENT); + } + + static void mount_mutex_unlock(void *arg) +@@ -660,6 +631,7 @@ static void mount_mutex_unlock(void *arg + + static void *do_mount_indirect(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct pending_args *mt; + struct autofs_point *ap; + char buf[PATH_MAX + 1]; +@@ -837,10 +809,13 @@ cont: + status = lookup_nss_mount(ap, NULL, mt->name, mt->len); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + if (status) { +- send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token); ++ ops->send_ready(ap->logopt, ++ ap->ioctlfd, mt->wait_queue_token); + info(ap->logopt, "mounted %s", buf); + } else { +- send_fail(ap->logopt, ap->ioctlfd, mt->wait_queue_token); ++ /* TODO: get mount return status from lookup_nss_mount */ ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, mt->wait_queue_token, -ENOENT); + info(ap->logopt, "failed to mount %s", buf); + } + pthread_setcancelstate(state, NULL); +@@ -854,6 +829,7 @@ cont: + + int handle_packet_missing_indirect(struct autofs_point *ap, autofs_packet_missing_indirect_t *pkt) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + pthread_t thid; + char buf[MAX_ERR_BUF]; + struct pending_args *mt; +@@ -868,7 +844,8 @@ int handle_packet_missing_indirect(struc + if (ap->shutdown || + ap->state == ST_SHUTDOWN_FORCE || + ap->state == ST_SHUTDOWN) { +- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, pkt->wait_queue_token, -ENOENT); + pthread_setcancelstate(state, NULL); + return 0; + } +@@ -877,7 +854,8 @@ int handle_packet_missing_indirect(struc + if (!mt) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + logerr("malloc: %s", estr); +- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, pkt->wait_queue_token, -ENOMEM); + pthread_setcancelstate(state, NULL); + return 1; + } +@@ -903,7 +881,8 @@ int handle_packet_missing_indirect(struc + status = pthread_create(&thid, &thread_attr, do_mount_indirect, mt); + if (status) { + error(ap->logopt, "expire thread create failed"); +- send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); ++ ops->send_fail(ap->logopt, ++ ap->ioctlfd, pkt->wait_queue_token, -status); + mount_mutex_unlock(NULL); + pending_cond_destroy(mt); + free_pending_args(mt); +diff -up autofs-5.0.3/daemon/state.c.device-node-control autofs-5.0.3/daemon/state.c +--- autofs-5.0.3/daemon/state.c.device-node-control 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/daemon/state.c 2008-02-25 09:03:12.000000000 +0900 +@@ -93,6 +93,7 @@ void nextstate(int statefd, enum states + */ + void expire_cleanup(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + pthread_t thid = pthread_self(); + struct expire_args *ec; + struct autofs_point *ap; +@@ -113,7 +114,8 @@ void expire_cleanup(void *arg) + + /* Check to see if expire process finished */ + if (thid == ap->exp_thread) { +- int rv, idle; ++ unsigned int idle; ++ int rv; + + ap->exp_thread = 0; + +@@ -135,7 +137,7 @@ void expire_cleanup(void *arg) + * allowing it to shutdown. + */ + if (ap->submount && !success) { +- rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &idle); ++ rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle); + if (!rv && idle && ap->submount > 1) { + next = ST_SHUTDOWN_PENDING; + break; +@@ -160,7 +162,7 @@ void expire_cleanup(void *arg) + * shutdown return to ready state unless we have + * been signaled to shutdown. + */ +- rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &idle); ++ rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle); + if (!idle && !ap->shutdown) { + next = ST_READY; + if (!ap->submount) +diff -up autofs-5.0.3/daemon/lookup.c.device-node-control autofs-5.0.3/daemon/lookup.c +--- autofs-5.0.3/daemon/lookup.c.device-node-control 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/daemon/lookup.c 2008-02-25 09:03:12.000000000 +0900 +@@ -1148,7 +1148,8 @@ int lookup_source_close_ioctlfd(struct a + me = cache_lookup_distinct(mc, key); + if (me) { + if (me->ioctlfd != -1) { +- close(me->ioctlfd); ++ struct ioctl_ops *ops = get_ioctl_ops(); ++ ops->close(ap->logopt, me->ioctlfd); + me->ioctlfd = -1; + } + cache_unlock(mc); +diff -up autofs-5.0.3/daemon/direct.c.device-node-control autofs-5.0.3/daemon/direct.c +--- autofs-5.0.3/daemon/direct.c.device-node-control 2008-02-25 08:58:46.000000000 +0900 ++++ autofs-5.0.3/daemon/direct.c 2008-02-25 09:03:12.000000000 +0900 +@@ -42,6 +42,9 @@ + + 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; + }; +@@ -88,6 +91,7 @@ static void mnts_cleanup(void *arg) + + int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + char buf[MAX_ERR_BUF]; + int ioctlfd, rv, left, retries; + +@@ -106,23 +110,13 @@ int do_umount_autofs_direct(struct autof + return 1; + } + ioctlfd = me->ioctlfd; +- } else { +- int cl_flags; +- +- ioctlfd = open(me->key, O_RDONLY); +- if (ioctlfd != -1) { +- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) { +- cl_flags |= FD_CLOEXEC; +- fcntl(ioctlfd, F_SETFD, cl_flags); +- } +- } +- } +- ++ } else ++ ops->open(ap->logopt, &ioctlfd, -1, me->key, direct); + + if (ioctlfd >= 0) { +- int status = 1; ++ unsigned int status = 1; + +- rv = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &status); ++ rv = ops->askumount(ap->logopt, ioctlfd, &status); + if (rv) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(ap->logopt, "ioctl failed: %s", estr); +@@ -135,19 +129,17 @@ int do_umount_autofs_direct(struct autof + return 1; + } else { + me->ioctlfd = -1; +- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0); +- close(ioctlfd); ++ ops->catatonic(ap->logopt, ioctlfd); ++ ops->close(ap->logopt, ioctlfd); + goto force_umount; + } + } + me->ioctlfd = -1; +- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0); +- close(ioctlfd); ++ ops->catatonic(ap->logopt, ioctlfd); ++ ops->close(ap->logopt, ioctlfd); + } else { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(ap->logopt, + "couldn't get ioctl fd for direct mount %s", me->key); +- debug(ap->logopt, "open: %s", estr); + return 1; + } + +@@ -297,10 +289,11 @@ static int unlink_mount_tree(struct auto + + int do_mount_autofs_direct(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, cl_flags; ++ int status, ret, ioctlfd; + struct list_head list; + const char *map_name; + +@@ -313,16 +306,8 @@ int do_mount_autofs_direct(struct autofs + + save_ioctlfd = ioctlfd = me->ioctlfd; + +- if (ioctlfd == -1) { +- ioctlfd = open(me->key, O_RDONLY); +- if (ioctlfd != -1) { +- cl_flags = fcntl(ioctlfd, F_GETFD, 0); +- if (cl_flags != -1) { +- cl_flags |= FD_CLOEXEC; +- fcntl(ioctlfd, F_SETFD, cl_flags); +- } +- } +- } ++ if (ioctlfd == -1) ++ ops->open(ap->logopt, &ioctlfd, -1, me->key, direct); + + if (ioctlfd < 0) { + error(ap->logopt, +@@ -331,13 +316,14 @@ int do_mount_autofs_direct(struct autofs + return 0; + } + +- ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &tout); ++ ops->timeout(ap->logopt, ioctlfd, &tout); + + if (save_ioctlfd == -1) +- close(ioctlfd); ++ ops->close(ap->logopt, ioctlfd); + + return 0; + } ++ + if (!unlink_mount_tree(ap, &list)) { + debug(ap->logopt, + "already mounted as other than autofs " +@@ -402,22 +388,16 @@ int do_mount_autofs_direct(struct autofs + goto out_err; + } + +- /* Root directory for ioctl()'s */ +- ioctlfd = open(me->key, O_RDONLY); ++ ops->open(ap->logopt, &ioctlfd, -1, me->key, direct); + if (ioctlfd < 0) { + crit(ap->logopt, "failed to create ioctl fd for %s", me->key); + goto out_umount; + } + +- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) { +- cl_flags |= FD_CLOEXEC; +- fcntl(ioctlfd, F_SETFD, cl_flags); +- } +- + /* Calculate the timeouts */ + ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO; + +- ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout); ++ ops->timeout(ap->logopt, ioctlfd, &timeout); + + if (ap->exp_timeout) + info(ap->logopt, +@@ -438,14 +418,14 @@ int do_mount_autofs_direct(struct autofs + } + cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino); + +- close(ioctlfd); ++ ops->close(ap->logopt, ioctlfd); + + debug(ap->logopt, "mounted trigger %s", me->key); + + return 0; + + out_close: +- close(ioctlfd); ++ ops->close(ap->logopt, ioctlfd); + out_umount: + /* TODO: maybe force umount (-l) */ + umount(me->key); +@@ -537,8 +517,9 @@ int mount_autofs_direct(struct autofs_po + + int umount_autofs_offset(struct autofs_point *ap, struct mapent *me) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + char buf[MAX_ERR_BUF]; +- int ioctlfd, cl_flags, rv = 1, retries; ++ int ioctlfd, rv = 1, retries; + + if (me->ioctlfd != -1) { + if (is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL)) { +@@ -555,20 +536,13 @@ int umount_autofs_offset(struct autofs_p + me->key); + return 0; + } +- +- ioctlfd = open(me->key, O_RDONLY); +- if (ioctlfd != -1) { +- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) { +- cl_flags |= FD_CLOEXEC; +- fcntl(ioctlfd, F_SETFD, cl_flags); +- } +- } ++ ops->open(ap->logopt, &ioctlfd, -1, me->key, offset); + } + + if (ioctlfd >= 0) { +- int status = 1; ++ unsigned int status = 1; + +- rv = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &status); ++ rv = ops->askumount(ap->logopt, ioctlfd, &status); + if (rv) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + logerr("ioctl failed: %s", estr); +@@ -581,14 +555,14 @@ int umount_autofs_offset(struct autofs_p + return 1; + } else { + me->ioctlfd = -1; +- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0); +- close(ioctlfd); ++ ops->catatonic(ap->logopt, ioctlfd); ++ ops->close(ap->logopt, ioctlfd); + goto force_umount; + } + } + me->ioctlfd = -1; +- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0); +- close(ioctlfd); ++ ops->catatonic(ap->logopt, ioctlfd); ++ ops->close(ap->logopt, ioctlfd); + } else { + struct stat st; + char *estr; +@@ -653,11 +627,12 @@ force_umount: + + int mount_autofs_offset(struct autofs_point *ap, struct mapent *me) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + char buf[MAX_ERR_BUF]; + struct mnt_params *mp; + time_t timeout = ap->exp_timeout; + struct stat st; +- int ioctlfd, cl_flags, status, ret; ++ int ioctlfd, status, ret; + const char *type, *map_name = NULL; + + if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) { +@@ -760,19 +735,13 @@ int mount_autofs_offset(struct autofs_po + goto out_err; + } + +- /* Root directory for ioctl()'s */ +- ioctlfd = open(me->key, O_RDONLY); ++ 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; + } + +- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) { +- cl_flags |= FD_CLOEXEC; +- fcntl(ioctlfd, F_SETFD, cl_flags); +- } +- +- ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, &timeout); ++ ops->timeout(ap->logopt, ioctlfd, &timeout); + + ret = fstat(ioctlfd, &st); + if (ret == -1) { +@@ -783,14 +752,14 @@ int mount_autofs_offset(struct autofs_po + + cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino); + +- close(ioctlfd); ++ ops->close(ap->logopt, ioctlfd); + + debug(ap->logopt, "mounted trigger %s", me->key); + + return 0; + + out_close: +- close(ioctlfd); ++ ops->close(ap->logopt, ioctlfd); + out_umount: + umount(me->key); + out_err: +@@ -800,53 +769,9 @@ out_err: + return -1; + } + +-static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt) +-{ +- char buf[MAX_ERR_BUF]; +- int ret, retries; +- struct stat st; +- +- if (fstat(ioctlfd, &st) == -1) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- debug(logopt, "fstat failed: %s", estr); +- return 0; +- } +- +- retries = (count_mounts(logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES; +- +- while (retries--) { +- struct timespec tm = {0, 100000000}; +- +- /* Ggenerate expire message for the mount. */ +- ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when); +- if (ret == -1) { +- /* Mount has gone away */ +- if (errno == EBADF || errno == EINVAL) +- return 1; +- +- /* +- * Other than EAGAIN is an expire error so continue. +- * Kernel try the same mount again, limited by +- * retries (ie. number of mounts directly under +- * mount point, should always be one for direct +- * mounts). +- */ +- if (errno == EAGAIN) +- break; +- } +- nanosleep(&tm, NULL); +- } +- +- if (!ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) { +- if (!ret) +- return 0; +- } +- +- return 1; +-} +- + void *expire_proc_direct(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct mnt_list *mnts = NULL, *next; + struct list_head list, *p; + struct expire_args *ea; +@@ -958,8 +883,8 @@ void *expire_proc_direct(void *arg) + + ioctlfd = me->ioctlfd; + +- ret = expire_direct(ioctlfd, next->path, now, ap->logopt); +- if (!ret) { ++ ret = ops->expire(ap->logopt, ioctlfd, next->path, now); ++ if (ret) { + left++; + pthread_setcancelstate(cur_state, NULL); + continue; +@@ -991,8 +916,8 @@ void *expire_proc_direct(void *arg) + debug(ap->logopt, "send expire to trigger %s", next->path); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); +- ret = expire_direct(ioctlfd, next->path, now, ap->logopt); +- if (!ret) ++ ret = ops->expire(ap->logopt, ioctlfd, next->path, now); ++ if (ret) + left++; + pthread_setcancelstate(cur_state, NULL); + } +@@ -1023,8 +948,11 @@ static void pending_cond_destroy(void *a + + static void expire_send_fail(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct pending_args *mt = arg; +- send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token); ++ struct autofs_point *ap = mt->ap; ++ ops->send_fail(ap->logopt, ++ mt->ioctlfd, mt->wait_queue_token, -ENOENT); + } + + static void free_pending_args(void *arg) +@@ -1042,6 +970,7 @@ static void expire_mutex_unlock(void *ar + + static void *do_expire_direct(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct pending_args *mt; + struct autofs_point *ap; + size_t len; +@@ -1076,15 +1005,16 @@ static void *do_expire_direct(void *arg) + status = do_expire(ap, mt->name, len); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + if (status) +- send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token); ++ ops->send_fail(ap->logopt, ++ mt->ioctlfd, mt->wait_queue_token, -ENOENT); + else { + struct mapent *me; + cache_readlock(mt->mc); + me = cache_lookup_distinct(mt->mc, mt->name); + me->ioctlfd = -1; + cache_unlock(mt->mc); +- send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token); +- close(mt->ioctlfd); ++ ops->send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token); ++ ops->close(ap->logopt, mt->ioctlfd); + } + pthread_setcancelstate(state, NULL); + +@@ -1097,6 +1027,7 @@ static void *do_expire_direct(void *arg) + + int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_direct_t *pkt) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct map_source *map; + struct mapent_cache *mc = NULL; + struct mapent *me = NULL; +@@ -1146,7 +1077,8 @@ int handle_packet_expire_direct(struct a + if (!mt) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(ap->logopt, "malloc: %s", estr); +- send_fail(ap->logopt, me->ioctlfd, pkt->wait_queue_token); ++ ops->send_fail(ap->logopt, ++ me->ioctlfd, pkt->wait_queue_token, -ENOMEM); + cache_unlock(mc); + pthread_setcancelstate(state, NULL); + return 1; +@@ -1175,7 +1107,8 @@ int handle_packet_expire_direct(struct a + status = pthread_create(&thid, &thread_attr, do_expire_direct, mt); + if (status) { + error(ap->logopt, "expire thread create failed"); +- send_fail(ap->logopt, mt->ioctlfd, pkt->wait_queue_token); ++ ops->send_fail(ap->logopt, ++ mt->ioctlfd, pkt->wait_queue_token, -status); + cache_unlock(mc); + expire_mutex_unlock(NULL); + pending_cond_destroy(mt); +@@ -1203,9 +1136,11 @@ int handle_packet_expire_direct(struct a + + static void mount_send_fail(void *arg) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct pending_args *mt = arg; +- send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token); +- close(mt->ioctlfd); ++ struct autofs_point *ap = mt->ap; ++ ops->send_fail(ap->logopt, mt->ioctlfd, mt->wait_queue_token, -ENOENT); ++ ops->close(ap->logopt, mt->ioctlfd); + } + + static void mount_mutex_unlock(void *arg) +@@ -1217,6 +1152,7 @@ static void mount_mutex_unlock(void *arg + + 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; +@@ -1409,15 +1345,19 @@ cont: + cache_unlock(mt->mc); + if (set_fd) { + me->ioctlfd = mt->ioctlfd; +- send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token); ++ ops->send_ready(ap->logopt, ++ mt->ioctlfd, mt->wait_queue_token); + } else { +- send_ready(ap->logopt, mt->ioctlfd, mt->wait_queue_token); +- close(mt->ioctlfd); ++ ops->send_ready(ap->logopt, ++ mt->ioctlfd, mt->wait_queue_token); ++ ops->close(ap->logopt, mt->ioctlfd); + } + info(ap->logopt, "mounted %s", mt->name); + } else { +- send_fail(mt->ap->logopt, mt->ioctlfd, mt->wait_queue_token); +- close(mt->ioctlfd); ++ /* TODO: get mount return status from lookup_nss_mount */ ++ ops->send_fail(ap->logopt, ++ mt->ioctlfd, mt->wait_queue_token, -ENOENT); ++ ops->close(ap->logopt, mt->ioctlfd); + info(ap->logopt, "failed to mount %s", mt->name); + } + pthread_setcancelstate(state, NULL); +@@ -1431,6 +1371,7 @@ cont: + + int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_direct_t *pkt) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct map_source *map; + struct mapent_cache *mc = NULL; + struct mapent *me = NULL; +@@ -1438,7 +1379,8 @@ int handle_packet_missing_direct(struct + struct pending_args *mt; + char buf[MAX_ERR_BUF]; + int status = 0; +- int ioctlfd, cl_flags, state; ++ int ioctlfd, state; ++ unsigned int type; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + +@@ -1475,12 +1417,16 @@ int handle_packet_missing_direct(struct + return 1; + } + ++ type = direct; ++ if (me->multi != me && !list_empty(&me->multi_list)) ++ type = offset; ++ + if (me->ioctlfd != -1) { + /* Maybe someone did a manual umount, clean up ! */ + ioctlfd = me->ioctlfd; + me->ioctlfd = -1; + } else +- ioctlfd = open(me->key, O_RDONLY); ++ ops->open(ap->logopt, &ioctlfd, -1, me->key, type); + + if (ioctlfd == -1) { + cache_unlock(mc); +@@ -1490,11 +1436,6 @@ int handle_packet_missing_direct(struct + return 1; + } + +- if ((cl_flags = fcntl(ioctlfd, F_GETFD, 0)) != -1) { +- cl_flags |= FD_CLOEXEC; +- fcntl(ioctlfd, F_SETFD, cl_flags); +- } +- + debug(ap->logopt, "token %ld, name %s, request pid %u", + (unsigned long) pkt->wait_queue_token, me->key, pkt->pid); + +@@ -1502,8 +1443,9 @@ int handle_packet_missing_direct(struct + if (ap->shutdown || + ap->state == ST_SHUTDOWN_FORCE || + ap->state == ST_SHUTDOWN) { +- send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); +- close(ioctlfd); ++ ops->send_fail(ap->logopt, ++ ioctlfd, pkt->wait_queue_token, -ENOENT); ++ ops->close(ap->logopt, ioctlfd); + cache_unlock(mc); + pthread_setcancelstate(state, NULL); + return 1; +@@ -1513,8 +1455,9 @@ int handle_packet_missing_direct(struct + if (!mt) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + error(ap->logopt, "malloc: %s", estr); +- send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); +- close(ioctlfd); ++ ops->send_fail(ap->logopt, ++ ioctlfd, pkt->wait_queue_token, -ENOMEM); ++ ops->close(ap->logopt, ioctlfd); + cache_unlock(mc); + pthread_setcancelstate(state, NULL); + return 1; +@@ -1542,8 +1485,9 @@ int handle_packet_missing_direct(struct + status = pthread_create(&thid, &thread_attr, do_mount_direct, mt); + if (status) { + error(ap->logopt, "missing mount thread create failed"); +- send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); +- close(ioctlfd); ++ ops->send_fail(ap->logopt, ++ ioctlfd, pkt->wait_queue_token, -status); ++ ops->close(ap->logopt, ioctlfd); + cache_unlock(mc); + mount_mutex_unlock(NULL); + pending_cond_destroy(mt); +diff -up autofs-5.0.3/daemon/automount.c.device-node-control autofs-5.0.3/daemon/automount.c +--- autofs-5.0.3/daemon/automount.c.device-node-control 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/daemon/automount.c 2008-02-25 09:03:12.000000000 +0900 +@@ -579,40 +579,6 @@ int umount_autofs(struct autofs_point *a + return ret; + } + +-int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token) +-{ +- char buf[MAX_ERR_BUF]; +- +- if (wait_queue_token == 0) +- return 0; +- +- debug(logopt, "token = %d", wait_queue_token); +- +- if (ioctl(ioctlfd, AUTOFS_IOC_READY, wait_queue_token) < 0) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- logerr("AUTOFS_IOC_READY: error %s", estr); +- return 1; +- } +- return 0; +-} +- +-int send_fail(unsigned logopt, int ioctlfd, unsigned int wait_queue_token) +-{ +- char buf[MAX_ERR_BUF]; +- +- if (wait_queue_token == 0) +- return 0; +- +- debug(logopt, "token = %d", wait_queue_token); +- +- if (ioctl(ioctlfd, AUTOFS_IOC_FAIL, wait_queue_token) < 0) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- logerr("AUTOFS_IOC_FAIL: error %s", estr); +- return 1; +- } +- return 0; +-} +- + static size_t get_kpkt_len(void) + { + size_t pkt_len = sizeof(struct autofs_v5_packet); +@@ -1540,7 +1506,9 @@ void *handle_mounts(void *arg) + + while (ap->state != ST_SHUTDOWN) { + if (handle_packet(ap)) { +- int ret, result; ++ struct ioctl_ops *ops = get_ioctl_ops(); ++ unsigned int result; ++ int ret; + + state_mutex_lock(ap); + /* +@@ -1557,7 +1525,7 @@ void *handle_mounts(void *arg) + * If the ioctl fails assume the kernel doesn't have + * AUTOFS_IOC_ASKUMOUNT and just continue. + */ +- ret = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &result); ++ ret = ops->askumount(ap->logopt, ap->ioctlfd, &result); + if (ret == -1) { + state_mutex_unlock(ap); + break; +@@ -2055,6 +2023,8 @@ int main(int argc, char *argv[]) + exit(1); + } + ++ init_ioctl_ctl(); ++ + if (!alarm_start_handler()) { + logerr("%s: failed to create alarm handler thread!", program); + master_kill(master_list); +@@ -2099,6 +2069,8 @@ int main(int argc, char *argv[]) + if (dh) + dlclose(dh); + #endif ++ close_ioctl_ctl(); ++ + info(logging, "autofs stopped"); + + exit(0); +diff -up autofs-5.0.3/include/automount.h.device-node-control autofs-5.0.3/include/automount.h +--- autofs-5.0.3/include/automount.h.device-node-control 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/include/automount.h 2008-02-25 09:03:12.000000000 +0900 +@@ -29,6 +29,7 @@ + #include "log.h" + #include "rpc_subs.h" + #include "parse_subs.h" ++#include "dev-ioctl-lib.h" + + #ifdef WITH_DMALLOC + #include +@@ -70,6 +71,10 @@ 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 + +@@ -367,7 +372,7 @@ 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); +-char *find_mnt_ino(const char *table, dev_t dev, ino_t ino); ++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); +@@ -377,6 +382,7 @@ int tree_get_mnt_list(struct mnt_list *m + 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 */ + +@@ -470,8 +476,6 @@ struct autofs_point { + + void *handle_mounts(void *arg); + int umount_multi(struct autofs_point *ap, const char *path, int incl); +-int send_ready(unsigned logopt, int ioctlfd, unsigned int wait_queue_token); +-int send_fail(unsigned logopt, int ioctlfd, unsigned int wait_queue_token); + int do_expire(struct autofs_point *ap, const char *name, int namelen); + void *expire_proc_indirect(void *); + void *expire_proc_direct(void *); +diff -up /dev/null autofs-5.0.3/include/linux/auto_dev-ioctl.h +--- /dev/null 2008-02-25 17:16:11.149000952 +0900 ++++ autofs-5.0.3/include/linux/auto_dev-ioctl.h 2008-02-25 09:03:44.000000000 +0900 +@@ -0,0 +1,113 @@ ++/* ++ * linux/include/linux/auto_dev-ioctl.h ++ * ++ * Copyright 2008 Red Hat, Inc. All rights reserved. ++ * Copyright 2008 Ian Kent ++ * ++ * This file is part of the Linux kernel and is made available under ++ * the terms of the GNU General Public License, version 2, or at your ++ * option, any later version, incorporated herein by reference. ++ */ ++ ++#ifndef _LINUX_AUTO_DEV_IOCTL_H ++#define _LINUX_AUTO_DEV_IOCTL_H ++ ++#include ++ ++#define AUTOFS_DEV_IOCTL_VERSION_MAJOR 1 ++#define AUTOFS_DEV_IOCTL_VERSION_MINOR 0 ++ ++#define AUTOFS_DEVID_LEN 16 ++ ++/* ++ * An ioctl interface for autofs mount point control. ++ */ ++ ++/* ++ * All theioctls use this structure. ++ * When sending a path size must account for the total length ++ * of the chunk of memory. ++ */ ++ ++struct autofs_dev_ioctl { ++ __u32 ver_major; ++ __u32 ver_minor; ++ __u32 size; /* total size of data passed in ++ * including this struct */ ++ __s32 ioctlfd; /* automount command fd */ ++ ++ __u32 arg1; /* Command parameters */ ++ __u32 arg2; ++ ++ char path[0]; ++}; ++ ++static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in) ++{ ++ in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR; ++ in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR; ++ in->size = sizeof(struct autofs_dev_ioctl); ++ in->ioctlfd = -1; ++ in->arg1 = 0; ++ in->arg2 = 0; ++ return; ++} ++ ++/* ++ * If you change this make sure you make the corresponding change ++ * to autofs-dev-ioctl.c:lookup_ioctl() ++ */ ++enum { ++ /* Get various version info */ ++ AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71, ++ AUTOFS_DEV_IOCTL_PROTOVER_CMD, ++ AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, ++ ++ /* Set mount we're acting on */ ++ AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, ++ ++ /* Close mount ioctl fd */ ++ AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, ++ ++ /* Mount/expire status returns */ ++ AUTOFS_DEV_IOCTL_READY_CMD, ++ AUTOFS_DEV_IOCTL_FAIL_CMD, ++ ++ /* Automount active/inactive */ ++ AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, ++ AUTOFS_DEV_IOCTL_CATATONIC_CMD, ++ ++ /* Expiry timeout */ ++ AUTOFS_DEV_IOCTL_TIMEOUT_CMD, ++ ++ /* Get mount last requesting uid and gid */ ++ AUTOFS_DEV_IOCTL_REQUESTOR_CMD, ++ ++ /* Check for eligible expire candidates */ ++ AUTOFS_DEV_IOCTL_EXPIRE_CMD, ++ ++ /* Request busy status */ ++ AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, ++ ++ /* Check if path is a mountpoint */ ++ AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, ++}; ++ ++#define AUTOFS_IOCTL 0x93 ++ ++#define AUTOFS_DEV_IOCTL_VERSION _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_PROTOVER _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_PROTOSUBVER _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_OPENMOUNT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_CLOSEMOUNT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_READY _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_FAIL _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_SETPIPEFD _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_CATATONIC _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_TIMEOUT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_REQUESTOR _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_REQUESTOR_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_EXPIRE _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_ASKUMOUNT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl) ++#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT _IOWR(AUTOFS_IOCTL, AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl) ++ ++#endif /* _LINUX_AUTO_DEV_IOCTL_H */ +diff -up /dev/null autofs-5.0.3/include/mounts.h +--- /dev/null 2008-02-25 17:16:11.149000952 +0900 ++++ autofs-5.0.3/include/mounts.h 2008-02-25 09:03:44.000000000 +0900 +@@ -0,0 +1,96 @@ ++/* ----------------------------------------------------------------------- * ++ * ++ * mounts.h - header file for mount utilities module. ++ * ++ * Copyright 2008 Red Hat, Inc. All rights reserved. ++ * Copyright 2004-2006 Ian Kent - All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, ++ * USA; either version 2 of the License, or (at your option) any later ++ * version; incorporated herein by reference. ++ * ++ * ----------------------------------------------------------------------- */ ++ ++#ifndef MOUNTS_H ++#define MOUNTS_H ++ ++#define AUTOFS_TYPE_INDIRECT 0x0001 ++#define AUTOFS_TYPE_DIRECT 0x0002 ++#define AUTOFS_TYPE_OFFSET 0x0004 ++ ++#define MNTS_ALL 0x0001 ++#define MNTS_REAL 0x0002 ++#define MNTS_AUTOFS 0x0004 ++ ++#define REMOUNT_SUCCESS 0x0000 ++#define REMOUNT_OPEN_FAIL 0x0001 ++#define REMOUNT_STAT_FAIL 0x0002 ++#define REMOUNT_READ_MAP 0x0004 ++ ++extern const unsigned int indirect; ++extern const unsigned int direct; ++extern const unsigned int offset; ++ ++struct mapent; ++ ++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, const 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, const unsigned int type); ++void set_tsd_user_vars(unsigned int, uid_t, gid_t); ++const char *mount_type_str(unsigned int); ++void notify_mount_result(struct autofs_point *, const char *, const char *); ++int remount_active_mount(struct autofs_point *, struct mapent_cache *, ++ const char *, dev_t devid, const unsigned int, 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 /dev/null autofs-5.0.3/include/dev-ioctl-lib.h +--- /dev/null 2008-02-25 17:16:11.149000952 +0900 ++++ autofs-5.0.3/include/dev-ioctl-lib.h 2008-02-25 09:03:44.000000000 +0900 +@@ -0,0 +1,62 @@ ++/* ----------------------------------------------------------------------- * ++ * ++ * dev-ioctl-lib.h - autofs device control. ++ * ++ * Copyright 2008 Red Hat, Inc. All rights reserved. ++ * Copyright 2008 Ian Kent ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, ++ * USA; either version 2 of the License, or (at your option) any later ++ * version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * ----------------------------------------------------------------------- */ ++ ++#ifndef AUTOFS_DEV_IOCTL_LIB_H ++#define AUTOFS_DEV_IOCTL_LIB_H ++ ++#include ++#include "linux/auto_dev-ioctl.h" ++ ++#define CONTROL_DEVICE "/dev/autofs" ++ ++#define DEV_IOCTL_IS_MOUNTED 0x0001 ++#define DEV_IOCTL_IS_AUTOFS 0x0002 ++#define DEV_IOCTL_IS_OTHER 0x0004 ++ ++struct ioctl_ctl { ++ int devfd; ++ struct ioctl_ops *ops; ++}; ++ ++struct ioctl_ops { ++ int (*version)(unsigned int, int, struct autofs_dev_ioctl *); ++ int (*protover)(unsigned int, int, unsigned int *); ++ int (*protosubver)(unsigned int, int, unsigned int *); ++ int (*open)(unsigned int, int *, dev_t, const char *, unsigned int); ++ int (*close)(unsigned int, int); ++ int (*send_ready)(unsigned int, int, unsigned int); ++ int (*send_fail)(unsigned int, int, unsigned int, int); ++ int (*setpipefd)(unsigned int, int, int); ++ int (*catatonic)(unsigned int, int); ++ int (*timeout)(unsigned int, int, time_t *); ++ int (*requestor)(unsigned int, int, const char *, uid_t *, gid_t *); ++ int (*expire)(unsigned int, int, const char *, unsigned int); ++ int (*askumount)(unsigned int, int, unsigned int *); ++ int (*ismountpoint)(unsigned int, int, const char *, unsigned int *); ++}; ++ ++void init_ioctl_ctl(void); ++void close_ioctl_ctl(void); ++struct ioctl_ops *get_ioctl_ops(void); ++struct autofs_dev_ioctl *alloc_ioctl_ctl_open(const char *, unsigned int); ++void free_ioctl_ctl_open(struct autofs_dev_ioctl *); ++ ++#endif ++ +diff -up autofs-5.0.3/CHANGELOG.device-node-control autofs-5.0.3/CHANGELOG +--- autofs-5.0.3/CHANGELOG.device-node-control 2008-02-25 08:58:46.000000000 +0900 ++++ autofs-5.0.3/CHANGELOG 2008-02-25 09:07:32.000000000 +0900 +@@ -8,6 +8,7 @@ + - another fix for don't fail on empty master map. + - fix expire working harder than needed. + - fix unlink of mount tree incorrectly causing autofs mount fail. ++- add miscellaneous device node interface library. + + 14/01/2008 autofs-5.0.3 + ----------------------- +diff -up autofs-5.0.3/redhat/autofs.init.in.device-node-control autofs-5.0.3/redhat/autofs.init.in +--- autofs-5.0.3/redhat/autofs.init.in.device-node-control 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/redhat/autofs.init.in 2008-02-25 09:03:12.000000000 +0900 +@@ -13,6 +13,7 @@ + DAEMON=@@sbindir@@/automount + prog=`basename $DAEMON` + MODULE="autofs4" ++DEVICE="autofs" + initdir=@@initdir@@ + confdir=@@autofsconfdir@@ + +@@ -56,6 +57,15 @@ function start() { + echo + return $RETVAL + fi ++ ++ # Check misc device ++ if [ -e "/proc/misc" ]; then ++ MINOR=`awk "/$DEVICE/ {print \\$1}" /proc/misc` ++ if [ -n "$MINOR" -a ! -c "/dev/$DEVICE" ]; then ++ mknod -m 0600 /dev/$DEVICE c 10 $MINOR ++ fi ++ fi ++ + echo -n $"Starting $prog: " + $prog $OPTIONS + RETVAL=$? +diff -up autofs-5.0.3/lib/master_parse.y.device-node-control autofs-5.0.3/lib/master_parse.y +--- autofs-5.0.3/lib/master_parse.y.device-node-control 2008-02-25 08:58:46.000000000 +0900 ++++ autofs-5.0.3/lib/master_parse.y 2008-02-25 09:03:12.000000000 +0900 +@@ -796,6 +796,7 @@ int master_parse_entry(const char *buffe + return 0; + } + } else { ++ struct ioctl_ops *ops = get_ioctl_ops(); + struct autofs_point *ap = entry->ap; + time_t tout = timeout; + +@@ -807,7 +808,7 @@ int master_parse_entry(const char *buffe + ap->exp_timeout = timeout; + ap->exp_runfreq = (ap->exp_timeout + CHECK_RATIO - 1) / CHECK_RATIO; + if (ap->ioctlfd != -1 && ap->type == LKP_INDIRECT) +- ioctl(ap->ioctlfd, AUTOFS_IOC_SETTIMEOUT, &tout); ++ ops->timeout(ap->logopt, ap->ioctlfd, &tout); + } + } + entry->ap->random_selection = random_selection; +diff -up autofs-5.0.3/lib/mounts.c.device-node-control autofs-5.0.3/lib/mounts.c +--- autofs-5.0.3/lib/mounts.c.device-node-control 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/lib/mounts.c 2008-02-25 09:03:12.000000000 +0900 +@@ -38,6 +38,7 @@ static const char kver_options_template[ + + unsigned int query_kproto_ver(void) + { ++ struct ioctl_ops *ops = get_ioctl_ops(); + char dir[] = "/tmp/autoXXXXXX", *t_dir; + char options[MAX_OPTIONS_LEN + 1]; + pid_t pgrp = getpgrp(); +@@ -70,7 +71,7 @@ unsigned int query_kproto_ver(void) + + close(pipefd[1]); + +- ioctlfd = open(t_dir, O_RDONLY); ++ ops->open(LOGOPT_NONE, &ioctlfd, -1, t_dir, AUTOFS_TYPE_INDIRECT); + if (ioctlfd == -1) { + umount(t_dir); + close(pipefd[0]); +@@ -78,11 +79,11 @@ unsigned int query_kproto_ver(void) + return 0; + } + +- ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0); ++ ops->catatonic(LOGOPT_NONE, ioctlfd); + + /* If this ioctl() doesn't work, it is kernel version 2 */ +- if (ioctl(ioctlfd, AUTOFS_IOC_PROTOVER, &kver.major) == -1) { +- close(ioctlfd); ++ if (ops->protover(LOGOPT_NONE, ioctlfd, &kver.major)) { ++ ops->close(LOGOPT_NONE, ioctlfd); + umount(t_dir); + close(pipefd[0]); + rmdir(t_dir); +@@ -90,15 +91,15 @@ unsigned int query_kproto_ver(void) + } + + /* If this ioctl() doesn't work, version is 4 or less */ +- if (ioctl(ioctlfd, AUTOFS_IOC_PROTOSUBVER, &kver.minor) == -1) { +- close(ioctlfd); ++ if (ops->protosubver(LOGOPT_NONE, ioctlfd, &kver.minor)) { ++ ops->close(LOGOPT_NONE, ioctlfd); + umount(t_dir); + close(pipefd[0]); + rmdir(t_dir); + return 0; + } + +- close(ioctlfd); ++ ops->close(LOGOPT_NONE, ioctlfd); + umount(t_dir); + close(pipefd[0]); + rmdir(t_dir); +@@ -456,49 +457,75 @@ int has_fstab_option(const char *opt) + return ret; + } + +-char *find_mnt_ino(const char *table, dev_t dev, ino_t ino) ++/* ++ * Find the device number of an autofs mount with given path and ++ * type (eg..AUTOFS_TYPE_DIRECT). An autofs display mount option ++ * "dev=" is provided by the kernel module for this. ++ * ++ * The device number is used by the kernel to identify the autofs ++ * super block when searching for the mount. ++ */ ++int find_mnt_devid(const char *table, ++ const char *path, char *devid, unsigned int type) + { +- struct mntent mnt_wrk; + struct mntent *mnt; ++ struct mntent mnt_wrk; + char buf[PATH_MAX * 3]; +- char *path = NULL; +- unsigned long l_dev = (unsigned long) dev; +- unsigned long l_ino = (unsigned long) ino; + FILE *tab; ++ char *dev; + + tab = setmntent(table, "r"); + if (!tab) { +- char *estr = strerror_r(errno, buf, (size_t) PATH_MAX - 1); +- logerr("setmntent: %s", estr); ++ printf("failed to open mount table\n"); + return 0; + } + ++ dev = NULL; + while ((mnt = getmntent_r(tab, &mnt_wrk, buf, PATH_MAX * 3))) { +- char *p_dev, *p_ino; +- unsigned long m_dev, m_ino; +- + if (strcmp(mnt->mnt_type, "autofs")) + continue; + +- p_dev = strstr(mnt->mnt_opts, "dev="); +- if (!p_dev) +- continue; +- sscanf(p_dev, "dev=%lu", &m_dev); +- if (m_dev != l_dev) ++ if (strcmp(mnt->mnt_dir, path)) + continue; + +- p_ino = strstr(mnt->mnt_opts, "ino="); +- if (!p_ino) +- continue; +- sscanf(p_ino, "ino=%lu", &m_ino); +- if (m_ino == l_ino) { +- path = strdup(mnt->mnt_dir); ++ switch (type) { ++ case AUTOFS_TYPE_INDIRECT: ++ if (!hasmntopt(mnt, "indirect")) ++ continue; ++ break; ++ ++ case AUTOFS_TYPE_DIRECT: ++ if (!hasmntopt(mnt, "direct")) ++ continue; ++ break; ++ ++ case AUTOFS_TYPE_OFFSET: ++ if (!hasmntopt(mnt, "offset")) ++ continue; ++ break; ++ } ++ ++ dev = hasmntopt(mnt, "dev"); ++ if (dev) { ++ char *start = strchr(dev, '=') + 1; ++ char *end = strchr(start, ','); ++ if (end) ++ *end = '\0'; ++ if (start) { ++ int len = strlen(start); ++ memcpy(devid, start, len); ++ devid[len] = '\0'; ++ } + break; + } + } ++ + endmntent(tab); + +- return path; ++ if (!dev) ++ return 0; ++ ++ return 1; + } + + char *get_offset(const char *prefix, char *offset, +@@ -976,3 +1003,70 @@ int tree_is_mounted(struct mnt_list *mnt + return mounted; + } + ++int tree_find_mnt_devid(struct mnt_list *mnts, ++ const char *path, char *devid, unsigned int type) ++{ ++ struct list_head *p; ++ struct list_head list; ++ size_t len = strlen(path); ++ char *dev; ++ ++ INIT_LIST_HEAD(&list); ++ ++ if (!tree_find_mnt_ents(mnts, &list, path)) ++ return 0; ++ ++ dev = NULL; ++ list_for_each(p, &list) { ++ struct mnt_list *mptr; ++ ++ mptr = list_entry(p, struct mnt_list, entries); ++ ++ if (strcmp(mptr->fs_type, "autofs")) ++ continue; ++ ++ if (strlen(mptr->path) < len) ++ return 0; ++ ++ if (strcmp(mptr->path, path)) ++ continue; ++ ++ switch (type) { ++ case AUTOFS_TYPE_INDIRECT: ++ if (!strstr(mptr->opts, "indirect")) ++ continue; ++ break; ++ ++ case AUTOFS_TYPE_DIRECT: ++ if (!strstr(mptr->opts, "direct")) ++ continue; ++ break; ++ ++ case AUTOFS_TYPE_OFFSET: ++ if (!strstr(mptr->opts, "offset")) ++ continue; ++ break; ++ } ++ ++ dev = strstr(mptr->opts, "dev"); ++ if (dev) { ++ char *start = strchr(dev, '=') + 1; ++ char *end = strchr(start, ','); ++ if (end) ++ *end = '\0'; ++ if (start) { ++ int len = strlen(start); ++ memcpy(devid, start, len); ++ devid[len] = '\0'; ++ } ++ *end = ','; ++ break; ++ } ++ } ++ ++ if (!dev) ++ return 0; ++ ++ return 1; ++} ++ +diff -up autofs-5.0.3/lib/Makefile.device-node-control autofs-5.0.3/lib/Makefile +--- autofs-5.0.3/lib/Makefile.device-node-control 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/lib/Makefile 2008-02-25 09:03:12.000000000 +0900 +@@ -7,12 +7,13 @@ include ../Makefile.rules + + SRCS = cache.c cat_path.c rpc_subs.c mounts.c log.c nsswitch.c \ + master_tok.l master_parse.y nss_tok.c nss_parse.tab.c \ +- args.c alarm.c macros.c master.c defaults.c parse_subs.c ++ args.c alarm.c macros.c master.c defaults.c parse_subs.c \ ++ dev-ioctl-lib.c + RPCS = mount.h mount_clnt.c mount_xdr.c + OBJS = cache.o mount_clnt.o mount_xdr.o cat_path.o rpc_subs.o \ + mounts.o log.o nsswitch.o master_tok.o master_parse.tab.o \ + nss_tok.o nss_parse.tab.o args.o alarm.o macros.o master.o \ +- defaults.o parse_subs.o ++ defaults.o parse_subs.o dev-ioctl-lib.o + + YACCSRC = nss_tok.c nss_parse.tab.c nss_parse.tab.h \ + master_tok.c master_parse.tab.c master_parse.tab.h +diff -up /dev/null autofs-5.0.3/lib/dev-ioctl-lib.c +--- /dev/null 2008-02-25 17:16:11.149000952 +0900 ++++ autofs-5.0.3/lib/dev-ioctl-lib.c 2008-02-25 09:03:44.000000000 +0900 +@@ -0,0 +1,747 @@ ++/* ----------------------------------------------------------------------- * ++ * ++ * ctl-dev-lib.c - module for Linux automount mount table lookup functions ++ * ++ * Copyright 2008 Red Hat, Inc. All rights reserved. ++ * Copyright 2008 Ian Kent - All Rights Reserved ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, ++ * USA; either version 2 of the License, or (at your option) any later ++ * version; incorporated herein by reference. ++ * ++ * ----------------------------------------------------------------------- */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "automount.h" ++ ++/* ioctld control function interface */ ++static struct ioctl_ctl ctl = { -1, NULL }; ++ ++#ifndef AUTOFS_SUPER_MAGIC ++#define AUTOFS_SUPER_MAGIC 0x0187 ++#endif ++ ++/* ++ * Define functions for autofs ioctl control. ++ * ++ * We provide two interfaces. One which routes ioctls via a ++ * miscelaneous device node and can be used to obtain an ioctl ++ * file descriptor for autofs mounts that are covered by an ++ * active mount (eg. active direct or multi-mount offsets). ++ * The other provides the traditional autofs ioctl implementation. ++ * ++ * The miscielaneous device control functions are prefixed with ++ * dev_ctl_ and the traditional ones are prefixed with ioctl_. ++ */ ++static int dev_ioctl_version(unsigned int, int, struct autofs_dev_ioctl *); ++static int dev_ioctl_protover(unsigned int, int, unsigned int *); ++static int dev_ioctl_protosubver(unsigned int, int, unsigned int *); ++static int dev_ioctl_open(unsigned int, int *, dev_t, const char *, unsigned int); ++static int dev_ioctl_close(unsigned int, int); ++static int dev_ioctl_send_ready(unsigned int, int, unsigned int); ++static int dev_ioctl_send_fail(unsigned int, int, unsigned int, int); ++static int dev_ioctl_setpipefd(unsigned int, int, int); ++static int dev_ioctl_catatonic(unsigned int, int); ++static int dev_ioctl_timeout(unsigned int, int, time_t *); ++static int dev_ioctl_requestor(unsigned int, int, const char *, uid_t *, gid_t *); ++static int dev_ioctl_expire(unsigned int, int, const char *, unsigned int); ++static int dev_ioctl_askumount(unsigned int, int, unsigned int *); ++static int dev_ioctl_ismountpoint(unsigned int, int, const char *, unsigned int *); ++ ++static int ioctl_protover(unsigned int, int, unsigned int *); ++static int ioctl_protosubver(unsigned int, int, unsigned int *); ++static int ioctl_open(unsigned int, int *, dev_t, const char *, unsigned int); ++static int ioctl_close(unsigned int, int); ++static int ioctl_send_ready(unsigned int, int, unsigned int); ++static int ioctl_send_fail(unsigned int, int, unsigned int, int); ++static int ioctl_catatonic(unsigned int, int); ++static int ioctl_timeout(unsigned int, int, time_t *); ++static int ioctl_expire(unsigned int, int, const char *, unsigned int); ++static int ioctl_askumount(unsigned int, int, unsigned int *); ++ ++static struct ioctl_ops dev_ioctl_ops = { ++ .version = dev_ioctl_version, ++ .protover = dev_ioctl_protover, ++ .protosubver = dev_ioctl_protosubver, ++ .open = dev_ioctl_open, ++ .close = dev_ioctl_close, ++ .send_ready = dev_ioctl_send_ready, ++ .send_fail = dev_ioctl_send_fail, ++ .setpipefd = dev_ioctl_setpipefd, ++ .catatonic = dev_ioctl_catatonic, ++ .timeout = dev_ioctl_timeout, ++ .requestor = dev_ioctl_requestor, ++ .expire = dev_ioctl_expire, ++ .askumount = dev_ioctl_askumount, ++ .ismountpoint = dev_ioctl_ismountpoint ++}; ++ ++static struct ioctl_ops ioctl_ops = { ++ .version = NULL, ++ .protover = ioctl_protover, ++ .protosubver = ioctl_protosubver, ++ .open = ioctl_open, ++ .close = ioctl_close, ++ .send_ready = ioctl_send_ready, ++ .send_fail = ioctl_send_fail, ++ .setpipefd = NULL, ++ .catatonic = ioctl_catatonic, ++ .timeout = ioctl_timeout, ++ .requestor = NULL, ++ .expire = ioctl_expire, ++ .askumount = ioctl_askumount, ++ .ismountpoint = NULL ++}; ++ ++/* ++ * Allocate the control struct that holds the misc device file ++ * descriptor and operation despatcher table. ++ */ ++void init_ioctl_ctl(void) ++{ ++ int devfd; ++ ++ if (ctl.ops) ++ return; ++ ++ devfd = open(CONTROL_DEVICE, O_RDONLY); ++ if (devfd == -1) ++ ctl.ops = &ioctl_ops; ++ else { ++ int cl_flags = fcntl(devfd, F_GETFD, 0); ++ if (cl_flags != -1) { ++ cl_flags |= FD_CLOEXEC; ++ fcntl(devfd, F_SETFD, cl_flags); ++ } ++ ctl.devfd = devfd; ++ ctl.ops = &dev_ioctl_ops; ++ } ++ return; ++} ++ ++void close_ioctl_ctl(void) ++{ ++ if (ctl.devfd != -1) { ++ close(ctl.devfd); ++ ctl.devfd = -1; ++ } ++ ctl.ops = NULL; ++ return; ++} ++ ++/* Return a pointer to the operations control struct */ ++struct ioctl_ops *get_ioctl_ops(void) ++{ ++ if (!ctl.ops) ++ init_ioctl_ctl(); ++ return ctl.ops; ++} ++ ++/* Get kenrel version of misc device code */ ++static int dev_ioctl_version(unsigned int logopt, ++ int ioctlfd, struct autofs_dev_ioctl *param) ++{ ++ param->ioctlfd = ioctlfd; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_VERSION, param) == -1) ++ return -1; ++ ++ return 0; ++} ++ ++/* Get major version of autofs kernel module mount protocol */ ++static int dev_ioctl_protover(unsigned int logopt, ++ int ioctlfd, unsigned int *major) ++{ ++ struct autofs_dev_ioctl param; ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_PROTOVER, ¶m) == -1) ++ return -1; ++ ++ *major = param.arg1; ++ ++ return 0; ++} ++ ++static int ioctl_protover(unsigned int logopt, ++ int ioctlfd, unsigned int *major) ++{ ++ return ioctl(ioctlfd, AUTOFS_IOC_PROTOVER, major); ++} ++ ++/* Get minor version of autofs kernel module mount protocol */ ++static int dev_ioctl_protosubver(unsigned int logopt, ++ int ioctlfd, unsigned int *minor) ++{ ++ struct autofs_dev_ioctl param; ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_PROTOSUBVER, ¶m) == -1) ++ return -1; ++ ++ *minor = param.arg1; ++ ++ return 0; ++} ++ ++static int ioctl_protosubver(unsigned int logopt, ++ int ioctlfd, unsigned int *minor) ++{ ++ return ioctl(ioctlfd, AUTOFS_IOC_PROTOSUBVER, minor); ++} ++ ++/* ++ * Allocate a parameter struct for misc device ioctl used when ++ * opening an autofs mount point. Attach the path to the end ++ * of the struct. and lookup the device number if not given. ++ * Locating the device number relies on the mount option ++ * "dev=" being present in the autofs fs mount ++ * options. ++ */ ++static struct autofs_dev_ioctl *alloc_dev_ioctl_open(const char *path, dev_t devid, unsigned int type) ++{ ++ struct autofs_dev_ioctl *ioctl; ++ size_t size, p_len; ++ dev_t devno = devid; ++ ++ if (!path) ++ return NULL; ++ ++ if (devno == -1) { ++ char device[AUTOFS_DEVID_LEN]; ++ ++ if (!find_mnt_devid(_PROC_MOUNTS, path, device, type)) { ++ errno = ENOENT; ++ return NULL; ++ } ++ devno = strtoul(device, NULL, 0); ++ } ++ ++ p_len = strlen(path); ++ size = sizeof(struct autofs_dev_ioctl) + p_len + 1; ++ ioctl = malloc(size); ++ if (!ioctl) { ++ errno = ENOMEM; ++ return NULL; ++ } ++ ++ init_autofs_dev_ioctl(ioctl); ++ ioctl->size = size; ++ memcpy(ioctl->path, path, p_len); ++ ioctl->path[p_len] = '\0'; ++ ioctl->arg1 = devno; ++ ++ return ioctl; ++} ++ ++static void free_dev_ioctl_open(struct autofs_dev_ioctl *ioctl) ++{ ++ free(ioctl); ++ return; ++} ++ ++/* ++ * Allocate a parameter struct for misc device ioctl which includes ++ * a path. This is used when getting the last mount requestor uid ++ * and gid and when checking if a path within the autofs filesystem ++ * is a mount point. We add the path to the end of the struct. ++ */ ++static struct autofs_dev_ioctl *alloc_dev_ioctl_path(int ioctlfd, const char *path) ++{ ++ struct autofs_dev_ioctl *ioctl; ++ size_t size, p_len; ++ ++ if (!path) ++ return NULL; ++ ++ p_len = strlen(path); ++ size = sizeof(struct autofs_dev_ioctl) + p_len + 1; ++ ioctl = malloc(size); ++ if (!ioctl) { ++ errno = ENOMEM; ++ return NULL; ++ } ++ ++ init_autofs_dev_ioctl(ioctl); ++ ioctl->ioctlfd = ioctlfd; ++ ioctl->size = size; ++ memcpy(ioctl->path, path, p_len); ++ ioctl->path[p_len] = '\0'; ++ ++ return ioctl; ++} ++ ++static void free_dev_ioctl_path(struct autofs_dev_ioctl *ioctl) ++{ ++ free(ioctl); ++ return; ++} ++ ++/* Get a file descriptor for control operations */ ++static int dev_ioctl_open(unsigned int logopt, int *ioctlfd, ++ dev_t devid, const char *path, unsigned int type) ++{ ++ struct autofs_dev_ioctl *param; ++ ++ *ioctlfd = -1; ++ ++ param = alloc_dev_ioctl_open(path, devid, type); ++ if (!param) ++ return -1; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) == -1) { ++ int save_errno = errno; ++ free_dev_ioctl_open(param); ++ errno = save_errno; ++ return -1; ++ } ++ ++ *ioctlfd = param->ioctlfd; ++ ++ free_dev_ioctl_open(param); ++ ++ return 0; ++} ++ ++static int ioctl_open(unsigned int logopt, int *ioctlfd, ++ dev_t devid, const char *path, unsigned int type) ++{ ++ struct statfs sfs; ++ int save_errno, fd, cl_flags; ++ ++ *ioctlfd = -1; ++ ++ fd = open(path, O_RDONLY); ++ if (fd == -1) ++ return -1; ++ ++ cl_flags = fcntl(fd, F_GETFD, 0); ++ if (cl_flags != -1) { ++ cl_flags |= FD_CLOEXEC; ++ fcntl(fd, F_SETFD, cl_flags); ++ } ++ ++ if (fstatfs(fd, &sfs) == -1) { ++ save_errno = errno; ++ goto err; ++ } ++ ++ if (sfs.f_type != AUTOFS_SUPER_MAGIC) { ++ save_errno = ENOENT; ++ goto err; ++ } ++ ++ *ioctlfd = fd; ++ ++ return 0; ++err: ++ close(fd); ++ errno = save_errno; ++ return -1; ++} ++ ++/* Close */ ++static int dev_ioctl_close(unsigned int logopt, int ioctlfd) ++{ ++ struct autofs_dev_ioctl param; ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_CLOSEMOUNT, ¶m) == -1) ++ return -1; ++ ++ return 0; ++} ++ ++static int ioctl_close(unsigned int logopt, int ioctlfd) ++{ ++ return close(ioctlfd); ++} ++ ++/* Send ready status for given token */ ++static int dev_ioctl_send_ready(unsigned int logopt, ++ int ioctlfd, unsigned int token) ++{ ++ struct autofs_dev_ioctl param; ++ ++ if (token == 0) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ debug(logopt, "token = %d", token); ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ param.arg1 = token; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_READY, ¶m) == -1) { ++ char *estr, buf[MAX_ERR_BUF]; ++ int save_errno = errno; ++ estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ logerr("AUTOFS_DEV_IOCTL_READY: error %s", estr); ++ errno = save_errno; ++ return -1; ++ } ++ return 0; ++} ++ ++static int ioctl_send_ready(unsigned int logopt, ++ int ioctlfd, unsigned int token) ++{ ++ if (token == 0) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ debug(logopt, "token = %d", token); ++ ++ if (ioctl(ioctlfd, AUTOFS_IOC_READY, token) == -1) { ++ char *estr, buf[MAX_ERR_BUF]; ++ int save_errno = errno; ++ estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ logerr("AUTOFS_IOC_READY: error %s", estr); ++ errno = save_errno; ++ return -1; ++ } ++ return 0; ++} ++ ++/* ++ * Send ready status for given token. ++ * ++ * The device node ioctl implementation allows for sending a status ++ * of other than ENOENT, unlike the tradional interface. ++ */ ++static int dev_ioctl_send_fail(unsigned int logopt, ++ int ioctlfd, unsigned int token, int status) ++{ ++ struct autofs_dev_ioctl param; ++ ++ if (token == 0) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ debug(logopt, "token = %d", token); ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ param.arg1 = token; ++ param.arg2 = status; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_FAIL, ¶m) == -1) { ++ char *estr, buf[MAX_ERR_BUF]; ++ int save_errno = errno; ++ estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ logerr("AUTOFS_DEV_IOCTL_FAIL: error %s", estr); ++ errno = save_errno; ++ return -1; ++ } ++ return 0; ++} ++ ++static int ioctl_send_fail(unsigned int logopt, ++ int ioctlfd, unsigned int token, int status) ++{ ++ if (token == 0) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ debug(logopt, "token = %d", token); ++ ++ if (ioctl(ioctlfd, AUTOFS_IOC_FAIL, token) == -1) { ++ char *estr, buf[MAX_ERR_BUF]; ++ int save_errno = errno; ++ estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ logerr("AUTOFS_IOC_FAIL: error %s", estr); ++ errno = save_errno; ++ return -1; ++ } ++ return 0; ++} ++ ++/* ++ * Set the pipe fd for kernel communication. ++ * ++ * Normally this is set at mount using an option but if we ++ * are reconnecting to a busy mount then we need to use this ++ * to tell the autofs kernel module about the new pipe fd. In ++ * order to protect mounts against incorrectly setting the ++ * pipefd we also require that the autofs mount be catatonic. ++ * ++ * If successful this also sets the process group id used to ++ * identify the controlling process to the process group of ++ * the caller. ++ */ ++static int dev_ioctl_setpipefd(unsigned int logopt, int ioctlfd, int pipefd) ++{ ++ struct autofs_dev_ioctl param; ++ ++ if (pipefd == -1) { ++ errno = EBADF; ++ return -1; ++ } ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ param.arg1 = pipefd; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_SETPIPEFD, ¶m) == -1) ++ return -1; ++ ++ return 0; ++} ++ ++/* ++ * Make the autofs mount point catatonic, no longer responsive to ++ * mount requests. Also closes the kernel pipe file descriptor. ++ */ ++static int dev_ioctl_catatonic(unsigned int logopt, int ioctlfd) ++{ ++ struct autofs_dev_ioctl param; ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_CATATONIC, ¶m) == -1) ++ return -1; ++ ++ return 0; ++} ++ ++static int ioctl_catatonic(unsigned int logopt, int ioctlfd) ++{ ++ return ioctl(ioctlfd, AUTOFS_IOC_CATATONIC, 0); ++} ++ ++/* Set the autofs mount timeout */ ++static int dev_ioctl_timeout(unsigned int logopt, int ioctlfd, time_t *timeout) ++{ ++ struct autofs_dev_ioctl param; ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ param.arg1 = *timeout; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_TIMEOUT, ¶m) == -1) ++ return -1; ++ ++ *timeout = param.arg1; ++ ++ return 0; ++} ++ ++static int ioctl_timeout(unsigned int logopt, int ioctlfd, time_t *timeout) ++{ ++ return ioctl(ioctlfd, AUTOFS_IOC_SETTIMEOUT, timeout); ++} ++ ++/* ++ * Get the uid and gid of the last request for the mountpoint, path. ++ * ++ * When reconstructing an autofs mount tree with active mounts ++ * we need to re-connect to mounts that may have used the original ++ * process uid and gid (or string variations of them) for mount ++ * lookups within the map entry. ++ */ ++static int dev_ioctl_requestor(unsigned int logopt, ++ int ioctlfd, const char *path, ++ uid_t *uid, gid_t *gid) ++{ ++ struct autofs_dev_ioctl *param; ++ int err; ++ ++ if (!path) ++ errno = EINVAL; ++ ++ *uid = -1; ++ *gid = -1; ++ ++ ++ param = alloc_dev_ioctl_path(ioctlfd, path); ++ if (!param) ++ return -1; ++ ++ err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_REQUESTOR, param); ++ if (err == -1) { ++ int save_errno = errno; ++ free_dev_ioctl_open(param); ++ errno = save_errno; ++ return -1; ++ } ++ ++ *uid = param->arg1; ++ *gid = param->arg2; ++ ++ free_dev_ioctl_path(param); ++ ++ return 0; ++} ++ ++/* ++ * Call repeatedly until it returns EAGAIN, meaning there's nothing ++ * more that can be done. ++ */ ++static int expire(unsigned int logopt, int cmd, int fd, ++ int ioctlfd, const char *path, void *arg) ++{ ++ char buf[MAX_ERR_BUF]; ++ struct stat st; ++ unsigned int retries; ++ unsigned int ret; ++ ++ if (fstat(ioctlfd, &st) == -1) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ debug(logopt, "fstat failed: %s", estr); ++ return 0; ++ } ++ ++ retries = (count_mounts(logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES; ++ ++ while (retries--) { ++ struct timespec tm = {0, 100000000}; ++ ++ ret = ioctl(fd, cmd, arg); ++ if (ret == -1) { ++ /* Mount has gone away */ ++ if (errno == EBADF || errno == EINVAL) ++ return 0; ++ ++ /* ++ * Other than EAGAIN is an expire error so continue. ++ * Kernel will try the next mount for indirect ++ * mounts. For direct mounts it will just try the ++ * same mount again, limited by retries (ie. number ++ * of mounts directly under mount point, should ++ * always be one for direct mounts). ++ */ ++ if (errno == EAGAIN) ++ break; ++ } ++ nanosleep(&tm, NULL); ++ } ++ ++ if (ctl.ops->askumount(logopt, ioctlfd, &ret)) ++ return -1; ++ ++ if (!ret) ++ return -1; ++ ++ return 0; ++} ++ ++static int dev_ioctl_expire(unsigned int logopt, ++ int ioctlfd, const char *path, unsigned int when) ++{ ++ struct autofs_dev_ioctl param; ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ param.arg1 = when; ++ ++ return expire(logopt, AUTOFS_DEV_IOCTL_EXPIRE, ++ ctl.devfd, ioctlfd, path, (void *) ¶m); ++} ++ ++static int ioctl_expire(unsigned int logopt, ++ int ioctlfd, const char *path, unsigned int when) ++{ ++ return expire(logopt, AUTOFS_IOC_EXPIRE_MULTI, ++ ioctlfd, ioctlfd, path, (void *) &when); ++} ++ ++/* Check if autofs mount point is in use */ ++static int dev_ioctl_askumount(unsigned int logopt, ++ int ioctlfd, unsigned int *busy) ++{ ++ struct autofs_dev_ioctl param; ++ ++ init_autofs_dev_ioctl(¶m); ++ param.ioctlfd = ioctlfd; ++ ++ if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ASKUMOUNT, ¶m) == -1) ++ return -1; ++ ++ *busy = param.arg1; ++ ++ return 0; ++} ++ ++static int ioctl_askumount(unsigned int logopt, ++ int ioctlfd, unsigned int *busy) ++{ ++ return ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, busy); ++} ++ ++/* ++ * Check if the given path is a mountpoint. ++ * ++ * The path is considered a mountpoint if it is itself a mountpoint ++ * or contains a mount, such as a multi-mount without a root mount. ++ * In addition, if the path is itself a mountpoint we return whether ++ * the mounted file system is an autofs filesystem or other file ++ * system. ++ */ ++static int dev_ioctl_ismountpoint(unsigned int logopt, ++ int ioctlfd, const char *path, ++ unsigned int *mountpoint) ++{ ++ struct autofs_dev_ioctl *param; ++ int err; ++ ++ *mountpoint = 0; ++ ++ if (!path) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ param = alloc_dev_ioctl_path(ioctlfd, path); ++ if (!param) ++ return -1; ++ ++ err = ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_ISMOUNTPOINT, param); ++ if (err == -1) { ++ int save_errno = errno; ++ free_dev_ioctl_open(param); ++ errno = save_errno; ++ return -1; ++ } ++ ++ if (param->arg1) { ++ *mountpoint = DEV_IOCTL_IS_MOUNTED; ++ ++ if (param->arg2) { ++ if (param->arg2 == AUTOFS_SUPER_MAGIC) ++ *mountpoint |= DEV_IOCTL_IS_AUTOFS; ++ else ++ *mountpoint |= DEV_IOCTL_IS_OTHER; ++ } ++ } ++ ++ free_dev_ioctl_path(param); ++ ++ return 0; ++} +diff -up autofs-5.0.3/samples/rc.autofs.in.device-node-control autofs-5.0.3/samples/rc.autofs.in +--- autofs-5.0.3/samples/rc.autofs.in.device-node-control 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/samples/rc.autofs.in 2008-02-25 09:03:12.000000000 +0900 +@@ -12,6 +12,7 @@ + DAEMON=@@sbindir@@/automount + prog=`basename $DAEMON` + MODULE="autofs4" ++DEVICE="autofs" + confdir=@@autofsconfdir@@ + + test -e $DAEMON || exit 0 +@@ -47,6 +48,14 @@ function start() { + return 1 + fi + ++ # Check misc device ++ if [ -e "/proc/misc" ]; then ++ MINOR=`awk "/$DEVICE/ {print \\$1}" /proc/misc` ++ if [ -n "$MINOR" -a ! -c "/dev/$DEVICE" ]; then ++ mknod -m 0600 /dev/$DEVICE c 10 $MINOR ++ fi ++ fi ++ + $prog $OPTIONS + RETVAL=$? + if [ $RETVAL -eq 0 ] ; then diff --git a/autofs-5.0.3-expire-works-too-hard.patch b/autofs-5.0.3-expire-works-too-hard.patch new file mode 100644 index 0000000..cd9fb43 --- /dev/null +++ b/autofs-5.0.3-expire-works-too-hard.patch @@ -0,0 +1,74 @@ +diff -up autofs-5.0.3/daemon/direct.c.expire-works-too-hard autofs-5.0.3/daemon/direct.c +--- autofs-5.0.3/daemon/direct.c.expire-works-too-hard 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/daemon/direct.c 2008-02-25 08:48:08.000000000 +0900 +@@ -808,7 +808,7 @@ static int expire_direct(int ioctlfd, co + + if (fstat(ioctlfd, &st) == -1) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- error(logopt, "fstat failed: %s", estr); ++ debug(logopt, "fstat failed: %s", estr); + return 0; + } + +@@ -824,11 +824,16 @@ static int expire_direct(int ioctlfd, co + if (errno == EBADF || errno == EINVAL) + return 1; + +- /* Other than need to wait for the kernel ? */ +- if (errno != EAGAIN) +- return 0; ++ /* ++ * Other than EAGAIN is an expire error so continue. ++ * Kernel try the same mount again, limited by ++ * retries (ie. number of mounts directly under ++ * mount point, should always be one for direct ++ * mounts). ++ */ ++ if (errno == EAGAIN) ++ break; + } +- + nanosleep(&tm, NULL); + } + +diff -up autofs-5.0.3/daemon/indirect.c.expire-works-too-hard autofs-5.0.3/daemon/indirect.c +--- autofs-5.0.3/daemon/indirect.c.expire-works-too-hard 2008-01-14 13:39:16.000000000 +0900 ++++ autofs-5.0.3/daemon/indirect.c 2008-02-25 08:48:53.000000000 +0900 +@@ -328,7 +328,7 @@ static int expire_indirect(struct autofs + + if (fstat(ioctlfd, &st) == -1) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- error(ap->logopt, "fstat failed: %s", estr); ++ debug(ap->logopt, "fstat failed: %s", estr); + return 0; + } + +@@ -344,11 +344,13 @@ static int expire_indirect(struct autofs + if (errno == EBADF || errno == EINVAL) + return 1; + +- /* Other than need to wait for the kernel ? */ +- if (errno != EAGAIN) +- return 0; ++ /* ++ * Other than EAGAIN is an expire error so continue. ++ * Kernel will try the next mount. ++ */ ++ if (errno == EAGAIN) ++ break; + } +- + nanosleep(&tm, NULL); + } + +diff -up autofs-5.0.3/CHANGELOG.expire-works-too-hard autofs-5.0.3/CHANGELOG +--- autofs-5.0.3/CHANGELOG.expire-works-too-hard 2008-02-25 08:44:54.000000000 +0900 ++++ autofs-5.0.3/CHANGELOG 2008-02-25 08:48:08.000000000 +0900 +@@ -6,6 +6,7 @@ + - avoid using UDP for probing NFSv4 mount requests. + - use libldap instead of libldap_r (Guillaume Rousse). + - another fix for don't fail on empty master map. ++- fix expire working harder than needed. + + 14/01/2008 autofs-5.0.3 + ----------------------- diff --git a/autofs-5.0.3-make-is_mounted-use-dev-ioctl.patch b/autofs-5.0.3-make-is_mounted-use-dev-ioctl.patch new file mode 100644 index 0000000..febde8b --- /dev/null +++ b/autofs-5.0.3-make-is_mounted-use-dev-ioctl.patch @@ -0,0 +1,49 @@ +diff --git a/lib/mounts.c b/lib/mounts.c +index ba49099..e3e8066 100644 +--- a/lib/mounts.c ++++ b/lib/mounts.c +@@ -391,7 +391,7 @@ int contained_in_local_fs(const char *path) + return ret; + } + +-int is_mounted(const char *table, const char *path, unsigned int type) ++static int table_is_mounted(const char *table, const char *path, unsigned int type) + { + struct mntent *mnt; + struct mntent mnt_wrk; +@@ -437,6 +437,35 @@ int is_mounted(const char *table, const char *path, unsigned int type) + return ret; + } + ++static int ioctl_is_mounted(const char *path, unsigned int type) ++{ ++ struct ioctl_ops *ops = get_ioctl_ops(); ++ unsigned int mounted; ++ ++ ops->ismountpoint(LOGOPT_NONE, -1, path, &mounted); ++ if (mounted) { ++ switch (type) { ++ case MNTS_ALL: ++ return 1; ++ case MNTS_AUTOFS: ++ return (mounted & DEV_IOCTL_IS_AUTOFS); ++ case MNTS_REAL: ++ return (mounted & DEV_IOCTL_IS_OTHER); ++ } ++ } ++ return 0; ++} ++ ++int is_mounted(const char *table, const char *path, unsigned int type) ++{ ++ struct ioctl_ops *ops = get_ioctl_ops(); ++ ++ if (ops->version) ++ return ioctl_is_mounted(path, type); ++ else ++ return table_is_mounted(table, path, type); ++} ++ + int has_fstab_option(const char *opt) + { + struct mntent *mnt; diff --git a/autofs-5.0.3-unlink-mount-return-fix.patch b/autofs-5.0.3-unlink-mount-return-fix.patch new file mode 100644 index 0000000..ea833f1 --- /dev/null +++ b/autofs-5.0.3-unlink-mount-return-fix.patch @@ -0,0 +1,52 @@ +diff --git a/CHANGELOG b/CHANGELOG +index eb4cce1..a0c7fa3 100644 +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -7,6 +7,7 @@ + - use libldap instead of libldap_r (Guillaume Rousse). + - another fix for don't fail on empty master map. + - fix expire working harder than needed. ++- fix unlink of mount tree incorrectly causing autofs mount fail. + + 14/01/2008 autofs-5.0.3 + ----------------------- +diff --git a/daemon/direct.c b/daemon/direct.c +index 760fbd4..8d1e9c6 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -275,7 +275,6 @@ static int unlink_mount_tree(struct autofs_point *ap, struct list_head *list) + else + rv = umount2(mnt->path, MNT_DETACH); + if (rv == -1) { +- ret = 0; + debug(ap->logopt, + "can't unlink %s from mount tree", mnt->path); + +@@ -287,6 +286,7 @@ static int unlink_mount_tree(struct autofs_point *ap, struct list_head *list) + + case ENOENT: + case EFAULT: ++ ret = 0; + warn(ap->logopt, "bad path for mount"); + break; + } +diff --git a/daemon/indirect.c b/daemon/indirect.c +index 39b42da..f0409ac 100644 +--- a/daemon/indirect.c ++++ b/daemon/indirect.c +@@ -65,7 +65,6 @@ static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts) + else + rv = umount2(this->path, MNT_DETACH); + if (rv == -1) { +- ret = 0; + debug(ap->logopt, + "can't unlink %s from mount tree", this->path); + +@@ -77,6 +76,7 @@ static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts) + + case ENOENT: + case EFAULT: ++ ret = 0; + warn(ap->logopt, "bad path for mount"); + break; + } diff --git a/autofs.spec b/autofs.spec index 6d9551a..9254e52 100644 --- a/autofs.spec +++ b/autofs.spec @@ -4,7 +4,7 @@ Summary: A tool for automatically mounting and unmounting filesystems Name: autofs Version: 5.0.3 -Release: 5 +Release: 6 Epoch: 1 License: GPL Group: System Environment/Daemons @@ -16,6 +16,12 @@ Patch3: autofs-5.0.3-basedn-with-spaces-fix-3.patch Patch4: autofs-5.0.3-nfs4-tcp-only.patch Patch5: autofs-5.0.3-correct-ldap-lib.patch Patch6: autofs-5.0.3-dont-fail-on-empty-master-fix-2.patch +Patch7: autofs-5.0.3-expire-works-too-hard.patch +Patch8: autofs-5.0.3-unlink-mount-return-fix.patch +Patch9: autofs-5.0.3-device-node-control.patch +Patch10: autofs-5.0.3-active-restart.patch +Patch11: autofs-5.0.3-device-node-and-active-restart-fixes.patch +Patch12: autofs-5.0.3-make-is_mounted-use-dev-ioctl.patch Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: autoconf, hesiod-devel, openldap-devel, bison, flex, libxml2-devel, cyrus-sasl-devel, openssl-devel module-init-tools util-linux nfs-utils e2fsprogs Conflicts: kernel < 2.6.17 @@ -63,6 +69,12 @@ echo %{version}-%{release} > .version %patch4 -p1 %patch5 -p1 %patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 %build #CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir} @@ -115,6 +127,14 @@ fi %{_libdir}/autofs/ %changelog +* Mon Feb 25 2008 Ian Kent - 5.0.3-6 +- fix expire calling kernel more often 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. +- device node and active restart fixes. +- update is_mounted to use device node ioctl, if available. + * Fri Feb 1 2008 Ian Kent - 5.0.3-5 - another fix for don't fail on empty master map.