From 958d4170beec4319476ed3eb0d46902ba2fa0063 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Nov 10 2008 05:30:26 +0000 Subject: - sync. with F-9 bug fixes. - fix lexer ambiguity in match when map type name is included in map name. - check for nohide mounts. - ignore nsswitch sources that aren't supported. - don't abuse the ap->ghost field on NFS mount. - multi-map doesn't pickup NIS updates automatically. - eliminate redundant DNS name lookups. - mount thread create condition handling fix. - allow directory create on NFS root. - check direct mount path length. - fix incorrect in check in get user info. - fix a couple of memory leaks. - don't close file handle for rootless direct mounti-mount at mount. - wait submount expire thread completion when expire successful. - add inadvertantly ommitted server list locking in LDAP module. - add map-type-in-map-name fix patch to sync with upstream and RHEL. - don't readmap on HUP for new mount. - add NIS_PARTIAL to map entry not found check and fix use after free bug. - fix fd leak at multi-mount non-fatal mount fail. - fix incorrect multi-mount mountpoint calcualtion. - add upstream bug fixes - bug fix for mtab check. - bug fix for zero length nis key. - update for ifc buffer handling. - bug fix for kernel automount handling. - add command line option to override is running check. - don't use proc fs for is running check. - fix fail on included browse map not found. - fix incorrect multi source messages. - clear stale flag on map read. - fix proximity other rpc ping timeout. - refactor mount request vars code. - make handle_mounts startup condition distinct. - fix submount shutdown handling. - try not to block on expire. - add configuration paramter UMOUNT_WAIT. - fix multi mount race. - fix nfs4 colon escape handling. - check replicated list after probe. - add replicated server selection debug logging. - update replicated server selection documentation. - use /dev/urandom instead of /dev/random. - check for mtab pointing to /proc/mounts. - fix interface config buffer size. - fix percent hack heap corruption. - fix segv during library re-open. - fix incorrect pthreads condition handling for expire requests. --- diff --git a/autofs-5.0.2-handle-zero-length-nis-key-update.patch b/autofs-5.0.2-handle-zero-length-nis-key-update.patch new file mode 100644 index 0000000..2b52d4c --- /dev/null +++ b/autofs-5.0.2-handle-zero-length-nis-key-update.patch @@ -0,0 +1,53 @@ +autofs-5.0.3 - handle zero length nis key update + +From: Ian Kent + +A zero length key is invalid but so is a single character +non-printable key and it causes the parser to get confused +as well. +--- + + modules/lookup_yp.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + + +--- autofs-5.0.2.orig/modules/lookup_yp.c ++++ autofs-5.0.2/modules/lookup_yp.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -168,6 +169,14 @@ int yp_all_master_callback(int status, c + if (status != YP_TRUE) + return status; + ++ /* Ignore zero length and single non-printable char keys */ ++ if (ypkeylen == 0 || (ypkeylen == 1 && !isprint(*ypkey))) { ++ warn(logopt, MODPREFIX ++ "ignoring invalid map entry, zero length or " ++ "single character non-printable key"); ++ return 0; ++ } ++ + /* + * Ignore keys beginning with '+' as plus map + * inclusion is only valid in file maps. +@@ -263,6 +272,14 @@ int yp_all_callback(int status, char *yp + if (status != YP_TRUE) + return status; + ++ /* Ignore zero length and single non-printable char keys */ ++ if (ypkeylen == 0 || (ypkeylen == 1 && !isprint(*ypkey))) { ++ warn(logopt, MODPREFIX ++ "ignoring invalid map entry, zero length or " ++ "single character non-printable key"); ++ return 0; ++ } ++ + /* + * Ignore keys beginning with '+' as plus map + * inclusion is only valid in file maps. diff --git a/autofs-5.0.3-add-missing-uris-list-locking.patch b/autofs-5.0.3-add-missing-uris-list-locking.patch new file mode 100644 index 0000000..d89f0d7 --- /dev/null +++ b/autofs-5.0.3-add-missing-uris-list-locking.patch @@ -0,0 +1,129 @@ +autofs-5.0.3 - add missing uris list locking + +From: Ian Kent + +Add inadvertantly ommitted server list locking in LDAP module. +--- + + include/lookup_ldap.h | 1 + + modules/lookup_ldap.c | 39 ++++++++++++++++++++++++++++++++++++++- + 2 files changed, 39 insertions(+), 1 deletion(-) + + +--- autofs-5.0.3.orig/include/lookup_ldap.h ++++ autofs-5.0.3/include/lookup_ldap.h +@@ -54,6 +54,7 @@ struct lookup_context { + * sdns is the list of basdns to check, done in the order + * given in configuration. + */ ++ pthread_mutex_t uris_mutex; + struct list_head *uri; + char *cur_host; + struct ldap_searchdn *sdns; +--- autofs-5.0.3.orig/modules/lookup_ldap.c ++++ autofs-5.0.3/modules/lookup_ldap.c +@@ -122,6 +122,22 @@ int ldap_parse_page_control(LDAP *ldap, + } + #endif /* HAVE_LDAP_PARSE_PAGE_CONTROL */ + ++static void uris_mutex_lock(struct lookup_context *ctxt) ++{ ++ int status = pthread_mutex_lock(&ctxt->uris_mutex); ++ if (status) ++ fatal(status); ++ return; ++} ++ ++static void uris_mutex_unlock(struct lookup_context *ctxt) ++{ ++ int status = pthread_mutex_unlock(&ctxt->uris_mutex); ++ if (status) ++ fatal(status); ++ return; ++} ++ + int bind_ldap_anonymous(unsigned logopt, LDAP *ldap, struct lookup_context *ctxt) + { + int rv; +@@ -627,16 +643,20 @@ static LDAP *find_server(unsigned logopt + LIST_HEAD(tmp); + + /* Try each uri in list, add connect fails to tmp list */ ++ uris_mutex_lock(ctxt); + p = ctxt->uri->next; + while(p != ctxt->uri) { + this = list_entry(p, struct ldap_uri, list); +- p = p->next; ++ uris_mutex_unlock(ctxt); + debug(logopt, "trying server %s", this->uri); + ldap = connect_to_server(logopt, this->uri, ctxt); + if (ldap) { + info(logopt, "connected to uri %s", this->uri); ++ uris_mutex_lock(ctxt); + break; + } ++ uris_mutex_lock(ctxt); ++ p = p->next; + list_del_init(&this->list); + list_add_tail(&this->list, &tmp); + } +@@ -648,6 +668,7 @@ static LDAP *find_server(unsigned logopt + list_splice(ctxt->uri, &tmp); + INIT_LIST_HEAD(ctxt->uri); + list_splice(&tmp, ctxt->uri); ++ uris_mutex_unlock(ctxt); + + return ldap; + } +@@ -662,14 +683,18 @@ static LDAP *do_reconnect(unsigned logop + return ldap; + } + ++ uris_mutex_lock(ctxt); + this = list_entry(ctxt->uri->next, struct ldap_uri, list); ++ uris_mutex_unlock(ctxt); + ldap = do_connect(logopt, this->uri, ctxt); + if (ldap) + return ldap; + + /* Failed to connect, put at end of list */ ++ uris_mutex_lock(ctxt); + list_del_init(&this->list); + list_add_tail(&this->list, ctxt->uri); ++ uris_mutex_unlock(ctxt); + + #ifdef WITH_SASL + autofs_sasl_dispose(ctxt); +@@ -1203,6 +1228,8 @@ done: + + static void free_context(struct lookup_context *ctxt) + { ++ int ret; ++ + if (ctxt->schema) { + free(ctxt->schema->map_class); + free(ctxt->schema->map_attr); +@@ -1235,6 +1262,9 @@ static void free_context(struct lookup_c + free(ctxt->base); + if (ctxt->uri) + defaults_free_uris(ctxt->uri); ++ ret = pthread_mutex_destroy(&ctxt->uris_mutex); ++ if (ret) ++ fatal(ret); + if (ctxt->sdns) + defaults_free_searchdns(ctxt->sdns); + free(ctxt); +@@ -1286,6 +1316,13 @@ int lookup_init(const char *mapfmt, int + } + memset(ctxt, 0, sizeof(struct lookup_context)); + ++ ret = pthread_mutex_init(&ctxt->uris_mutex, NULL); ++ if (ret) { ++ error(LOGOPT_ANY, MODPREFIX "failed to init uris mutex"); ++ free(ctxt); ++ return 1; ++ } ++ + /* If a map type isn't explicitly given, parse it like sun entries. */ + if (mapfmt == NULL) + mapfmt = MAPFMT_DEFAULT; diff --git a/autofs-5.0.3-add-replicated-debug-logging.patch b/autofs-5.0.3-add-replicated-debug-logging.patch new file mode 100644 index 0000000..6d72ee9 --- /dev/null +++ b/autofs-5.0.3-add-replicated-debug-logging.patch @@ -0,0 +1,174 @@ +autofs-5.0.3 - add replicated server selection debug logging + +From: Ian Kent + +Add some debug logging to the replicated server selection code. +--- + + modules/replicated.c | 86 +++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 66 insertions(+), 20 deletions(-) + + +--- autofs-5.0.2.orig/modules/replicated.c ++++ autofs-5.0.2/modules/replicated.c +@@ -404,6 +404,10 @@ static unsigned int get_nfs_info(unsigne + double taken = 0; + int status, count = 0; + ++ debug(logopt, ++ "called for host %s proto %s version 0x%x", ++ host->name, proto, version); ++ + memset(&parms, 0, sizeof(struct pmap)); + + parms.pm_prog = NFS_PROGRAM; +@@ -428,11 +432,17 @@ static unsigned int get_nfs_info(unsigne + status = rpc_ping_proto(rpc_info); + gettimeofday(&end, &tz); + if (status) { +- if (random_selection) ++ double reply; ++ if (random_selection) { + /* Random value between 0 and 1 */ +- taken += ((float) random())/((float) RAND_MAX+1); +- else +- taken += elapsed(start, end);; ++ reply = ((float) random())/((float) RAND_MAX+1); ++ debug(logopt, ++ "nfs v4 random selection time: %f", reply); ++ } else { ++ reply = elapsed(start, end); ++ debug(logopt, "nfs v4 rpc ping time: %f", reply); ++ } ++ taken += reply; + count++; + supported = NFS4_SUPPORTED; + } +@@ -470,11 +480,17 @@ v3_ver: + status = rpc_ping_proto(rpc_info); + gettimeofday(&end, &tz); + if (status) { +- if (random_selection) ++ double reply; ++ if (random_selection) { + /* Random value between 0 and 1 */ +- taken += ((float) random())/((float) RAND_MAX+1); +- else +- taken += elapsed(start, end);; ++ reply = ((float) random())/((float) RAND_MAX+1); ++ debug(logopt, ++ "nfs v3 random selection time: %f", reply); ++ } else { ++ reply = elapsed(start, end); ++ debug(logopt, "nfs v3 rpc ping time: %f", reply); ++ } ++ taken += reply; + count++; + supported |= NFS3_SUPPORTED; + } +@@ -504,11 +520,17 @@ v2_ver: + status = rpc_ping_proto(rpc_info); + gettimeofday(&end, &tz); + if (status) { +- if (random_selection) ++ double reply; ++ if (random_selection) { + /* Random value between 0 and 1 */ +- taken += ((float) random())/((float) RAND_MAX+1); +- else +- taken += elapsed(start, end);; ++ reply = ((float) random())/((float) RAND_MAX+1); ++ debug(logopt, ++ "nfs v2 random selection time: %f", reply); ++ } else { ++ reply = elapsed(start, end);; ++ debug(logopt, "nfs v2 rpc ping time: %f", reply); ++ } ++ taken += reply; + count++; + supported |= NFS2_SUPPORTED; + } +@@ -533,6 +555,9 @@ done_ver: + /* Allow for user bias */ + if (host->weight) + host->cost *= (host->weight + 1); ++ ++ debug(logopt, "host %s cost %ld weight %d", ++ host->name, host->cost, host->weight); + } + + return supported; +@@ -603,6 +628,9 @@ static int get_supported_ver_and_cost(un + time_t timeout = RPC_TIMEOUT; + int status; + ++ debug(logopt, ++ "called with host %s version 0x%x", host->name, version); ++ + memset(&pm_info, 0, sizeof(struct conn_info)); + memset(&rpc_info, 0, sizeof(struct conn_info)); + memset(&parms, 0, sizeof(struct pmap)); +@@ -681,11 +709,14 @@ static int get_supported_ver_and_cost(un + status = rpc_ping_proto(&rpc_info); + gettimeofday(&end, &tz); + if (status) { +- if (random_selection) ++ if (random_selection) { + /* Random value between 0 and 1 */ + taken = ((float) random())/((float) RAND_MAX+1); +- else ++ debug(logopt, "random selection time %f", taken); ++ } else { + taken = elapsed(start, end); ++ debug(logopt, "rpc ping time %f", taken); ++ } + } + } + done: +@@ -705,6 +736,8 @@ done: + if (host->weight) + host->cost *= (host->weight + 1); + ++ debug(logopt, "cost %ld weight %d", host->cost, host->weight); ++ + return 1; + } + +@@ -811,18 +844,31 @@ int prune_host_list(unsigned logopt, str + max_udp_count = mmax(v4_udp_count, v3_udp_count, v2_udp_count); + max_count = max(max_tcp_count, max_udp_count); + +- if (max_count == v4_tcp_count) ++ if (max_count == v4_tcp_count) { + selected_version = NFS4_TCP_SUPPORTED; +- else if (max_count == v3_tcp_count) ++ debug(logopt, ++ "selected subset of hosts that support NFS4 over TCP"); ++ } else if (max_count == v3_tcp_count) { + selected_version = NFS3_TCP_SUPPORTED; +- else if (max_count == v2_tcp_count) ++ debug(logopt, ++ "selected subset of hosts that support NFS3 over TCP"); ++ } else if (max_count == v2_tcp_count) { + selected_version = NFS2_TCP_SUPPORTED; +- else if (max_count == v4_udp_count) ++ debug(logopt, ++ "selected subset of hosts that support NFS2 over TCP"); ++ } else if (max_count == v4_udp_count) { + selected_version = NFS4_UDP_SUPPORTED; +- else if (max_count == v3_udp_count) ++ debug(logopt, ++ "selected subset of hosts that support NFS4 over UDP"); ++ } else if (max_count == v3_udp_count) { + selected_version = NFS3_UDP_SUPPORTED; +- else if (max_count == v2_udp_count) ++ debug(logopt, ++ "selected subset of hosts that support NFS3 over UDP"); ++ } else if (max_count == v2_udp_count) { + selected_version = NFS2_UDP_SUPPORTED; ++ debug(logopt, ++ "selected subset of hosts that support NFS2 over UDP"); ++ } + + /* Add local and hosts with selected version to new list */ + this = *list; diff --git a/autofs-5.0.3-add-umount_wait-parameter.patch b/autofs-5.0.3-add-umount_wait-parameter.patch new file mode 100644 index 0000000..ed2d527 --- /dev/null +++ b/autofs-5.0.3-add-umount_wait-parameter.patch @@ -0,0 +1,138 @@ +autofs-5.0.3 - add configuration paramter UMOUNT_WAIT + +From: Ian Kent + +To try and prevent expire delays when trying to umount from a server +that is not available we limit the time that we wait for a response +from the spawned umount process before sending it a SIGTERM signal. +This patch adds a configuration parameter to allow this wait to be +changed if needed. +--- + + daemon/spawn.c | 2 +- + include/defaults.h | 2 ++ + lib/defaults.c | 13 +++++++++++++ + man/auto.master.5.in | 6 ++++++ + redhat/autofs.sysconfig.in | 4 ++++ + samples/autofs.conf.default.in | 4 ++++ + 6 files changed, 30 insertions(+), 1 deletions(-) + + +diff --git a/daemon/spawn.c b/daemon/spawn.c +index e3c355e..6b26c41 100644 +--- a/daemon/spawn.c ++++ b/daemon/spawn.c +@@ -502,7 +502,7 @@ int spawn_umount(unsigned logopt, ...) + unsigned int options; + unsigned int retries = MTAB_LOCK_RETRIES; + int ret, printed = 0; +- unsigned int wait = 12; ++ unsigned int wait = defaults_get_umount_wait(); + + #ifdef ENABLE_MOUNT_LOCKING + options = SPAWN_OPT_LOCK; +diff --git a/include/defaults.h b/include/defaults.h +index 6e4f52a..12534ec 100644 +--- a/include/defaults.h ++++ b/include/defaults.h +@@ -24,6 +24,7 @@ + + #define DEFAULT_TIMEOUT 600 + #define DEFAULT_NEGATIVE_TIMEOUT 60 ++#define DEFAULT_UMOUNT_WAIT 12 + #define DEFAULT_BROWSE_MODE 1 + #define DEFAULT_LOGGING 0 + +@@ -59,6 +60,7 @@ struct ldap_schema *defaults_get_schema(void); + struct ldap_searchdn *defaults_get_searchdns(void); + void defaults_free_searchdns(struct ldap_searchdn *); + unsigned int defaults_get_append_options(void); ++unsigned int defaults_get_umount_wait(void); + const char *defaults_get_auth_conf_file(void); + + #endif +diff --git a/lib/defaults.c b/lib/defaults.c +index 8149549..21d76d2 100644 +--- a/lib/defaults.c ++++ b/lib/defaults.c +@@ -45,6 +45,7 @@ + #define ENV_NAME_VALUE_ATTR "VALUE_ATTRIBUTE" + + #define ENV_APPEND_OPTIONS "APPEND_OPTIONS" ++#define ENV_UMOUNT_WAIT "UMOUNT_WAIT" + #define ENV_AUTH_CONF_FILE "AUTH_CONF_FILE" + + static const char *default_master_map_name = DEFAULT_MASTER_MAP_NAME; +@@ -320,6 +321,7 @@ unsigned int defaults_read_config(unsigned int to_syslog) + check_set_config_value(key, ENV_NAME_ENTRY_ATTR, value, to_syslog) || + check_set_config_value(key, ENV_NAME_VALUE_ATTR, value, to_syslog) || + check_set_config_value(key, ENV_APPEND_OPTIONS, value, to_syslog) || ++ check_set_config_value(key, ENV_UMOUNT_WAIT, value, to_syslog) || + check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog)) + ; + } +@@ -647,6 +649,17 @@ unsigned int defaults_get_append_options(void) + return res; + } + ++unsigned int defaults_get_umount_wait(void) ++{ ++ long wait; ++ ++ wait = get_env_number(ENV_UMOUNT_WAIT); ++ if (wait < 0) ++ wait = DEFAULT_UMOUNT_WAIT; ++ ++ return (unsigned int) wait; ++} ++ + const char *defaults_get_auth_conf_file(void) + { + char *cf; +diff --git a/man/auto.master.5.in b/man/auto.master.5.in +index 49a711c..9cc5f02 100644 +--- a/man/auto.master.5.in ++++ b/man/auto.master.5.in +@@ -174,6 +174,12 @@ Set the default timeout for caching failed key lookups (program default + 60). If the equivalent command line option is given it will override this + setting. + .TP ++.B UMOUNT_WAIT ++Set the default time to wait for a response from a spawned umount(8) ++before sending it a SIGTERM. Note that we still need to wait for the ++RPC layer to timeout before the sub-process exits so this isn't ideal ++but it is the best we can do. ++.TP + .B BROWSE_MODE + Maps are browsable by default (program default "yes"). + .TP +diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in +index 636763a..ce64feb 100644 +--- a/redhat/autofs.sysconfig.in ++++ b/redhat/autofs.sysconfig.in +@@ -14,6 +14,10 @@ TIMEOUT=300 + # + #NEGATIVE_TIMEOUT=60 + # ++# UMOUNT_WAIT - time to wait for a response from umount(8). ++# ++#UMOUNT_WAIT=12 ++# + # BROWSE_MODE - maps are browsable by default. + # + BROWSE_MODE="no" +diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in +index 086ba4f..0231e1d 100644 +--- a/samples/autofs.conf.default.in ++++ b/samples/autofs.conf.default.in +@@ -14,6 +14,10 @@ TIMEOUT=300 + # + #NEGATIVE_TIMEOUT=60 + # ++# UMOUNT_WAIT - time to wait for a response from umount(8). ++# ++#UMOUNT_WAIT=12 ++# + # BROWSE_MODE - maps are browsable by default. + # + BROWSE_MODE="no" diff --git a/autofs-5.0.3-allow-dir-create-on-nfs-root.patch b/autofs-5.0.3-allow-dir-create-on-nfs-root.patch new file mode 100644 index 0000000..52b70a8 --- /dev/null +++ b/autofs-5.0.3-allow-dir-create-on-nfs-root.patch @@ -0,0 +1,33 @@ +autofs-5.0.3 - allow directory create on NFS root + +From: Matthias Koenig + +autofs will not create the autofs mountpoint path if the filesystem is +not a locally mounted filesystem (e.g. a NFS mounted filesystem). + +contained_in_local_fs() returns false in this case. This is intentional +but breaks clients that have an NFS root filesystem. In this case we +shouldn't impose this restriction. +--- + + lib/mounts.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + + +--- autofs-5.0.2.orig/lib/mounts.c ++++ autofs-5.0.2/lib/mounts.c +@@ -363,7 +363,13 @@ int contained_in_local_fs(const char *pa + if (!strncmp(path, this->path, len)) { + if (len > 1 && pathlen > len && path[len] != '/') + continue; +- else if (this->fs_name[0] == '/') { ++ else if (len == 1 && this->path[0] == '/') { ++ /* ++ * always return true on rootfs, we don't ++ * want to break diskless clients. ++ */ ++ ret = 1; ++ } else if (this->fs_name[0] == '/') { + if (strlen(this->fs_name) > 1) { + if (this->fs_name[1] != '/') + ret = 1; diff --git a/autofs-5.0.3-check-direct-path-len.patch b/autofs-5.0.3-check-direct-path-len.patch new file mode 100644 index 0000000..648ccd3 --- /dev/null +++ b/autofs-5.0.3-check-direct-path-len.patch @@ -0,0 +1,72 @@ +autofs-5.0.3 - check direct mount path length + +From: Ian Kent + +The length of the path corresponding to a direct mount can't be +checked in the kernel so we need to check it will fit into the +request structire before going ahead with the mount. The name +field of the request structure is also to short and so is increased +to PATH_MAX. +--- + + daemon/direct.c | 15 +++++++++++++-- + include/automount.h | 2 +- + 2 files changed, 14 insertions(+), 3 deletions(-) + + +--- autofs-5.0.2.orig/daemon/direct.c ++++ autofs-5.0.2/daemon/direct.c +@@ -1411,7 +1411,7 @@ static void *do_mount_direct(void *arg) + } + + cont: +- status = lookup_nss_mount(ap, NULL, mt.name, strlen(mt.name)); ++ status = lookup_nss_mount(ap, NULL, mt.name, mt.len); + /* + * Direct mounts are always a single mount. If it fails there's + * nothing to undo so just complain +@@ -1454,7 +1454,7 @@ 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, len, cl_flags, state; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + +@@ -1525,6 +1525,16 @@ int handle_packet_missing_direct(struct + return 1; + } + ++ len = strlen(me->key); ++ if (len >= PATH_MAX) { ++ error(ap->logopt, "direct mount path too long %s", me->key); ++ send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); ++ close(ioctlfd); ++ cache_unlock(mc); ++ pthread_setcancelstate(state, NULL); ++ return 1; ++ } ++ + mt = malloc(sizeof(struct pending_args)); + if (!mt) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +@@ -1553,6 +1563,7 @@ int handle_packet_missing_direct(struct + mt->ioctlfd = ioctlfd; + mt->mc = mc; + strcpy(mt->name, me->key); ++ mt->len = len; + mt->dev = me->dev; + mt->type = NFY_MOUNT; + mt->uid = pkt->uid; +--- autofs-5.0.2.orig/include/automount.h ++++ autofs-5.0.2/include/automount.h +@@ -409,7 +409,7 @@ struct pending_args { + int type; /* Type of packet */ + int ioctlfd; /* Mount ioctl fd */ + struct mapent_cache *mc; /* Cache Containing entry */ +- char name[KEY_MAX_LEN]; /* Name field of the request */ ++ char name[PATH_MAX]; /* Name field of the request */ + dev_t dev; /* device number of mount */ + unsigned int len; /* Name field len */ + uid_t uid; /* uid of requestor */ diff --git a/autofs-5.0.3-check-for-kernel-automount-fix.patch b/autofs-5.0.3-check-for-kernel-automount-fix.patch new file mode 100644 index 0000000..225f51b --- /dev/null +++ b/autofs-5.0.3-check-for-kernel-automount-fix.patch @@ -0,0 +1,25 @@ +autofs-5.0.3 - check for kernel automount fix + +From: Ian Kent + +Look in the correct mount table for kernel automounted "nohide" +mounts. +--- + + daemon/direct.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + + +diff --git a/daemon/direct.c b/daemon/direct.c +index afb354e..13f572c 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -709,7 +709,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char * + * the kernel NFS client. + */ + if (me->multi != me && +- is_mounted(_PATH_MOUNTED, mountpoint, MNTS_REAL)) ++ is_mounted(_PROC_MOUNTS, mountpoint, MNTS_REAL)) + return MOUNT_OFFSET_IGNORE; + + /* diff --git a/autofs-5.0.3-check-for-kernel-automount.patch b/autofs-5.0.3-check-for-kernel-automount.patch new file mode 100644 index 0000000..766a0d8 --- /dev/null +++ b/autofs-5.0.3-check-for-kernel-automount.patch @@ -0,0 +1,189 @@ +autofs 5.0.3 - check for exported mounts automatically mounted by kernel + +From: Ian Kent + +If a server exports file systems that are automatically mounted by +the kernel client autofs will mistakenly over mount them when it +constructs and mounts its multi-mount triggers. + +This patch makes autofs check for this case and ignores them if the +kernel mounts them while it mounts multi-mount triggers. + +We don't want to fight with NFS over mounting these because it +confuses autofs and they magically go away when the owner mount is +umounted. This isn't ideal because autofs will mount these mounts +while constructing its multi-mount triggers but it is unavoidable +at the moment. +--- + + daemon/direct.c | 26 ++++++++++++++++++-------- + include/automount.h | 4 ++++ + lib/parse_subs.c | 26 ++++++++++++++++++-------- + 3 files changed, 40 insertions(+), 16 deletions(-) + + +--- autofs-5.0.2.orig/daemon/direct.c ++++ autofs-5.0.2/daemon/direct.c +@@ -664,12 +664,12 @@ int mount_autofs_offset(struct autofs_po + if (ap->state != ST_READMAP) + warn(ap->logopt, + "trigger %s already mounted", me->key); +- return 0; ++ return MOUNT_OFFSET_OK; + } + + if (me->ioctlfd != -1) { + error(ap->logopt, "active offset mount %s", me->key); +- return -1; ++ return MOUNT_OFFSET_FAIL; + } + + status = pthread_once(&key_mnt_params_once, key_mnt_params_init); +@@ -683,7 +683,7 @@ int mount_autofs_offset(struct autofs_po + crit(ap->logopt, + "mnt_params value create failed for offset mount %s", + me->key); +- return 0; ++ return MOUNT_OFFSET_OK; + } + mp->options = NULL; + +@@ -697,12 +697,22 @@ int mount_autofs_offset(struct autofs_po + if (!mp->options) { + mp->options = make_options_string(ap->path, ap->kpipefd, "offset"); + if (!mp->options) +- return 0; ++ return MOUNT_OFFSET_OK; + } + + /* In case the directory doesn't exist, try to mkdir it */ + if (mkdir_path(me->key, 0555) < 0) { + if (errno == EEXIST) { ++ /* ++ * If the mount point directory is a real mount ++ * and it isn't the root offset then it must be ++ * a mount that has been automatically mounted by ++ * the kernel NFS client. ++ */ ++ if (me->multi != me && ++ is_mounted(_PROC_MOUNTS, me->key, MNTS_REAL)) ++ return MOUNT_OFFSET_IGNORE; ++ + /* + * If we recieve an error, and it's EEXIST + * we know the directory was not created. +@@ -721,13 +731,13 @@ int mount_autofs_offset(struct autofs_po + debug(ap->logopt, + "can't create mount directory: %s, %s", + me->key, estr); +- return -1; ++ return MOUNT_OFFSET_FAIL; + } else { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + crit(ap->logopt, + "failed to create mount directory: %s, %s", + me->key, estr); +- return -1; ++ return MOUNT_OFFSET_FAIL; + } + } else { + /* No errors so the directory was successfully created */ +@@ -787,7 +797,7 @@ int mount_autofs_offset(struct autofs_po + + debug(ap->logopt, "mounted trigger %s", me->key); + +- return 0; ++ return MOUNT_OFFSET_OK; + + out_close: + close(ioctlfd); +@@ -797,7 +807,7 @@ out_err: + if (stat(me->key, &st) == 0 && me->dir_created) + rmdir_path(ap, me->key, st.st_dev); + +- return -1; ++ return MOUNT_OFFSET_FAIL; + } + + static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt) +--- autofs-5.0.2.orig/include/automount.h ++++ autofs-5.0.2/include/automount.h +@@ -468,6 +468,10 @@ struct autofs_point { + + /* Standard functions used by daemon or modules */ + ++#define MOUNT_OFFSET_OK 0 ++#define MOUNT_OFFSET_FAIL -1 ++#define MOUNT_OFFSET_IGNORE -2 ++ + 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); +--- autofs-5.0.2.orig/lib/parse_subs.c ++++ autofs-5.0.2/lib/parse_subs.c +@@ -390,7 +390,7 @@ int mount_multi_triggers(struct autofs_p + struct list_head *pos = NULL; + unsigned int fs_path_len; + unsigned int mounted; +- int start; ++ int ret, start; + + fs_path_len = strlen(root) + strlen(base); + if (fs_path_len > PATH_MAX) +@@ -411,15 +411,25 @@ int mount_multi_triggers(struct autofs_p + } + + oe = cache_lookup_offset(base, offset, start, &me->multi_list); +- if (!oe) ++ if (!oe || !oe->mapent) + 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 ++ ret = mount_autofs_offset(ap, oe); ++ if (ret >= MOUNT_OFFSET_OK) + mounted++; ++ else { ++ if (ret != MOUNT_OFFSET_IGNORE) ++ warn(ap->logopt, "failed to mount offset"); ++ else { ++ debug(ap->logopt, ++ "ignoring \"nohide\" trigger %s", ++ oe->key); ++ free(oe->mapent); ++ oe->mapent = NULL; ++ } ++ } + cont: + offset = cache_get_offset(base, + offset, start, &me->multi_list, &pos); +@@ -457,7 +467,7 @@ int umount_multi_triggers(struct autofs_ + + oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list); + /* root offset is a special case */ +- if (!oe || (strlen(oe->key) - start) == 1) ++ if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1) + continue; + + /* +@@ -481,7 +491,7 @@ int umount_multi_triggers(struct autofs_ + 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) ++ if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1) + continue; + + debug(ap->logopt, "umount offset %s", oe->key); +@@ -505,7 +515,7 @@ int umount_multi_triggers(struct autofs_ + 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, "/")) ++ if (mount_multi_triggers(ap, root, me, "/") < 0) + warn(ap->logopt, + "failed to remount offset triggers"); + return left++; diff --git a/autofs-5.0.3-check-replicated-list-after-probe.patch b/autofs-5.0.3-check-replicated-list-after-probe.patch new file mode 100644 index 0000000..696682f --- /dev/null +++ b/autofs-5.0.3-check-replicated-list-after-probe.patch @@ -0,0 +1,31 @@ +autofs-5.0.3 - check replicated list after probe + +From: Ian Kent + +When checking a list of servers for proximity and NFS version +the list may become empty after after the initial probe. This +case isn't handled and this patch adds it. +--- + + modules/replicated.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + + +--- autofs-5.0.2.orig/modules/replicated.c ++++ autofs-5.0.2/modules/replicated.c +@@ -768,6 +768,15 @@ int prune_host_list(unsigned logopt, str + this = next; + } + ++ /* ++ * The list of hosts that aren't proximity local may now ++ * be empty if we haven't been able probe any so we need ++ * to check again for a list containing only proximity ++ * local hosts. ++ */ ++ if (!first) ++ return 1; ++ + last = this; + + /* Select NFS version of highest number of closest servers */ diff --git a/autofs-5.0.3-clear-stale-on-map-read.patch b/autofs-5.0.3-clear-stale-on-map-read.patch new file mode 100644 index 0000000..c4f2730 --- /dev/null +++ b/autofs-5.0.3-clear-stale-on-map-read.patch @@ -0,0 +1,29 @@ +autofs-5.0.3 - clear stale flag on map read + +From: Ian Kent + +We're not properly clearing the map stale flag after a map re-read +which causes a re-read after every lookup for master map entries +that have the "browse" option set. I removed the line that did +this at some point in the past and I must have had a reason to +do so. We'll have to wait and see what shows up after fixing +it. +--- + + daemon/lookup.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + + +diff --git a/daemon/lookup.c b/daemon/lookup.c +index d33aadc..2277623 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -298,6 +298,8 @@ static int do_read_map(struct autofs_point *ap, struct map_source *map, time_t a + + status = lookup->lookup_read_map(ap, age, lookup->context); + ++ map->stale = 0; ++ + /* + * For maps that don't support enumeration return success + * and do whatever we must to have autofs function with an diff --git a/autofs-5.0.3-dont-abuse-ap-ghost-field.patch b/autofs-5.0.3-dont-abuse-ap-ghost-field.patch new file mode 100644 index 0000000..7e571c5 --- /dev/null +++ b/autofs-5.0.3-dont-abuse-ap-ghost-field.patch @@ -0,0 +1,77 @@ +autofs-5.0.3 - don't abuse the ap->ghost field on NFS mount + +From: Ian Kent + +Using the ap->ghost field in the autofs mount point struct, to prevent +the mount point directory from being removed, when attempting a bind +mount when an NFS mount is local may lead to incorrectly reading and +ghosting the map. This can happen if a mount request comes in during +a map re-read when the autofs map doesn't have the browse option set. +This patch corrects that by using the existence check in the bind mount +module instead of the hack of changing the struct field. +--- + + modules/mount_bind.c | 2 +- + modules/mount_nfs.c | 11 ----------- + 2 files changed, 1 insertion(+), 12 deletions(-) + + +--- autofs-5.0.2.orig/modules/mount_bind.c ++++ autofs-5.0.2/modules/mount_bind.c +@@ -144,7 +144,7 @@ int mount_mount(struct autofs_point *ap, + if (ap->type != LKP_INDIRECT) + return 1; + +- if ((!ap->ghost && name_len) || !existed) ++ if ((!ap->ghost && name_len) && !existed) + rmdir_path(ap, fullpath, ap->dev); + + return err; +--- autofs-5.0.2.orig/modules/mount_nfs.c ++++ autofs-5.0.2/modules/mount_nfs.c +@@ -62,7 +62,6 @@ int mount_mount(struct autofs_point *ap, + { + char *fullpath, buf[MAX_ERR_BUF]; + struct host *this, *hosts = NULL; +- unsigned int save_ghost = ap->ghost; + unsigned int vers; + char *nfsoptions = NULL; + int len, rlen, status, err, existed = 1; +@@ -186,13 +185,6 @@ int mount_mount(struct autofs_point *ap, + if (!status) + existed = 0; + +- /* +- * We need to stop the bind mount module from removing the +- * mount point directory if a bind attempt fails so abuse +- * the ap->ghost field for this. +- */ +- ap->ghost = 1; +- + this = hosts; + while (this) { + char *loc, *port_opt = NULL; +@@ -229,7 +221,6 @@ int mount_mount(struct autofs_point *ap, + /* Success - we're done */ + if (!err) { + free_host_list(&hosts); +- ap->ghost = save_ghost; + return 0; + } + +@@ -271,7 +262,6 @@ int mount_mount(struct autofs_point *ap, + info(ap->logopt, MODPREFIX "mounted %s on %s", loc, fullpath); + free(loc); + free_host_list(&hosts); +- ap->ghost = save_ghost; + return 0; + } + +@@ -281,7 +271,6 @@ int mount_mount(struct autofs_point *ap, + + forced_fail: + free_host_list(&hosts); +- ap->ghost = save_ghost; + + /* If we get here we've failed to complete the mount */ + diff --git a/autofs-5.0.3-dont-block-on-expire.patch b/autofs-5.0.3-dont-block-on-expire.patch new file mode 100644 index 0000000..12616a4 --- /dev/null +++ b/autofs-5.0.3-dont-block-on-expire.patch @@ -0,0 +1,467 @@ +autofs-5.0.3 - try not to block on expire + +From: Ian Kent + +When a server is not available umount and any stat statfs and related +function calls may block for a significant amount of time. This effects +expire timeouts a lot due to their synchronous nature. This patch limits +the time we wait on spawned umounts and elininates calls to functions +that would block. This allows us to retry the umount on the next expire +event and continue the expire of remaining mounts. +--- + + daemon/automount.c | 34 +++++++++++++++++------------- + daemon/direct.c | 29 +++++--------------------- + daemon/indirect.c | 26 ++++++++--------------- + daemon/spawn.c | 59 +++++++++++++++++++++++++++++++++++++++++++---------- + include/master.h | 1 + lib/master.c | 23 ++++++++++++++++++++ + lib/mounts.c | 48 +------------------------------------------ + 7 files changed, 110 insertions(+), 110 deletions(-) + + +--- autofs-5.0.2.orig/daemon/automount.c ++++ autofs-5.0.2/daemon/automount.c +@@ -247,9 +247,17 @@ static int walk_tree(const char *base, i + int, void *), int incl, unsigned logopt, void *arg) + { + char buf[PATH_MAX + 1]; +- struct stat st; ++ struct stat st, *pst = &st; ++ int ret; ++ ++ if (!is_mounted(_PATH_MOUNTED, base, MNTS_REAL)) ++ ret = lstat(base, pst); ++ else { ++ pst = NULL; ++ ret = 0; ++ } + +- if (lstat(base, &st) != -1 && (fn) (logopt, base, &st, 0, arg)) { ++ if (ret != -1 && (fn) (logopt, base, pst, 0, arg)) { + if (S_ISDIR(st.st_mode)) { + struct dirent **de; + int n; +@@ -283,7 +291,7 @@ static int walk_tree(const char *base, i + free(de); + } + if (incl) +- (fn) (logopt, base, &st, 1, arg); ++ (fn) (logopt, base, pst, 1, arg); + } + return 0; + } +@@ -294,6 +302,9 @@ static int rm_unwanted_fn(unsigned logop + char buf[MAX_ERR_BUF]; + struct stat newst; + ++ if (!st) ++ return 0; ++ + if (when == 0) { + if (st->st_dev != dev) + return 0; +@@ -344,8 +355,8 @@ static int counter_fn(unsigned logopt, c + { + struct counter_args *counter = (struct counter_args *) arg; + +- if (S_ISLNK(st->st_mode) || (S_ISDIR(st->st_mode) +- && st->st_dev != counter->dev)) { ++ if (!st || (S_ISLNK(st->st_mode) || (S_ISDIR(st->st_mode) ++ && st->st_dev != counter->dev))) { + counter->count++; + return 0; + } +@@ -512,9 +523,8 @@ static int umount_subtree_mounts(struct + int umount_multi(struct autofs_point *ap, const char *path, int incl) + { + struct mapent_cache *nc; +- struct statfs fs; + int is_autofs_fs; +- int ret, left; ++ int left; + + debug(ap->logopt, "path %s incl %d", path, incl); + +@@ -526,13 +536,9 @@ int umount_multi(struct autofs_point *ap + } + cache_unlock(nc); + +- ret = statfs(path, &fs); +- if (ret == -1) { +- error(ap->logopt, "could not stat fs of %s", path); +- return 1; +- } +- +- is_autofs_fs = fs.f_type == (__SWORD_TYPE) AUTOFS_SUPER_MAGIC ? 1 : 0; ++ is_autofs_fs = 0; ++ if (master_find_submount(ap, path)) ++ is_autofs_fs = 1; + + left = 0; + +--- autofs-5.0.2.orig/daemon/direct.c ++++ autofs-5.0.2/daemon/direct.c +@@ -152,7 +152,7 @@ int do_umount_autofs_direct(struct autof + + retries = UMOUNT_RETRIES; + while ((rv = umount(me->key)) == -1 && retries--) { +- struct timespec tm = {0, 100000000}; ++ struct timespec tm = {0, 200000000}; + if (errno != EBUSY) + break; + nanosleep(&tm, NULL); +@@ -604,7 +604,7 @@ int umount_autofs_offset(struct autofs_p + + retries = UMOUNT_RETRIES; + while ((rv = umount(me->key)) == -1 && retries--) { +- struct timespec tm = {0, 100000000}; ++ struct timespec tm = {0, 200000000}; + if (errno != EBUSY) + break; + nanosleep(&tm, NULL); +@@ -705,7 +705,7 @@ int mount_autofs_offset(struct autofs_po + * the kernel NFS client. + */ + if (me->multi != me && +- is_mounted(_PROC_MOUNTS, me->key, MNTS_REAL)) ++ is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL)) + return MOUNT_OFFSET_IGNORE; + + /* +@@ -807,17 +807,7 @@ out_err: + + 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); +- error(logopt, "fstat failed: %s", estr); +- return 0; +- } +- +- retries = (count_mounts(logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES; ++ int ret, retries = EXPIRE_RETRIES; + + while (retries--) { + struct timespec tm = {0, 100000000}; +@@ -911,7 +901,6 @@ void *expire_proc_direct(void *arg) + + if (!strcmp(next->fs_type, "autofs")) { + struct stat st; +- struct statfs fs; + int ioctlfd; + + cache_unlock(me->mc); +@@ -932,14 +921,8 @@ void *expire_proc_direct(void *arg) + continue; + } + +- if (statfs(next->path, &fs) == -1) { +- pthread_setcancelstate(cur_state, NULL); +- warn(ap->logopt, +- "fstatfs failed for %s", next->path); +- continue; +- } +- +- if (fs.f_type != (__SWORD_TYPE) AUTOFS_SUPER_MAGIC) { ++ /* It's got a mount, deal with in the outer loop */ ++ if (tree_is_mounted(mnts, me->key, MNTS_REAL)) { + pthread_setcancelstate(cur_state, NULL); + continue; + } +--- autofs-5.0.2.orig/daemon/indirect.c ++++ autofs-5.0.2/daemon/indirect.c +@@ -285,7 +285,7 @@ int umount_autofs_indirect(struct autofs + + retries = UMOUNT_RETRIES; + while ((rv = umount(ap->path)) == -1 && retries--) { +- struct timespec tm = {0, 100000000}; ++ struct timespec tm = {0, 200000000}; + if (errno != EBUSY) + break; + nanosleep(&tm, NULL); +@@ -368,17 +368,7 @@ force_umount: + + 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); +- error(ap->logopt, "fstat failed: %s", estr); +- return 0; +- } +- +- retries = (count_mounts(ap->logopt, path, st.st_dev) + 1) * EXPIRE_RETRIES; ++ int ret, retries = EXPIRE_RETRIES; + + while (retries--) { + struct timespec tm = {0, 100000000}; +@@ -512,7 +502,6 @@ void *expire_proc_indirect(void *arg) + left++; + pthread_setcancelstate(cur_state, NULL); + } +- pthread_cleanup_pop(1); + + /* + * If there are no more real mounts left we could still +@@ -520,12 +509,17 @@ void *expire_proc_indirect(void *arg) + * umount them here. + */ + if (mnts) { ++ int retries; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); +- ret = expire_indirect(ap, ap->ioctlfd, ap->path, now); +- if (!ret) +- left++; ++ retries = (count_mounts(ap->logopt, ap->path, ap->dev) + 1); ++ while (retries--) { ++ ret = expire_indirect(ap, ap->ioctlfd, ap->path, now); ++ if (!ret) ++ left++; ++ } + pthread_setcancelstate(cur_state, NULL); + } ++ pthread_cleanup_pop(1); + + count = offsets = submnts = 0; + mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 0); +--- autofs-5.0.2.orig/daemon/spawn.c ++++ autofs-5.0.2/daemon/spawn.c +@@ -89,13 +89,43 @@ void reset_signals(void) + + #define ERRBUFSIZ 2047 /* Max length of error string excl \0 */ + +-static int do_spawn(unsigned logopt, unsigned int options, const char *prog, const char *const *argv) ++static int timed_read(int pipe, char *buf, size_t len, int time) ++{ ++ struct timeval timeout = { 0, 0 }; ++ struct timeval *tout = NULL; ++ fd_set wset, rset; ++ int ret; ++ ++ FD_ZERO(&rset); ++ FD_SET(pipe, &rset); ++ wset = rset; ++ ++ if (time != -1) { ++ timeout.tv_sec = time; ++ tout = &timeout; ++ } ++ ++ ret = select(pipe + 1, &rset, &wset, NULL, tout); ++ if (ret <= 0) { ++ if (ret == 0) ++ ret = -ETIMEDOUT; ++ return ret; ++ } ++ ++ while ((ret = read(pipe, buf, len)) == -1 && errno == EINTR); ++ ++ return ret; ++} ++ ++static int do_spawn(unsigned logopt, unsigned int wait, ++ unsigned int options, const char *prog, ++ const char *const *argv) + { + pid_t f; + int ret, status, pipefd[2]; + char errbuf[ERRBUFSIZ + 1], *p, *sp; + int errp, errn; +- int cancel_state; ++ int flags, cancel_state; + unsigned int use_lock = options & SPAWN_OPT_LOCK; + unsigned int use_access = options & SPAWN_OPT_ACCESS; + sigset_t allsigs, tmpsig, oldsig; +@@ -183,12 +213,15 @@ static int do_spawn(unsigned logopt, uns + return -1; + } + ++ if ((flags = fcntl(pipefd[0], F_GETFD, 0)) != -1) { ++ flags |= FD_CLOEXEC; ++ fcntl(pipefd[0], F_SETFD, flags); ++ } ++ + errp = 0; + do { +- while ((errn = +- read(pipefd[0], errbuf + errp, ERRBUFSIZ - errp)) == -1 +- && errno == EINTR); +- ++ errn = timed_read(pipefd[0], ++ errbuf + errp, ERRBUFSIZ - errp, wait); + if (errn > 0) { + errp += errn; + +@@ -213,6 +246,9 @@ static int do_spawn(unsigned logopt, uns + } + } while (errn > 0); + ++ if (errn == -ETIMEDOUT) ++ kill(f, SIGTERM); ++ + close(pipefd[0]); + + if (errp > 0) { +@@ -238,7 +274,7 @@ static int do_spawn(unsigned logopt, uns + + int spawnv(unsigned logopt, const char *prog, const char *const *argv) + { +- return do_spawn(logopt, SPAWN_OPT_NONE, prog, argv); ++ return do_spawn(logopt, -1, SPAWN_OPT_NONE, prog, argv); + } + + int spawnl(unsigned logopt, const char *prog, ...) +@@ -259,7 +295,7 @@ int spawnl(unsigned logopt, const char * + while ((*p++ = va_arg(arg, char *))); + va_end(arg); + +- return do_spawn(logopt, SPAWN_OPT_NONE, prog, (const char **) argv); ++ return do_spawn(logopt, -1, SPAWN_OPT_NONE, prog, (const char **) argv); + } + + int spawn_mount(unsigned logopt, ...) +@@ -307,7 +343,7 @@ int spawn_mount(unsigned logopt, ...) + va_end(arg); + + while (retries--) { +- ret = do_spawn(logopt, options, prog, (const char **) argv); ++ ret = do_spawn(logopt, -1, options, prog, (const char **) argv); + if (ret & MTAB_NOTUPDATED) { + struct timespec tm = {3, 0}; + +@@ -406,7 +442,7 @@ int spawn_bind_mount(unsigned logopt, .. + va_end(arg); + + while (retries--) { +- ret = do_spawn(logopt, options, prog, (const char **) argv); ++ ret = do_spawn(logopt, -1, options, prog, (const char **) argv); + if (ret & MTAB_NOTUPDATED) { + struct timespec tm = {3, 0}; + +@@ -466,6 +502,7 @@ int spawn_umount(unsigned logopt, ...) + unsigned int options; + unsigned int retries = MTAB_LOCK_RETRIES; + int ret, printed = 0; ++ unsigned int wait = 12; + + #ifdef ENABLE_MOUNT_LOCKING + options = SPAWN_OPT_LOCK; +@@ -488,7 +525,7 @@ int spawn_umount(unsigned logopt, ...) + va_end(arg); + + while (retries--) { +- ret = do_spawn(logopt, options, prog, (const char **) argv); ++ ret = do_spawn(logopt, wait, options, prog, (const char **) argv); + if (ret & MTAB_NOTUPDATED) { + /* + * If the mount succeeded but the mtab was not +--- autofs-5.0.2.orig/include/master.h ++++ autofs-5.0.2/include/master.h +@@ -91,6 +91,7 @@ void master_source_lock_cleanup(void *); + void master_source_current_wait(struct master_mapent *); + void master_source_current_signal(struct master_mapent *); + struct master_mapent *master_find_mapent(struct master *, const char *); ++struct autofs_point *master_find_submount(struct autofs_point *, const char *); + struct master_mapent *master_new_mapent(struct master *, const char *, time_t); + void master_add_mapent(struct master *, struct master_mapent *); + void master_remove_mapent(struct master_mapent *); +--- autofs-5.0.2.orig/lib/master.c ++++ autofs-5.0.2/lib/master.c +@@ -602,6 +602,29 @@ struct master_mapent *master_find_mapent + return NULL; + } + ++struct autofs_point *master_find_submount(struct autofs_point *ap, const char *path) ++{ ++ struct list_head *head, *p; ++ ++ mounts_mutex_lock(ap); ++ ++ head = &ap->submounts; ++ list_for_each(p, head) { ++ struct autofs_point *submount; ++ ++ submount = list_entry(p, struct autofs_point, mounts); ++ ++ if (!strcmp(submount->path, path)) { ++ mounts_mutex_unlock(ap); ++ return submount; ++ } ++ } ++ ++ mounts_mutex_unlock(ap); ++ ++ return NULL; ++} ++ + struct master_mapent *master_new_mapent(struct master *master, const char *path, time_t age) + { + struct master_mapent *entry; +--- autofs-5.0.2.orig/lib/mounts.c ++++ autofs-5.0.2/lib/mounts.c +@@ -1073,55 +1073,11 @@ free_tsv: + + 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); +- } ++ int rv; + ++ 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); diff --git a/autofs-5.0.3-dont-readmap-on-hup-for-new-mount.patch b/autofs-5.0.3-dont-readmap-on-hup-for-new-mount.patch new file mode 100644 index 0000000..39823c2 --- /dev/null +++ b/autofs-5.0.3-dont-readmap-on-hup-for-new-mount.patch @@ -0,0 +1,39 @@ +autofs-5.0.3 - don't readmap on HUP for new mount + +From: Ian Kent + +If we're performing a new mount during a HUP signal then +we will read the map during the mount. +--- + + lib/master.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + + +--- autofs-5.0.3.orig/lib/master.c ++++ autofs-5.0.3/lib/master.c +@@ -1108,8 +1108,6 @@ int master_mount_mounts(struct master *m + } + cache_unlock(nc); + +- check_update_map_sources(this, readall); +- + st_mutex_lock(); + + state_pipe = this->ap->state_pipe[1]; +@@ -1120,11 +1118,14 @@ int master_mount_mounts(struct master *m + + st_mutex_unlock(); + +- if (ret == -1 && save_errno == EBADF) ++ if (!ret) ++ check_update_map_sources(this, readall); ++ else if (ret == -1 && save_errno == EBADF) { + if (!master_do_mount(this)) { + list_del_init(&this->list); + master_free_mapent_sources(ap->entry, 1); + master_free_mapent(ap->entry); ++ } + } + } + diff --git a/autofs-5.0.3-dont-use-proc-for-is-running-check.patch b/autofs-5.0.3-dont-use-proc-for-is-running-check.patch new file mode 100644 index 0000000..662ac25 --- /dev/null +++ b/autofs-5.0.3-dont-use-proc-for-is-running-check.patch @@ -0,0 +1,591 @@ +autofs-5.0.3 - don't use proc for is running check + +From: Ian Kent + +Using /proc//cmdline to check if the daemon is running allows +any user to create a trivial program called "automount" and prevent +the system automounter from running simply by executing it and +leaving it running. This patch makes autofs use a flag file for this +check instead. +--- + + Makefile.conf.in | 3 + aclocal.m4 | 16 ++++ + configure | 35 +++++++++ + configure.in | 17 ++++ + daemon/Makefile | 5 - + daemon/automount.c | 95 +++++++------------------- + daemon/flag.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 293 insertions(+), 70 deletions(-) + create mode 100644 daemon/flag.c + + +--- autofs-5.0.2.orig/Makefile.conf.in ++++ autofs-5.0.2/Makefile.conf.in +@@ -74,6 +74,9 @@ autofsmapdir = @mapdir@ + # Location for autofs fifos + autofsfifodir = @fifodir@ + ++# Location for autofs flag file ++autofsflagdir = @flagdir@ ++ + # Where to install the automount program + sbindir = @sbindir@ + +--- autofs-5.0.2.orig/aclocal.m4 ++++ autofs-5.0.2/aclocal.m4 +@@ -136,6 +136,22 @@ AC_DEFUN(AF_FIFO_D, + done + fi]) + ++dnl -------------------------------------------------------------------------- ++dnl AF_FLAG_D ++dnl ++dnl Check the location of the autofs flag file directory ++dnl -------------------------------------------------------------------------- ++AC_DEFUN(AF_FLAG_D, ++[if test -z "$flagdir"; then ++ for flag_d in /var/run /tmp; do ++ if test -z "$flagdir"; then ++ if test -d "$flag_d"; then ++ flagdir="$flag_d" ++ fi ++ fi ++ done ++fi]) ++ + dnl ----------------------------------- ## -*- Autoconf -*- + dnl Check if --with-dmalloc was given. ## + dnl From Franc,ois Pinard ## +--- autofs-5.0.2.orig/configure ++++ autofs-5.0.2/configure +@@ -655,6 +655,7 @@ initdir + confdir + mapdir + fifodir ++flagdir + DMALLOCLIB + MOUNT + HAVE_MOUNT +@@ -1295,6 +1296,7 @@ Optional Packages: + --with-confdir=DIR use DIR for autofs configuration files + --with-mapdir=PATH look in PATH for mount maps used by the automounter + --with-fifodir=PATH use PATH as the directory for fifos used by the automounter ++ --with-flagdir=PATH use PATH as the directory for the flag file used by the automounter + --with-dmalloc use dmalloc, as in + http://www.dmalloc.com/dmalloc.tar.gz + --with-hesiod=DIR enable Hesiod support (libs and includes in DIR) +@@ -1876,6 +1878,36 @@ echo "${ECHO_T}$fifodir" >&6; } + + + # ++# The user can specify --with-flagdir=PATH to specify where autofs flag file goes ++# ++if test -z "$flagdir"; then ++ for flag_d in /var/run /tmp; do ++ if test -z "$flagdir"; then ++ if test -d "$flag_d"; then ++ flagdir="$flag_d" ++ fi ++ fi ++ done ++fi ++ ++# Check whether --with-flagdir was given. ++if test "${with_flagdir+set}" = set; then ++ withval=$with_flagdir; if test -z "$withval" -o "$withval" = "yes" -o "$withval" = "no" ++ then ++ : ++ else ++ filagdir="${withval}" ++ fi ++ ++fi ++ ++{ echo "$as_me:$LINENO: checking for autofs flag file directory" >&5 ++echo $ECHO_N "checking for autofs flag file directory... $ECHO_C" >&6; } ++{ echo "$as_me:$LINENO: result: $flagdir" >&5 ++echo "${ECHO_T}$flagdir" >&6; } ++ ++ ++# + # Optional include dmalloc + # + { echo "$as_me:$LINENO: checking if malloc debugging is wanted" >&5 +@@ -6247,6 +6279,7 @@ initdir!$initdir$ac_delim + confdir!$confdir$ac_delim + mapdir!$mapdir$ac_delim + fifodir!$fifodir$ac_delim ++flagdir!$flagdir$ac_delim + DMALLOCLIB!$DMALLOCLIB$ac_delim + MOUNT!$MOUNT$ac_delim + HAVE_MOUNT!$HAVE_MOUNT$ac_delim +@@ -6297,7 +6330,7 @@ LIBOBJS!$LIBOBJS$ac_delim + LTLIBOBJS!$LTLIBOBJS$ac_delim + _ACEOF + +- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 89; then ++ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 90; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +--- autofs-5.0.2.orig/configure.in ++++ autofs-5.0.2/configure.in +@@ -96,6 +96,23 @@ AC_MSG_RESULT([$fifodir]) + AC_SUBST(fifodir) + + # ++# The user can specify --with-flagdir=PATH to specify where autofs flag file goes ++# ++AF_FLAG_D() ++AC_ARG_WITH(flagdir, ++[ --with-flagdir=PATH use PATH as the directory for the flag file used by the automounter], ++ if test -z "$withval" -o "$withval" = "yes" -o "$withval" = "no" ++ then ++ : ++ else ++ filagdir="${withval}" ++ fi ++) ++AC_MSG_CHECKING([for autofs flag file directory]) ++AC_MSG_RESULT([$flagdir]) ++AC_SUBST(flagdir) ++ ++# + # Optional include dmalloc + # + AM_WITH_DMALLOC() +--- autofs-5.0.2.orig/daemon/Makefile ++++ autofs-5.0.2/daemon/Makefile +@@ -6,9 +6,9 @@ + include ../Makefile.rules + + SRCS = automount.c indirect.c direct.c spawn.c module.c mount.c \ +- lookup.c state.c ++ lookup.c state.c flag.c + OBJS = automount.o indirect.o direct.o spawn.o module.o mount.o \ +- lookup.o state.o ++ lookup.o state.o flag.o + + version := $(shell cat ../.version) + +@@ -17,6 +17,7 @@ CFLAGS += -DAUTOFS_LIB_DIR=\"$(autofslib + CFLAGS += -DAUTOFS_MAP_DIR=\"$(autofsmapdir)\" + CFLAGS += -DAUTOFS_CONF_DIR=\"$(autofsconfdir)\" + CFLAGS += -DAUTOFS_FIFO_DIR=\"$(autofsfifodir)\" ++CFLAGS += -DAUTOFS_FLAG_DIR=\"$(autofsflagdir)\" + CFLAGS += -DVERSION_STRING=\"$(version)\" + LDFLAGS += -rdynamic + LIBS = -ldl +--- autofs-5.0.2.orig/daemon/automount.c ++++ autofs-5.0.2/daemon/automount.c +@@ -81,6 +81,8 @@ pthread_key_t key_thread_stdenv_vars; + + #define MAX_OPEN_FILES 10240 + ++int aquire_flag_file(void); ++void release_flag_file(void); + static int umount_all(struct autofs_point *ap, int force); + + extern pthread_mutex_t master_mutex; +@@ -1098,7 +1100,7 @@ static int handle_packet(struct autofs_p + return -1; + } + +-static void become_daemon(unsigned foreground) ++static void become_daemon(unsigned foreground, unsigned daemon_check) + { + FILE *pidfp; + char buf[MAX_ERR_BUF]; +@@ -1118,9 +1120,14 @@ static void become_daemon(unsigned foreg + } + + /* Detach from foreground process */ +- if (foreground) ++ if (foreground) { ++ if (daemon_check && !aquire_flag_file()) { ++ fprintf(stderr, "%s: program is already running.\n", ++ program); ++ exit(1); ++ } + log_to_stderr(); +- else { ++ } else { + pid = fork(); + if (pid > 0) { + int r; +@@ -1136,6 +1143,13 @@ static void become_daemon(unsigned foreg + } + close(start_pipefd[0]); + ++ if (daemon_check && !aquire_flag_file()) { ++ fprintf(stderr, "%s: program is already running.\n", ++ program); ++ close(start_pipefd[1]); ++ exit(1); ++ } ++ + /* + * Make our own process group for "magic" reason: processes that share + * our pgrp see the raw filesystem behind the magic. +@@ -1143,6 +1157,7 @@ static void become_daemon(unsigned foreg + if (setsid() == -1) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + fprintf(stderr, "setsid: %s", estr); ++ close(start_pipefd[1]); + exit(1); + } + log_to_syslog(); +@@ -1617,64 +1632,6 @@ static void key_thread_stdenv_vars_destr + return; + } + +-static int is_automount_running(void) +-{ +- FILE *fp; +- DIR *dir; +- struct dirent entry; +- struct dirent *result; +- char path[PATH_MAX + 1], buf[PATH_MAX]; +- +- if ((dir = opendir("/proc")) == NULL) { +- fprintf(stderr, "cannot opendir(/proc)\n"); +- exit(1); +- } +- +- while (readdir_r(dir, &entry, &result) == 0) { +- int path_len, pid = 0; +- +- if (!result) +- break; +- +- if (*entry.d_name == '.') +- continue; +- +- if (!strcmp(entry.d_name, "self")) +- continue; +- +- if (!isdigit(*entry.d_name)) +- continue; +- +- pid = atoi(entry.d_name); +- if (pid == getpid()) +- continue; +- +- path_len = sprintf(path, "/proc/%s/cmdline", entry.d_name); +- if (path_len >= PATH_MAX) { +- fprintf(stderr, +- "buffer to small for /proc path\n"); +- return -1; +- } +- path[path_len] = '\0'; +- +- fp = fopen(path, "r"); +- if (fp) { +- int c, len = 0; +- +- while (len < 127 && (c = fgetc(fp)) != EOF && c) +- buf[len++] = c; +- buf[len] = '\0'; +- +- if (strstr(buf, "automount")) +- return pid; +- fclose(fp); +- } +- } +- closedir(dir); +- +- return 0; +-} +- + static void usage(void) + { + fprintf(stderr, +@@ -1973,11 +1930,6 @@ int main(int argc, char *argv[]) + exit(exit_code); + } + +- if (daemon_check && is_automount_running() > 0) { +- fprintf(stderr, "%s: program is already running.\n", +- program); +- exit(1); +- } + #if 0 + if (!load_autofs4_module()) { + fprintf(stderr, "%s: can't load %s filesystem module.\n", +@@ -2009,7 +1961,7 @@ int main(int argc, char *argv[]) + "can't increase core file limit - continuing"); + #endif + +- become_daemon(foreground); ++ become_daemon(foreground, daemon_check); + + if (argc == 0) + master_list = master_new(NULL, timeout, ghost); +@@ -2020,6 +1972,7 @@ int main(int argc, char *argv[]) + logerr("%s: can't create master map %s", + program, argv[0]); + close(start_pipefd[1]); ++ release_flag_file(); + exit(1); + } + +@@ -2027,6 +1980,7 @@ int main(int argc, char *argv[]) + logerr("%s: failed to init thread attribute struct!", + program); + close(start_pipefd[1]); ++ release_flag_file(); + exit(1); + } + +@@ -2035,6 +1989,7 @@ int main(int argc, char *argv[]) + logerr("%s: failed to set detached thread attribute!", + program); + close(start_pipefd[1]); ++ release_flag_file(); + exit(1); + } + +@@ -2044,6 +1999,7 @@ int main(int argc, char *argv[]) + logerr("%s: failed to set stack size thread attribute!", + program); + close(start_pipefd[1]); ++ release_flag_file(); + exit(1); + } + #endif +@@ -2060,6 +2016,7 @@ int main(int argc, char *argv[]) + program); + master_kill(master_list); + close(start_pipefd[1]); ++ release_flag_file(); + exit(1); + } + +@@ -2067,6 +2024,7 @@ int main(int argc, char *argv[]) + logerr("%s: failed to create alarm handler thread!", program); + master_kill(master_list); + close(start_pipefd[1]); ++ release_flag_file(); + exit(1); + } + +@@ -2074,6 +2032,7 @@ int main(int argc, char *argv[]) + logerr("%s: failed to create FSM handler thread!", program); + master_kill(master_list); + close(start_pipefd[1]); ++ release_flag_file(); + exit(1); + } + +@@ -2086,6 +2045,7 @@ int main(int argc, char *argv[]) + *pst_stat = 3; + res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat)); + close(start_pipefd[1]); ++ release_flag_file(); + exit(3); + } + +@@ -2102,6 +2062,7 @@ int main(int argc, char *argv[]) + pid_file = NULL; + } + closelog(); ++ release_flag_file(); + + #ifdef LIBXML2_WORKAROUND + if (dh) +--- /dev/null ++++ autofs-5.0.2/daemon/flag.c +@@ -0,0 +1,192 @@ ++/* ----------------------------------------------------------------------- * ++ * ++ * flag.c - autofs flag file management ++ * ++ * 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. ++ * ++ * ----------------------------------------------------------------------- */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_PIDSIZE 20 ++#define FLAG_FILE AUTOFS_FLAG_DIR "/autofs-running" ++ ++/* Flag for already existing flag file. */ ++static int we_created_flagfile = 0; ++ ++/* file descriptor of flag file */ ++static int fd = -1; ++ ++static int flag_is_owned(int fd) ++{ ++ int pid = 0, tries = 3; ++ ++ while (tries--) { ++ char pidbuf[MAX_PIDSIZE + 1]; ++ int got; ++ ++ lseek(fd, 0, SEEK_SET); ++ got = read(fd, pidbuf, MAX_PIDSIZE); ++ /* ++ * We add a terminator to the pid to verify write complete. ++ * If the write isn't finished in 300 milliseconds then it's ++ * probably a stale lock file. ++ */ ++ if (got > 0 && pidbuf[got - 1] == '\n') { ++ sscanf(pidbuf, "%d", &pid); ++ break; ++ } else { ++ struct timespec t = { 0, 100000000 }; ++ struct timespec r; ++ ++ while (nanosleep(&t, &r) == -1 && errno == EINTR) ++ memcpy(&t, &r, sizeof(struct timespec)); ++ ++ continue; ++ } ++ ++ /* Stale flagfile */ ++ if (!tries) ++ return 0; ++ } ++ ++ ++ if (pid) { ++ int ret; ++ ++ ret = kill(pid, 0); ++ /* ++ * If lock file exists but is not owned by a process ++ * we return unowned status so we can get rid of it ++ * and continue. ++ */ ++ if (ret == -1 && errno == ESRCH) ++ return 0; ++ } else { ++ /* ++ * Odd, no pid in file - so what should we do? ++ * Assume something bad happened to owner and ++ * return unowned status. ++ */ ++ return 0; ++ } ++ ++ return 1; ++} ++ ++/* Remove flag file. */ ++void release_flag_file(void) ++{ ++ if (fd > 0) { ++ close(fd); ++ fd = -1; ++ } ++ ++ if (we_created_flagfile) { ++ unlink(FLAG_FILE); ++ we_created_flagfile = 0; ++ } ++} ++ ++/* * Try to create flag file */ ++int aquire_flag_file(void) ++{ ++ char *linkf; ++ int len; ++ ++ len = strlen(FLAG_FILE) + MAX_PIDSIZE; ++ linkf = alloca(len + 1); ++ snprintf(linkf, len, "%s.%d", FLAG_FILE, getpid()); ++ ++ /* ++ * Repeat until it was us who made the link or we find the ++ * flag file already exists. If an unexpected error occurs ++ * we return 0 claiming the flag file exists which may not ++ * really be the case. ++ */ ++ while (!we_created_flagfile) { ++ int errsv, i, j; ++ ++ i = open(linkf, O_WRONLY|O_CREAT, 0); ++ if (i < 0) { ++ release_flag_file(); ++ return 0; ++ } ++ close(i); ++ ++ j = link(linkf, FLAG_FILE); ++ errsv = errno; ++ ++ (void) unlink(linkf); ++ ++ if (j < 0 && errsv != EEXIST) { ++ release_flag_file(); ++ return 0; ++ } ++ ++ fd = open(FLAG_FILE, O_RDWR); ++ if (fd < 0) { ++ /* Maybe the file was just deleted? */ ++ if (errno == ENOENT) ++ continue; ++ release_flag_file(); ++ return 0; ++ } ++ ++ if (j == 0) { ++ char pidbuf[MAX_PIDSIZE + 1]; ++ int pidlen; ++ ++ pidlen = sprintf(pidbuf, "%d\n", getpid()); ++ if (write(fd, pidbuf, pidlen) != pidlen) { ++ release_flag_file(); ++ return 0; ++ } ++ ++ we_created_flagfile = 1; ++ } else { ++ /* ++ * Someone else made the link. ++ * If the flag file is not owned by anyone clean ++ * it up and try again, otherwise return fail. ++ */ ++ if (!flag_is_owned(fd)) { ++ close(fd); ++ fd = -1; ++ unlink(FLAG_FILE); ++ continue; ++ } ++ ++ release_flag_file(); ++ return 0; ++ } ++ ++ close(fd); ++ fd = -1; ++ } ++ ++ return 1; ++} ++ diff --git a/autofs-5.0.3-expire-thread-create-cond-handling.patch b/autofs-5.0.3-expire-thread-create-cond-handling.patch new file mode 100644 index 0000000..2f01d56 --- /dev/null +++ b/autofs-5.0.3-expire-thread-create-cond-handling.patch @@ -0,0 +1,179 @@ +autofs-5.0.3 - fix incorrect pthreads condition handling for expire requests. + +From: Ian Kent + +Occassionally, when starting an expire thread we can attempt to use the +structure for parameter communication after it has been freed. This patch +resolves this issue. +--- + + daemon/direct.c | 40 +++++++++++++++++++++------------------- + daemon/indirect.c | 28 +++++++++++++++------------- + 2 files changed, 36 insertions(+), 32 deletions(-) + + +--- autofs-5.0.3.orig/daemon/direct.c ++++ autofs-5.0.3/daemon/direct.c +@@ -1033,55 +1033,53 @@ static void expire_mutex_unlock(void *ar + + static void *do_expire_direct(void *arg) + { +- struct pending_args *mt; ++ struct pending_args *args, mt; + struct autofs_point *ap; + size_t len; + int status, state; + +- mt = (struct pending_args *) arg; ++ args = (struct pending_args *) arg; + + status = pthread_mutex_lock(&ea_mutex); + if (status) + fatal(status); + +- ap = mt->ap; ++ memcpy(&mt, args, sizeof(struct pending_args)); ++ ++ ap = mt.ap; + +- mt->signaled = 1; +- status = pthread_cond_signal(&mt->cond); ++ args->signaled = 1; ++ status = pthread_cond_signal(&args->cond); + if (status) + fatal(status); + + expire_mutex_unlock(NULL); + +- pthread_cleanup_push(free_pending_args, mt); +- pthread_cleanup_push(pending_cond_destroy, mt); +- pthread_cleanup_push(expire_send_fail, mt); ++ pthread_cleanup_push(expire_send_fail, &mt); + +- len = _strlen(mt->name, KEY_MAX_LEN); ++ len = _strlen(mt.name, KEY_MAX_LEN); + if (!len) { +- warn(ap->logopt, "direct key path too long %s", mt->name); ++ warn(ap->logopt, "direct key path too long %s", mt.name); + /* TODO: force umount ?? */ + pthread_exit(NULL); + } + +- status = do_expire(ap, mt->name, len); ++ 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); ++ send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token); + else { + struct mapent *me; +- cache_readlock(mt->mc); +- me = cache_lookup_distinct(mt->mc, mt->name); ++ 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); ++ cache_unlock(mt.mc); ++ send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); ++ close(mt.ioctlfd); + } + pthread_setcancelstate(state, NULL); + + pthread_cleanup_pop(0); +- pthread_cleanup_pop(1); +- pthread_cleanup_pop(1); + + return NULL; + } +@@ -1198,6 +1196,8 @@ int handle_packet_expire_direct(struct a + cache_unlock(mc); + master_source_unlock(ap->entry); + ++ pthread_cleanup_push(free_pending_args, mt); ++ pthread_cleanup_push(pending_cond_destroy, mt); + pthread_cleanup_push(expire_mutex_unlock, NULL); + pthread_setcancelstate(state, NULL); + +@@ -1212,6 +1212,8 @@ int handle_packet_expire_direct(struct a + } + + pthread_cleanup_pop(1); ++ pthread_cleanup_pop(1); ++ pthread_cleanup_pop(1); + + return 0; + } +--- autofs-5.0.3.orig/daemon/indirect.c ++++ autofs-5.0.3/daemon/indirect.c +@@ -596,40 +596,38 @@ static void expire_mutex_unlock(void *ar + + static void *do_expire_indirect(void *arg) + { +- struct pending_args *mt; ++ struct pending_args *args, mt; + struct autofs_point *ap; + int status, state; + +- mt = (struct pending_args *) arg; ++ args = (struct pending_args *) arg; + + status = pthread_mutex_lock(&ea_mutex); + if (status) + fatal(status); + +- ap = mt->ap; ++ memcpy(&mt, args, sizeof(struct pending_args)); + +- mt->signaled = 1; +- status = pthread_cond_signal(&mt->cond); ++ ap = mt.ap; ++ ++ args->signaled = 1; ++ status = pthread_cond_signal(&args->cond); + if (status) + fatal(status); + + expire_mutex_unlock(NULL); + +- pthread_cleanup_push(free_pending_args, mt); +- pthread_cleanup_push(pending_cond_destroy, mt); +- pthread_cleanup_push(expire_send_fail, mt); ++ pthread_cleanup_push(expire_send_fail, &mt); + +- status = do_expire(mt->ap, mt->name, mt->len); ++ 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); ++ send_fail(ap->logopt, ap->ioctlfd, mt.wait_queue_token); + else +- send_ready(ap->logopt, ap->ioctlfd, mt->wait_queue_token); ++ send_ready(ap->logopt, ap->ioctlfd, mt.wait_queue_token); + pthread_setcancelstate(state, NULL); + + pthread_cleanup_pop(0); +- pthread_cleanup_pop(1); +- pthread_cleanup_pop(1); + + return NULL; + } +@@ -682,6 +680,8 @@ int handle_packet_expire_indirect(struct + return 1; + } + ++ pthread_cleanup_push(free_pending_args, mt); ++ pthread_cleanup_push(pending_cond_destroy, mt); + pthread_cleanup_push(expire_mutex_unlock, NULL); + pthread_setcancelstate(state, NULL); + +@@ -696,6 +696,8 @@ int handle_packet_expire_indirect(struct + } + + pthread_cleanup_pop(1); ++ pthread_cleanup_pop(1); ++ pthread_cleanup_pop(1); + + return 0; + } diff --git a/autofs-5.0.3-fix-couple-of-memory-leaks.patch b/autofs-5.0.3-fix-couple-of-memory-leaks.patch new file mode 100644 index 0000000..e568dc3 --- /dev/null +++ b/autofs-5.0.3-fix-couple-of-memory-leaks.patch @@ -0,0 +1,51 @@ +autofs-5.0.3 - fix a couple of memory leaks + +From: Ian Kent + + +--- + + daemon/lookup.c | 5 ++++- + modules/parse_sun.c | 14 ++++++++++---- + 2 files changed, 14 insertions(+), 5 deletions(-) + + +--- autofs-5.0.2.orig/daemon/lookup.c ++++ autofs-5.0.2/daemon/lookup.c +@@ -996,8 +996,11 @@ int lookup_prune_cache(struct autofs_poi + + key = strdup(me->key); + me = cache_enumerate(mc, me); +- if (!key || *key == '*') ++ if (!key || *key == '*') { ++ if (key) ++ free(key); + continue; ++ } + + path = make_fullpath(ap->path, key); + if (!path) { +--- autofs-5.0.2.orig/modules/parse_sun.c ++++ autofs-5.0.2/modules/parse_sun.c +@@ -462,11 +462,17 @@ static char *concat_options(char *left, + char buf[MAX_ERR_BUF]; + char *ret; + +- if (left == NULL || *left == '\0') +- return strdup(right); ++ if (left == NULL || *left == '\0') { ++ ret = strdup(right); ++ free(right); ++ return ret; ++ } + +- if (right == NULL || *right == '\0') +- return strdup(left); ++ if (right == NULL || *right == '\0') { ++ ret = strdup(left); ++ free(left); ++ return ret; ++ } + + ret = malloc(strlen(left) + strlen(right) + 2); + diff --git a/autofs-5.0.3-fix-fd-leak-at-multi-mount-fail.patch b/autofs-5.0.3-fix-fd-leak-at-multi-mount-fail.patch new file mode 100644 index 0000000..8e78948 --- /dev/null +++ b/autofs-5.0.3-fix-fd-leak-at-multi-mount-fail.patch @@ -0,0 +1,39 @@ +autofs-5.0.3 - fix fd leak at multi-mount fail + +From: Ian Kent + +Fix file handle being left open following a multi-mount non-fatal mount +fail. +--- + + daemon/direct.c | 12 ++++++++++-- + 1 files changed, 10 insertions(+), 2 deletions(-) + + +diff --git a/daemon/direct.c b/daemon/direct.c +index 13f572c..b94601a 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -1303,12 +1303,20 @@ static void *do_mount_direct(void *arg) + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + if (status) { + struct mapent *me; ++ struct statfs fs; ++ unsigned int close_fd = 0; ++ ++ if (statfs(mt.name, &fs) == -1 || ++ (fs.f_type == AUTOFS_SUPER_MAGIC && ++ !master_find_submount(ap, mt.name))) ++ close_fd = 1; + cache_writelock(mt.mc); +- me = cache_lookup_distinct(mt.mc, mt.name); +- if (me) ++ if (!close_fd && (me = cache_lookup_distinct(mt.mc, mt.name))) + me->ioctlfd = mt.ioctlfd; + send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); + cache_unlock(mt.mc); ++ if (close_fd) ++ close(mt.ioctlfd); + info(ap->logopt, "mounted %s", mt.name); + } else { + send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token); diff --git a/autofs-5.0.3-fix-get-user-info-check.patch b/autofs-5.0.3-fix-get-user-info-check.patch new file mode 100644 index 0000000..f5596c4 --- /dev/null +++ b/autofs-5.0.3-fix-get-user-info-check.patch @@ -0,0 +1,34 @@ +autofs-5.0.3 - fix incorrect if check in get user info + +From: Ian Kent + +Fix an if statement checking the wrong value in the get user info code. +--- + + daemon/direct.c | 2 +- + daemon/indirect.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + + +--- autofs-5.0.2.orig/daemon/direct.c ++++ autofs-5.0.2/daemon/direct.c +@@ -1337,7 +1337,7 @@ static void *do_mount_direct(void *arg) + } + + tsv->home = strdup(pw.pw_dir); +- if (!tsv->user) { ++ if (!tsv->home) { + error(ap->logopt, "failed to malloc buffer for home"); + free(pw_tmp); + free(tsv->user); +--- autofs-5.0.2.orig/daemon/indirect.c ++++ autofs-5.0.2/daemon/indirect.c +@@ -768,7 +768,7 @@ static void *do_mount_indirect(void *arg + } + + tsv->home = strdup(pw.pw_dir); +- if (!tsv->user) { ++ if (!tsv->home) { + error(ap->logopt, "failed to malloc buffer for home"); + free(pw_tmp); + free(tsv->user); diff --git a/autofs-5.0.3-fix-ifc-buff-size-fix-2.patch b/autofs-5.0.3-fix-ifc-buff-size-fix-2.patch new file mode 100644 index 0000000..4010c2d --- /dev/null +++ b/autofs-5.0.3-fix-ifc-buff-size-fix-2.patch @@ -0,0 +1,59 @@ +autofs-5.0.3 - fix ifc buff size fix 2 + +From: Ian Kent + +For the case of a large number of interfaces there can be +a lot of malloc(3)s for every mount which could slow things +down. So we remember the maximum allocation size and use it +in subsequent allocations. +--- + + modules/replicated.c | 12 ++++++++++-- + 1 files changed, 10 insertions(+), 2 deletions(-) + + +diff --git a/modules/replicated.c b/modules/replicated.c +index 35a6675..b435f4b 100644 +--- a/modules/replicated.c ++++ b/modules/replicated.c +@@ -62,7 +62,10 @@ + #ifndef MAX_ERR_BUF + #define MAX_ERR_BUF 512 + #endif ++ + #define MAX_IFC_BUF 2048 ++static int volatile ifc_buf_len = MAX_IFC_BUF; ++static int volatile ifc_last_len = 0; + + #define MASK_A 0x7F000000 + #define MASK_B 0xBFFF0000 +@@ -97,7 +100,7 @@ void seed_random(void) + + static int alloc_ifreq(struct ifconf *ifc, int sock) + { +- int ret, lastlen = 0, len = MAX_IFC_BUF; ++ int ret, lastlen = ifc_last_len, len = ifc_buf_len; + char err_buf[MAX_ERR_BUF], *buf; + + while (1) { +@@ -119,7 +122,7 @@ static int alloc_ifreq(struct ifconf *ifc, int sock) + return 0; + } + +- if (ifc->ifc_len == lastlen) ++ if (ifc->ifc_len <= lastlen) + break; + + lastlen = ifc->ifc_len; +@@ -127,6 +130,11 @@ static int alloc_ifreq(struct ifconf *ifc, int sock) + free(buf); + } + ++ if (lastlen != ifc_last_len) { ++ ifc_last_len = lastlen; ++ ifc_buf_len = len; ++ } ++ + return 1; + } + diff --git a/autofs-5.0.3-fix-ifc-buff-size.patch b/autofs-5.0.3-fix-ifc-buff-size.patch new file mode 100644 index 0000000..1e41621 --- /dev/null +++ b/autofs-5.0.3-fix-ifc-buff-size.patch @@ -0,0 +1,129 @@ +autofs-5.0.3 - fix interface config buffer size + +From: Ian Kent + +When getting the interface configuration information autofs uses a +fixed size buffer for the interface information. If there are many +interfaces this causes the check to fail. +--- + + modules/replicated.c | 51 +++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 43 insertions(+), 8 deletions(-) + + +--- autofs-5.0.2.orig/modules/replicated.c ++++ autofs-5.0.2/modules/replicated.c +@@ -95,6 +95,41 @@ void seed_random(void) + return; + } + ++static int alloc_ifreq(struct ifconf *ifc, int sock) ++{ ++ int ret, lastlen = 0, len = MAX_IFC_BUF; ++ char err_buf[MAX_ERR_BUF], *buf; ++ ++ while (1) { ++ buf = malloc(len); ++ if (!buf) { ++ char *estr = strerror_r(errno, err_buf, MAX_ERR_BUF); ++ logerr("malloc: %s", estr); ++ return 0; ++ } ++ ++ ifc->ifc_len = sizeof(buf); ++ ifc->ifc_req = (struct ifreq *) buf; ++ ++ ret = ioctl(sock, SIOCGIFCONF, ifc); ++ if (ret == -1) { ++ char *estr = strerror_r(errno, err_buf, MAX_ERR_BUF); ++ logerr("ioctl: %s", estr); ++ free(buf); ++ return 0; ++ } ++ ++ if (ifc->ifc_len == lastlen) ++ break; ++ ++ lastlen = ifc->ifc_len; ++ len += MAX_IFC_BUF; ++ free(buf); ++ } ++ ++ return 1; ++} ++ + static unsigned int get_proximity(const char *host_addr, int addr_len) + { + struct sockaddr_in *msk_addr, *if_addr; +@@ -122,12 +157,7 @@ static unsigned int get_proximity(const + fcntl(sock, F_SETFD, cl_flags); + } + +- ifc.ifc_len = sizeof(buf); +- ifc.ifc_req = (struct ifreq *) buf; +- ret = ioctl(sock, SIOCGIFCONF, &ifc); +- if (ret == -1) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- logerr("ioctl: %s", estr); ++ if (!alloc_ifreq(&ifc, sock)) { + close(sock); + return PROXIMITY_ERROR; + } +@@ -138,7 +168,7 @@ static unsigned int get_proximity(const + i = 0; + ptr = (char *) &ifc.ifc_buf[0]; + +- while (ptr < buf + ifc.ifc_len) { ++ while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) { + ifr = (struct ifreq *) ptr; + + switch (ifr->ifr_addr.sa_family) { +@@ -147,6 +177,7 @@ static unsigned int get_proximity(const + ret = memcmp(&if_addr->sin_addr, hst_addr, addr_len); + if (!ret) { + close(sock); ++ free(ifc.ifc_req); + return PROXIMITY_LOCAL; + } + break; +@@ -162,7 +193,7 @@ static unsigned int get_proximity(const + i = 0; + ptr = (char *) &ifc.ifc_buf[0]; + +- while (ptr < buf + ifc.ifc_len) { ++ while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) { + ifr = (struct ifreq *) ptr; + + switch (ifr->ifr_addr.sa_family) { +@@ -178,6 +209,7 @@ static unsigned int get_proximity(const + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + logerr("ioctl: %s", estr); + close(sock); ++ free(ifc.ifc_req); + return PROXIMITY_ERROR; + } + +@@ -186,6 +218,7 @@ static unsigned int get_proximity(const + + if ((ia & mask) == (ha & mask)) { + close(sock); ++ free(ifc.ifc_req); + return PROXIMITY_SUBNET; + } + +@@ -208,6 +241,7 @@ static unsigned int get_proximity(const + + if ((ia & mask) == (ha & mask)) { + close(sock); ++ free(ifc.ifc_req); + return PROXIMITY_NET; + } + break; +@@ -221,6 +255,7 @@ static unsigned int get_proximity(const + } + + close(sock); ++ free(ifc.ifc_req); + + return PROXIMITY_OTHER; + } diff --git a/autofs-5.0.3-fix-included-browse-map-not-found.patch b/autofs-5.0.3-fix-included-browse-map-not-found.patch new file mode 100644 index 0000000..a854566 --- /dev/null +++ b/autofs-5.0.3-fix-included-browse-map-not-found.patch @@ -0,0 +1,26 @@ +autofs-5.0.3 - fix fail on included browse map not found + +From: Ian Kent + +When looking up nsswitch sources, if nsswitch action check tells us +to continue we need to set the returned result to success so we +don't return a false failure. +--- + + daemon/lookup.c | 2 ++ + 1 files changed, 2 insertions(+), 0 deletions(-) + + +diff --git a/daemon/lookup.c b/daemon/lookup.c +index 29a1491..3c22a35 100644 +--- a/daemon/lookup.c ++++ b/daemon/lookup.c +@@ -545,6 +545,8 @@ int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time + map = NULL; + break; + } ++ ++ result = NSS_STATUS_SUCCESS; + } + pthread_cleanup_pop(1); + diff --git a/autofs-5.0.3-fix-incorrect-multi-mount-mountpoint.patch b/autofs-5.0.3-fix-incorrect-multi-mount-mountpoint.patch new file mode 100644 index 0000000..89ae77b --- /dev/null +++ b/autofs-5.0.3-fix-incorrect-multi-mount-mountpoint.patch @@ -0,0 +1,32 @@ +autofs-5.0.3 - fix incorrect multi-mount mountpoint + +From: Ian Kent + +Fix case where an incorrect mount point path was being used when +mounting a multi-mount component. +--- + + modules/parse_sun.c | 8 +++++++- + 1 files changed, 7 insertions(+), 1 deletions(-) + + +diff --git a/modules/parse_sun.c b/modules/parse_sun.c +index 333f8a5..5a39113 100644 +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -1248,8 +1248,14 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me, + return 1; + } + } else if (rv < 0) { ++ char *mm_root_base = alloca(strlen(mm_root) + strlen(mm_base) + 1); ++ + move = MOUNT_MOVE_NONE; +- ret = mount_multi_triggers(ap, me->multi, mm_root, start, mm_base); ++ ++ strcpy(mm_root_base, mm_root); ++ strcat(mm_root_base, mm_base); ++ ++ ret = mount_multi_triggers(ap, me->multi, mm_root_base, start, mm_base); + if (ret == -1) { + error(ap->logopt, MODPREFIX + "failed to mount offset triggers"); diff --git a/autofs-5.0.3-fix-multi-mount-race.patch b/autofs-5.0.3-fix-multi-mount-race.patch new file mode 100644 index 0000000..958e355 --- /dev/null +++ b/autofs-5.0.3-fix-multi-mount-race.patch @@ -0,0 +1,1593 @@ +autofs-5.0.3 - fix multi mount race. + +From: Ian Kent + +When using multi-mounts it is possible for a path walk to walk into +a mount tree before it is completely setup which leads to autofs +incorrectly failing to perform mounts. + +For example, for the multi-mount + +mm1 + /om1 :/ + /om2 :/ + /om2/om21 :/ + /om2/om22 :/ + +when a path walk hits mm1/om2 :/ is mounted on top of +mm1/om2. If a path walk comes along before the multi-mount offsets for +mm1/om2 are setup it doesn't see that mm1/om2 is pending. This happens +because the lookup gets to mm1/om2, which is within the mm1 file system, +and is covered by a mount trigger mounted at mm1/om2, and the the trigger +itself is covered by the :/ mount. So the walk follows +the stack up to the mount at :/, never seeing that the +trigger mm1/om2 is currently pending. + +In the example above mm1/om2 could also be a submount. + +To resolve this the mount tree needs to be created under a temporary +directory and moved into place once setup in one operation. +--- + + daemon/automount.c | 32 ++- + daemon/direct.c | 40 ++-- + daemon/indirect.c | 55 +++--- + daemon/lookup.c | 6 + daemon/state.c | 2 + include/automount.h | 12 - + include/master.h | 1 + include/mounts.h | 4 + lib/master.c | 20 +- + lib/mounts.c | 21 +- + modules/mount_autofs.c | 61 +++---- + modules/mount_bind.c | 43 +--- + modules/mount_changer.c | 34 +-- + modules/mount_ext2.c | 40 +--- + modules/mount_generic.c | 40 +--- + modules/mount_nfs.c | 41 +--- + modules/parse_sun.c | 414 ++++++++++++++++++++++++++++++++++++------------ + 17 files changed, 519 insertions(+), 347 deletions(-) + + +--- autofs-5.0.2.orig/daemon/automount.c ++++ autofs-5.0.2/daemon/automount.c +@@ -489,7 +489,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); +- if (umount_multi_triggers(ap, root, me, base)) { ++ if (umount_multi_triggers(ap, me, root, base)) { + warn(ap->logopt, + "some offset mounts still present under %s", path); + left++; +@@ -572,7 +572,7 @@ static int umount_all(struct autofs_poin + return left; + } + +-int umount_autofs(struct autofs_point *ap, int force) ++int umount_autofs(struct autofs_point *ap, const char *root, int force) + { + int ret = 0; + +@@ -589,7 +589,7 @@ int umount_autofs(struct autofs_point *a + if (ap->type == LKP_INDIRECT) { + if (umount_all(ap, force) && !force) + return -1; +- ret = umount_autofs_indirect(ap); ++ ret = umount_autofs_indirect(ap, root); + } else + ret = umount_autofs_direct(ap); + +@@ -754,7 +754,7 @@ out_free: + return ret; + } + +-static int destroy_logpri_fifo(struct autofs_point *ap) ++int destroy_logpri_fifo(struct autofs_point *ap) + { + int ret = -1; + int fd = ap->logpri_fifo; +@@ -1056,7 +1056,7 @@ static int autofs_init_ap(struct autofs_ + return 0; + } + +-static int mount_autofs(struct autofs_point *ap) ++static int mount_autofs(struct autofs_point *ap, const char *root) + { + int status = 0; + +@@ -1066,7 +1066,7 @@ static int mount_autofs(struct autofs_po + if (ap->type == LKP_DIRECT) + status = mount_autofs_direct(ap); + else +- status = mount_autofs_indirect(ap); ++ status = mount_autofs_indirect(ap, root); + + if (status < 0) + return -1; +@@ -1531,10 +1531,12 @@ void *handle_mounts(void *arg) + struct startup_cond *suc; + struct autofs_point *ap; + int cancel_state, status = 0; ++ char *root; + + suc = (struct startup_cond *) arg; + + ap = suc->ap; ++ root = strdup(suc->root); + + pthread_cleanup_push(return_start_status, suc); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); +@@ -1545,14 +1547,24 @@ void *handle_mounts(void *arg) + fatal(status); + } + +- if (mount_autofs(ap) < 0) { ++ if (!root) { ++ crit(ap->logopt, "failed to alloc string root"); ++ suc->status = 1; ++ pthread_setcancelstate(cancel_state, NULL); ++ pthread_exit(NULL); ++ } ++ ++ if (mount_autofs(ap, root) < 0) { + crit(ap->logopt, "mount of %s failed!", ap->path); + suc->status = 1; +- umount_autofs(ap, 1); ++ umount_autofs(ap, root, 1); ++ free(root); + pthread_setcancelstate(cancel_state, NULL); + pthread_exit(NULL); + } + ++ free(root); ++ + if (ap->ghost && ap->type != LKP_DIRECT) + info(ap->logopt, "ghosting enabled"); + +@@ -1615,7 +1627,7 @@ void *handle_mounts(void *arg) + * to check for possible recovery. + */ + if (ap->type == LKP_DIRECT) { +- umount_autofs(ap, 1); ++ umount_autofs(ap, NULL, 1); + break; + } + +@@ -1625,7 +1637,7 @@ void *handle_mounts(void *arg) + * so we can continue. This can happen if a lookup + * occurs while we're trying to umount. + */ +- ret = umount_autofs(ap, 1); ++ ret = umount_autofs(ap, NULL, 1); + if (!ret) + break; + +--- autofs-5.0.2.orig/daemon/direct.c ++++ autofs-5.0.2/daemon/direct.c +@@ -646,7 +646,7 @@ force_umount: + return rv; + } + +-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me) ++int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset) + { + char buf[MAX_ERR_BUF]; + struct mnt_params *mp; +@@ -654,6 +654,7 @@ int mount_autofs_offset(struct autofs_po + struct stat st; + int ioctlfd, cl_flags, status, ret; + const char *type, *map_name = NULL; ++ char mountpoint[PATH_MAX]; + + if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) { + if (ap->state != ST_READMAP) +@@ -695,8 +696,11 @@ int mount_autofs_offset(struct autofs_po + return MOUNT_OFFSET_OK; + } + ++ strcpy(mountpoint, root); ++ strcat(mountpoint, offset); ++ + /* In case the directory doesn't exist, try to mkdir it */ +- if (mkdir_path(me->key, 0555) < 0) { ++ if (mkdir_path(mountpoint, 0555) < 0) { + if (errno == EEXIST) { + /* + * If the mount point directory is a real mount +@@ -705,7 +709,7 @@ int mount_autofs_offset(struct autofs_po + * the kernel NFS client. + */ + if (me->multi != me && +- is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL)) ++ is_mounted(_PATH_MOUNTED, mountpoint, MNTS_REAL)) + return MOUNT_OFFSET_IGNORE; + + /* +@@ -725,13 +729,13 @@ int mount_autofs_offset(struct autofs_po + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + debug(ap->logopt, + "can't create mount directory: %s, %s", +- me->key, estr); ++ mountpoint, estr); + return MOUNT_OFFSET_FAIL; + } else { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + crit(ap->logopt, + "failed to create mount directory: %s, %s", +- me->key, estr); ++ mountpoint, estr); + return MOUNT_OFFSET_FAIL; + } + } else { +@@ -741,7 +745,7 @@ int mount_autofs_offset(struct autofs_po + + debug(ap->logopt, + "calling mount -t autofs " SLOPPY " -o %s automount %s", +- mp->options, me->key); ++ mp->options, mountpoint); + + type = ap->entry->maps->type; + if (type && !strcmp(ap->entry->maps->type, "hosts")) { +@@ -753,22 +757,18 @@ int mount_autofs_offset(struct autofs_po + } else + map_name = me->mc->map->argv[0]; + +- ret = mount(map_name, me->key, "autofs", MS_MGC_VAL, mp->options); ++ ret = mount(map_name, mountpoint, "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); ++ "failed to mount offset trigger %s at %s", ++ me->key, mountpoint); + goto out_err; + } + + /* Root directory for ioctl()'s */ +- ioctlfd = open(me->key, O_RDONLY); ++ ioctlfd = open(mountpoint, O_RDONLY); + if (ioctlfd < 0) { +- crit(ap->logopt, "failed to create ioctl fd for %s", me->key); ++ crit(ap->logopt, "failed to create ioctl fd for %s", mountpoint); + goto out_umount; + } + +@@ -782,7 +782,7 @@ int mount_autofs_offset(struct autofs_po + ret = fstat(ioctlfd, &st); + if (ret == -1) { + error(ap->logopt, +- "failed to stat direct mount trigger %s", me->key); ++ "failed to stat direct mount trigger %s", mountpoint); + goto out_close; + } + +@@ -790,17 +790,17 @@ int mount_autofs_offset(struct autofs_po + + close(ioctlfd); + +- debug(ap->logopt, "mounted trigger %s", me->key); ++ debug(ap->logopt, "mounted trigger %s at %s", me->key, mountpoint); + + return MOUNT_OFFSET_OK; + + out_close: + close(ioctlfd); + out_umount: +- umount(me->key); ++ umount(mountpoint); + out_err: +- if (stat(me->key, &st) == 0 && me->dir_created) +- rmdir_path(ap, me->key, st.st_dev); ++ if (stat(mountpoint, &st) == 0 && me->dir_created) ++ rmdir_path(ap, mountpoint, st.st_dev); + + return MOUNT_OFFSET_FAIL; + } +--- autofs-5.0.2.orig/daemon/indirect.c ++++ autofs-5.0.2/daemon/indirect.c +@@ -83,7 +83,7 @@ static int unlink_mount_tree(struct auto + return ret; + } + +-static int do_mount_autofs_indirect(struct autofs_point *ap) ++static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root) + { + time_t timeout = ap->exp_timeout; + char *options = NULL; +@@ -109,11 +109,11 @@ static int do_mount_autofs_indirect(stru + goto out_err; + + /* In case the directory doesn't exist, try to mkdir it */ +- if (mkdir_path(ap->path, 0555) < 0) { ++ if (mkdir_path(root, 0555) < 0) { + if (errno != EEXIST && errno != EROFS) { + crit(ap->logopt, + "failed to create autofs directory %s", +- ap->path); ++ root); + goto out_err; + } + /* If we recieve an error, and it's EEXIST or EROFS we know +@@ -134,9 +134,10 @@ static int do_mount_autofs_indirect(stru + } else + map_name = ap->entry->maps->argv[0]; + +- ret = mount(map_name, ap->path, "autofs", MS_MGC_VAL, options); ++ ret = mount(map_name, root, "autofs", MS_MGC_VAL, options); + if (ret) { +- crit(ap->logopt, "failed to mount autofs path %s", ap->path); ++ crit(ap->logopt, ++ "failed to mount autofs path %s at %s", ap->path, root); + goto out_rmdir; + } + +@@ -145,7 +146,7 @@ static int do_mount_autofs_indirect(stru + options = NULL; + + /* Root directory for ioctl()'s */ +- ap->ioctlfd = open(ap->path, O_RDONLY); ++ ap->ioctlfd = open(root, O_RDONLY); + if (ap->ioctlfd < 0) { + crit(ap->logopt, + "failed to create ioctl fd for autofs path %s", ap->path); +@@ -163,13 +164,13 @@ static int do_mount_autofs_indirect(stru + + if (ap->exp_timeout) + info(ap->logopt, +- "mounted indirect mount on %s " ++ "mounted indirect mount for %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", ++ "mounted indirect mount for %s with timeouts disabled", + ap->path); + + fstat(ap->ioctlfd, &st); +@@ -178,10 +179,10 @@ static int do_mount_autofs_indirect(stru + return 0; + + out_umount: +- umount(ap->path); ++ umount(root); + out_rmdir: + if (ap->dir_created) +- rmdir_path(ap, ap->path, ap->dev); ++ rmdir(root); + out_err: + if (options) + free(options); +@@ -193,7 +194,7 @@ out_err: + return -1; + } + +-int mount_autofs_indirect(struct autofs_point *ap) ++int mount_autofs_indirect(struct autofs_point *ap, const char *root) + { + time_t now = time(NULL); + int status; +@@ -207,11 +208,11 @@ int mount_autofs_indirect(struct autofs_ + return -1; + } + +- status = do_mount_autofs_indirect(ap); ++ status = do_mount_autofs_indirect(ap, root); + if (status < 0) + return -1; + +- map = lookup_ghost(ap); ++ map = lookup_ghost(ap, root); + if (map & LKP_FAIL) { + if (map & LKP_DIRECT) { + error(ap->logopt, +@@ -230,7 +231,7 @@ int mount_autofs_indirect(struct autofs_ + return 0; + } + +-static void close_mount_fds(struct autofs_point *ap) ++void close_mount_fds(struct autofs_point *ap) + { + /* + * Since submounts look after themselves the parent never knows +@@ -255,11 +256,17 @@ static void close_mount_fds(struct autof + return; + } + +-int umount_autofs_indirect(struct autofs_point *ap) ++int umount_autofs_indirect(struct autofs_point *ap, const char *root) + { + char buf[MAX_ERR_BUF]; ++ char mountpoint[PATH_MAX + 1]; + int ret, rv, retries; + ++ if (root) ++ strcpy(mountpoint, root); ++ else ++ strcpy(mountpoint, ap->path); ++ + /* If we are trying to shutdown make sure we can umount */ + rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret); + if (rv == -1) { +@@ -284,7 +291,7 @@ int umount_autofs_indirect(struct autofs + sched_yield(); + + retries = UMOUNT_RETRIES; +- while ((rv = umount(ap->path)) == -1 && retries--) { ++ while ((rv = umount(mountpoint)) == -1 && retries--) { + struct timespec tm = {0, 200000000}; + if (errno != EBUSY) + break; +@@ -296,13 +303,13 @@ int umount_autofs_indirect(struct autofs + case ENOENT: + case EINVAL: + error(ap->logopt, +- "mount point %s does not exist", ap->path); ++ "mount point %s does not exist", mountpoint); + close_mount_fds(ap); + return 0; + break; + case EBUSY: + debug(ap->logopt, +- "mount point %s is in use", ap->path); ++ "mount point %s is in use", mountpoint); + if (ap->state == ST_SHUTDOWN_FORCE) { + close_mount_fds(ap); + goto force_umount; +@@ -321,11 +328,11 @@ int umount_autofs_indirect(struct autofs + return 0; + } + #endif +- ap->ioctlfd = open(ap->path, O_RDONLY); ++ ap->ioctlfd = open(mountpoint, O_RDONLY); + if (ap->ioctlfd < 0) { + warn(ap->logopt, + "could not recover autofs path %s", +- ap->path); ++ mountpoint); + close_mount_fds(ap); + return 0; + } +@@ -355,12 +362,12 @@ int umount_autofs_indirect(struct autofs + force_umount: + if (rv != 0) { + warn(ap->logopt, +- "forcing umount of indirect mount %s", ap->path); +- rv = umount2(ap->path, MNT_DETACH); ++ "forcing umount of indirect mount %s", mountpoint); ++ rv = umount2(mountpoint, MNT_DETACH); + } else { +- info(ap->logopt, "umounted indirect mount %s", ap->path); ++ info(ap->logopt, "umounted indirect mount %s", mountpoint); + if (ap->submount) +- rm_unwanted(ap->logopt, ap->path, 1, ap->dev); ++ rm_unwanted(ap->logopt, mountpoint, 1, ap->dev); + } + + return rv; +--- autofs-5.0.2.orig/daemon/lookup.c ++++ autofs-5.0.2/daemon/lookup.c +@@ -565,7 +565,7 @@ int lookup_nss_read_map(struct autofs_po + return 0; + } + +-int lookup_ghost(struct autofs_point *ap) ++int lookup_ghost(struct autofs_point *ap, const char *root) + { + struct master_mapent *entry = ap->entry; + struct map_source *map; +@@ -611,12 +611,12 @@ int lookup_ghost(struct autofs_point *ap + goto next; + } + +- fullpath = alloca(strlen(me->key) + strlen(ap->path) + 3); ++ fullpath = alloca(strlen(me->key) + strlen(root) + 3); + if (!fullpath) { + warn(ap->logopt, "failed to allocate full path"); + goto next; + } +- sprintf(fullpath, "%s/%s", ap->path, me->key); ++ sprintf(fullpath, "%s/%s", root, me->key); + + ret = stat(fullpath, &st); + if (ret == -1 && errno != ENOENT) { +--- autofs-5.0.2.orig/daemon/state.c ++++ autofs-5.0.2/daemon/state.c +@@ -393,7 +393,7 @@ static void *do_readmap(void *arg) + + if (ap->type == LKP_INDIRECT) { + lookup_prune_cache(ap, now); +- status = lookup_ghost(ap); ++ status = lookup_ghost(ap, ap->path); + } else { + struct mapent *me, *ne, *nested; + mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/"); +--- autofs-5.0.2.orig/include/automount.h ++++ autofs-5.0.2/include/automount.h +@@ -230,7 +230,7 @@ int lookup_nss_read_master(struct master + int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time_t age); + int lookup_enumerate(struct autofs_point *ap, + int (*fn)(struct autofs_point *,struct mapent *, int), time_t now); +-int lookup_ghost(struct autofs_point *ap); ++int lookup_ghost(struct autofs_point *ap, const char *root); + int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len); + void lookup_close_lookup(struct autofs_point *ap); + int lookup_prune_cache(struct autofs_point *ap, time_t age); +@@ -332,6 +332,7 @@ struct startup_cond { + pthread_mutex_t mutex; + pthread_cond_t cond; + struct autofs_point *ap; ++ char *root; + unsigned int done; + unsigned int status; + }; +@@ -427,12 +428,13 @@ int do_expire(struct autofs_point *ap, c + void *expire_proc_indirect(void *); + void *expire_proc_direct(void *); + int expire_offsets_direct(struct autofs_point *ap, struct mapent *me, int now); +-int mount_autofs_indirect(struct autofs_point *ap); ++int mount_autofs_indirect(struct autofs_point *ap, const char *root); + int mount_autofs_direct(struct autofs_point *ap); +-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me); ++int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset); + void submount_signal_parent(struct autofs_point *ap, unsigned int success); +-int umount_autofs(struct autofs_point *ap, int force); +-int umount_autofs_indirect(struct autofs_point *ap); ++void close_mount_fds(struct autofs_point *ap); ++int umount_autofs(struct autofs_point *ap, const char *root, int force); ++int umount_autofs_indirect(struct autofs_point *ap, const char *root); + int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me); + int umount_autofs_direct(struct autofs_point *ap); + int umount_autofs_offset(struct autofs_point *ap, struct mapent *me); +--- autofs-5.0.2.orig/include/master.h ++++ autofs-5.0.2/include/master.h +@@ -91,6 +91,7 @@ void master_source_lock_cleanup(void *); + void master_source_current_wait(struct master_mapent *); + void master_source_current_signal(struct master_mapent *); + struct master_mapent *master_find_mapent(struct master *, const char *); ++struct autofs_point *__master_find_submount(struct autofs_point *, const char *); + struct autofs_point *master_find_submount(struct autofs_point *, const char *); + struct master_mapent *master_new_mapent(struct master *, const char *, time_t); + void master_add_mapent(struct master *, struct master_mapent *); +--- autofs-5.0.2.orig/include/mounts.h ++++ autofs-5.0.2/include/mounts.h +@@ -85,7 +85,7 @@ int tree_find_mnt_ents(struct mnt_list * + int tree_is_mounted(struct mnt_list *mnts, const char *path, unsigned int type); + void set_tsd_user_vars(unsigned int, uid_t, gid_t); + 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 *); ++int mount_multi_triggers(struct autofs_point *, struct mapent *, const char *, unsigned int, const char *); ++int umount_multi_triggers(struct autofs_point *, struct mapent *, char *, const char *); + + #endif +--- autofs-5.0.2.orig/lib/master.c ++++ autofs-5.0.2/lib/master.c +@@ -602,27 +602,32 @@ struct master_mapent *master_find_mapent + return NULL; + } + +-struct autofs_point *master_find_submount(struct autofs_point *ap, const char *path) ++struct autofs_point *__master_find_submount(struct autofs_point *ap, const char *path) + { + struct list_head *head, *p; + +- mounts_mutex_lock(ap); +- + head = &ap->submounts; + list_for_each(p, head) { + struct autofs_point *submount; + + submount = list_entry(p, struct autofs_point, mounts); + +- if (!strcmp(submount->path, path)) { +- mounts_mutex_unlock(ap); ++ if (!strcmp(submount->path, path)) + return submount; +- } + } + ++ return NULL; ++} ++ ++struct autofs_point *master_find_submount(struct autofs_point *ap, const char *path) ++{ ++ struct autofs_point *submount; ++ ++ mounts_mutex_lock(ap); ++ submount = __master_find_submount(ap, path); + mounts_mutex_unlock(ap); + +- return NULL; ++ return submount; + } + + struct master_mapent *master_new_mapent(struct master *master, const char *path, time_t age) +@@ -955,6 +960,7 @@ static int master_do_mount(struct master + } + + suc.ap = ap; ++ suc.root = ap->path; + suc.done = 0; + suc.status = 0; + +--- autofs-5.0.2.orig/lib/mounts.c ++++ autofs-5.0.2/lib/mounts.c +@@ -1105,7 +1105,8 @@ int umount_ent(struct autofs_point *ap, + return rv; + } + +-int mount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) ++int mount_multi_triggers(struct autofs_point *ap, struct mapent *me, ++ const char *root, unsigned int start, const char *base) + { + char path[PATH_MAX + 1]; + char *offset = path; +@@ -1113,17 +1114,13 @@ int mount_multi_triggers(struct autofs_p + struct list_head *pos = NULL; + unsigned int fs_path_len; + unsigned int mounted; +- int ret, start; ++ int ret; + +- fs_path_len = strlen(root) + strlen(base); ++ fs_path_len = start + 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); +@@ -1137,9 +1134,9 @@ int mount_multi_triggers(struct autofs_p + if (!oe || !oe->mapent) + goto cont; + +- debug(ap->logopt, "mount offset %s", oe->key); ++ debug(ap->logopt, "mount offset %s at %s", oe->key, root); + +- ret = mount_autofs_offset(ap, oe); ++ ret = mount_autofs_offset(ap, oe, root, offset); + if (ret >= MOUNT_OFFSET_OK) + mounted++; + else { +@@ -1161,7 +1158,7 @@ cont: + return mounted; + } + +-int umount_multi_triggers(struct autofs_point *ap, char *root, struct mapent *me, const char *base) ++int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root, const char *base) + { + char path[PATH_MAX + 1]; + char *offset; +@@ -1198,7 +1195,7 @@ int umount_multi_triggers(struct autofs_ + * nonstrict mount fail. + */ + oe_base = oe->key + strlen(root); +- left += umount_multi_triggers(ap, root, oe, oe_base); ++ left += umount_multi_triggers(ap, oe, root, oe_base); + + if (oe->ioctlfd != -1) + left++; +@@ -1238,7 +1235,7 @@ int umount_multi_triggers(struct autofs_ + 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, "/") < 0) ++ if (mount_multi_triggers(ap, me, root, strlen(root), "/") < 0) + warn(ap->logopt, + "failed to remount offset triggers"); + return left++; +--- autofs-5.0.2.orig/modules/mount_autofs.c ++++ autofs-5.0.2/modules/mount_autofs.c +@@ -48,7 +48,7 @@ int mount_mount(struct autofs_point *ap, + { + struct startup_cond suc; + pthread_t thid; +- char *fullpath; ++ char *realpath, *mountpoint; + const char **argv; + int argc, status, ghost = ap->ghost; + time_t timeout = ap->exp_timeout; +@@ -60,32 +60,32 @@ int mount_mount(struct autofs_point *ap, + struct autofs_point *nap; + char buf[MAX_ERR_BUF]; + char *options, *p; +- int ret; +- +- fullpath = alloca(strlen(root) + name_len + 2); +- if (!fullpath) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- logerr(MODPREFIX "alloca: %s", estr); +- return 1; +- } ++ int len, ret; + + /* Root offset of multi-mount */ +- if (*name == '/' && name_len == 1) +- strcpy(fullpath, root); +- else if (*name == '/') +- strcpy(fullpath, name); +- else { +- strcpy(fullpath, root); +- strcat(fullpath, "/"); +- strcat(fullpath, name); +- } +- +- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { +- error(ap->logopt, +- MODPREFIX +- "warning: about to mount over %s, continuing", +- fullpath); +- return 0; ++ len = strlen(root); ++ if (root[len - 1] == '/') { ++ realpath = alloca(strlen(ap->path) + name_len + 2); ++ mountpoint = alloca(len + 1); ++ strcpy(realpath, ap->path); ++ strcat(realpath, "/"); ++ strcat(realpath, name); ++ len--; ++ strncpy(mountpoint, root, len); ++ mountpoint[len] = '\0'; ++ } else if (*name == '/') { ++ realpath = alloca(name_len + 1); ++ mountpoint = alloca(len + 1); ++ strcpy(mountpoint, root); ++ strcpy(realpath, name); ++ } else { ++ realpath = alloca(len + name_len + 2); ++ mountpoint = alloca(len + name_len + 2); ++ strcpy(mountpoint, root); ++ strcat(mountpoint, "/"); ++ strcpy(realpath, mountpoint); ++ strcat(mountpoint, name); ++ strcat(realpath, name); + } + + options = NULL; +@@ -136,12 +136,12 @@ int mount_mount(struct autofs_point *ap, + } + + debug(ap->logopt, +- MODPREFIX "fullpath=%s what=%s options=%s", +- fullpath, what, options); ++ MODPREFIX "mountpoint=%s what=%s options=%s", ++ mountpoint, what, options); + + master = ap->entry->master; + +- entry = master_new_mapent(master, fullpath, ap->entry->age); ++ entry = master_new_mapent(master, realpath, ap->entry->age); + if (!entry) { + error(ap->logopt, + MODPREFIX "failed to malloc master_mapent struct"); +@@ -228,6 +228,7 @@ int mount_mount(struct autofs_point *ap, + } + + suc.ap = nap; ++ suc.root = mountpoint; + suc.done = 0; + suc.status = 0; + +@@ -235,7 +236,7 @@ int mount_mount(struct autofs_point *ap, + crit(ap->logopt, + MODPREFIX + "failed to create mount handler thread for %s", +- fullpath); ++ realpath); + handle_mounts_startup_cond_destroy(&suc); + mounts_mutex_unlock(ap); + master_free_map_source(source, 1); +@@ -256,7 +257,7 @@ int mount_mount(struct autofs_point *ap, + + if (suc.status) { + crit(ap->logopt, +- MODPREFIX "failed to create submount for %s", fullpath); ++ MODPREFIX "failed to create submount for %s", realpath); + handle_mounts_startup_cond_destroy(&suc); + mounts_mutex_unlock(ap); + master_free_map_source(source, 1); +--- autofs-5.0.2.orig/modules/mount_bind.c ++++ autofs-5.0.2/modules/mount_bind.c +@@ -74,34 +74,24 @@ int mount_mount(struct autofs_point *ap, + char *fullpath; + char buf[MAX_ERR_BUF]; + int err; +- int i, rlen; ++ int i, len; + + /* Root offset of multi-mount */ +- if (*name == '/' && name_len == 1) { +- rlen = strlen(root); +- name_len = 0; ++ len = strlen(root); ++ if (root[len - 1] == '/') { ++ fullpath = alloca(len); ++ len = snprintf(fullpath, len, "%s", root); + /* Direct mount name is absolute path so don't use root */ +- } else if (*name == '/') +- rlen = 0; +- else +- rlen = strlen(root); +- +- fullpath = alloca(rlen + name_len + 2); +- if (!fullpath) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- logerr(MODPREFIX "alloca: %s", estr); +- return 1; ++ } else if (*name == '/') { ++ fullpath = alloca(len + 1); ++ len = sprintf(fullpath, "%s", root); ++ } else { ++ fullpath = alloca(len + name_len + 2); ++ len = sprintf(fullpath, "%s/%s", root, name); + } ++ fullpath[len] = '\0'; + +- if (name_len) { +- if (rlen) +- sprintf(fullpath, "%s/%s", root, name); +- else +- sprintf(fullpath, "%s", name); +- } else +- sprintf(fullpath, "%s", root); +- +- i = strlen(fullpath); ++ i = len; + while (--i > 0 && fullpath[i] == '/') + fullpath[i] = '\0'; + +@@ -125,13 +115,6 @@ int mount_mount(struct autofs_point *ap, + if (!status) + existed = 0; + +- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { +- error(ap->logopt, +- MODPREFIX "warning: %s is already mounted", +- fullpath); +- return 0; +- } +- + debug(ap->logopt, + MODPREFIX + "calling mount --bind " SLOPPY " -o %s %s %s", +--- autofs-5.0.2.orig/modules/mount_changer.c ++++ autofs-5.0.2/modules/mount_changer.c +@@ -49,34 +49,24 @@ int mount_mount(struct autofs_point *ap, + char *fullpath; + char buf[MAX_ERR_BUF]; + int err; +- int rlen, status, existed = 1; ++ int len, status, existed = 1; + + fstype = "iso9660"; + + /* Root offset of multi-mount */ +- if (*name == '/' && name_len == 1) { +- rlen = strlen(root); +- name_len = 0; ++ len = strlen(root); ++ if (root[len - 1] == '/') { ++ fullpath = alloca(len); ++ len = snprintf(fullpath, len, "%s", root); + /* Direct mount name is absolute path so don't use root */ +- } else if (*name == '/') +- rlen = 0; +- else +- rlen = strlen(root); +- +- fullpath = alloca(rlen + name_len + 2); +- if (!fullpath) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- logerr(MODPREFIX "alloca: %s", estr); +- return 1; ++ } else if (*name == '/') { ++ fullpath = alloca(len + 1); ++ len = sprintf(fullpath, "%s", root); ++ } else { ++ fullpath = alloca(len + name_len + 2); ++ len = sprintf(fullpath, "%s/%s", root, name); + } +- +- if (name_len) { +- if (rlen) +- sprintf(fullpath, "%s/%s", root, name); +- else +- sprintf(fullpath, "%s", name); +- } else +- sprintf(fullpath, "%s", root); ++ fullpath[len] = '\0'; + + debug(ap->logopt, MODPREFIX "calling umount %s", what); + +--- autofs-5.0.2.orig/modules/mount_ext2.c ++++ autofs-5.0.2/modules/mount_ext2.c +@@ -43,32 +43,22 @@ int mount_mount(struct autofs_point *ap, + const char *p, *p1; + int err, ro = 0; + const char *fsck_prog; +- int rlen, status, existed = 1; ++ int len, status, existed = 1; + + /* Root offset of multi-mount */ +- if (*name == '/' && name_len == 1) { +- rlen = strlen(root); +- name_len = 0; ++ len = strlen(root); ++ if (root[len - 1] == '/') { ++ fullpath = alloca(len); ++ len = snprintf(fullpath, len, "%s", root); + /* Direct mount name is absolute path so don't use root */ +- } else if (*name == '/') +- rlen = 0; +- else +- rlen = strlen(root); +- +- fullpath = alloca(rlen + name_len + 2); +- if (!fullpath) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- logerr(MODPREFIX "alloca: %s", estr); +- return 1; ++ } else if (*name == '/') { ++ fullpath = alloca(len + 1); ++ len = sprintf(fullpath, "%s", root); ++ } else { ++ fullpath = alloca(len + name_len + 2); ++ len = sprintf(fullpath, "%s/%s", root, name); + } +- +- if (name_len) { +- if (rlen) +- sprintf(fullpath, "%s/%s", root, name); +- else +- sprintf(fullpath, "%s", name); +- } else +- sprintf(fullpath, "%s", root); ++ fullpath[len] = '\0'; + + debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath); + +@@ -83,12 +73,6 @@ int mount_mount(struct autofs_point *ap, + if (!status) + existed = 0; + +- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { +- error(ap->logopt, +- MODPREFIX "warning: %s is already mounted", fullpath); +- return 0; +- } +- + if (options && options[0]) { + for (p = options; (p1 = strchr(p, ',')); p = p1) + if (!strncmp(p, "ro", p1 - p) && ++p1 - p == sizeof("ro")) +--- autofs-5.0.2.orig/modules/mount_generic.c ++++ autofs-5.0.2/modules/mount_generic.c +@@ -42,32 +42,22 @@ int mount_mount(struct autofs_point *ap, + char *fullpath; + char buf[MAX_ERR_BUF]; + int err; +- int rlen, status, existed = 1; ++ int len, status, existed = 1; + + /* Root offset of multi-mount */ +- if (*name == '/' && name_len == 1) { +- rlen = strlen(root); +- name_len = 0; ++ len = strlen(root); ++ if (root[len - 1] == '/') { ++ fullpath = alloca(len); ++ len = snprintf(fullpath, len, "%s", root); + /* Direct mount name is absolute path so don't use root */ +- } else if (*name == '/') +- rlen = 0; +- else +- rlen = strlen(root); +- +- fullpath = alloca(rlen + name_len + 2); +- if (!fullpath) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- logerr(MODPREFIX "alloca: %s", estr); +- return 1; ++ } else if (*name == '/') { ++ fullpath = alloca(len + 1); ++ len = sprintf(fullpath, "%s", root); ++ } else { ++ fullpath = alloca(len + name_len + 2); ++ len = sprintf(fullpath, "%s/%s", root, name); + } +- +- if (name_len) { +- if (rlen) +- sprintf(fullpath, "%s/%s", root, name); +- else +- sprintf(fullpath, "%s", name); +- } else +- sprintf(fullpath, "%s", root); ++ fullpath[len] = '\0'; + + debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath); + +@@ -82,12 +72,6 @@ int mount_mount(struct autofs_point *ap, + if (!status) + existed = 0; + +- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { +- error(ap->logopt, +- MODPREFIX "warning: %s is already mounted", fullpath); +- return 0; +- } +- + if (options && options[0]) { + debug(ap->logopt, + MODPREFIX "calling mount -t %s " SLOPPY "-o %s %s %s", +--- autofs-5.0.2.orig/modules/mount_nfs.c ++++ autofs-5.0.2/modules/mount_nfs.c +@@ -64,7 +64,7 @@ int mount_mount(struct autofs_point *ap, + struct host *this, *hosts = NULL; + unsigned int vers; + char *nfsoptions = NULL; +- int len, rlen, status, err, existed = 1; ++ int len, status, err, existed = 1; + int nosymlink = 0; + int ro = 0; /* Set if mount bind should be read-only */ + +@@ -146,30 +146,18 @@ int mount_mount(struct autofs_point *ap, + /* Construct and perhaps create mount point directory */ + + /* Root offset of multi-mount */ +- if (*name == '/' && name_len == 1) { +- rlen = strlen(root); +- name_len = 0; ++ len = strlen(root); ++ if (root[len - 1] == '/') { ++ fullpath = alloca(len); ++ len = snprintf(fullpath, len, "%s", root); + /* Direct mount name is absolute path so don't use root */ +- } else if (*name == '/') +- rlen = 0; +- else +- rlen = strlen(root); +- +- fullpath = alloca(rlen + name_len + 2); +- if (!fullpath) { +- char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +- logerr(MODPREFIX "alloca: %s", estr); +- free_host_list(&hosts); +- return 1; +- } +- +- if (name_len) { +- if (rlen) +- len = sprintf(fullpath, "%s/%s", root, name); +- else +- len = sprintf(fullpath, "%s", name); +- } else ++ } else if (*name == '/') { ++ fullpath = alloca(len + 1); + len = sprintf(fullpath, "%s", root); ++ } else { ++ fullpath = alloca(len + name_len + 2); ++ len = sprintf(fullpath, "%s/%s", root, name); ++ } + fullpath[len] = '\0'; + + debug(ap->logopt, MODPREFIX "calling mkdir_path %s", fullpath); +@@ -189,13 +177,6 @@ int mount_mount(struct autofs_point *ap, + while (this) { + char *loc, *port_opt = NULL; + +- if (is_mounted(_PATH_MOUNTED, fullpath, MNTS_REAL)) { +- error(ap->logopt, +- MODPREFIX +- "warning: %s is already mounted", fullpath); +- break; +- } +- + /* + * If the "port" option is specified, then we don't want + * a bind mount. Use the "port" option if you want to +--- autofs-5.0.2.orig/modules/parse_sun.c ++++ autofs-5.0.2/modules/parse_sun.c +@@ -31,12 +31,18 @@ + #include + #include + #include ++#include ++#include + + #define MODULE_PARSE + #include "automount.h" + + #define MODPREFIX "parse(sun): " + ++#define MOUNT_MOVE_NONE 0x00 ++#define MOUNT_MOVE_AUTOFS 0x01 ++#define MOUNT_MOVE_OTHER 0x02 ++ + int parse_version = AUTOFS_PARSE_VERSION; /* Required by protocol */ + + static struct mount_mod *mount_nfs = NULL; +@@ -67,6 +73,7 @@ static struct parse_context default_cont + 1 /* Do slashify_colons */ + }; + ++int destroy_logpri_fifo(struct autofs_point *ap); + static char *concat_options(char *left, char *right); + + /* Free all storage associated with this context */ +@@ -756,8 +763,10 @@ add_offset_entry(struct autofs_point *ap + + p_len = strlen(path); + /* Trailing '/' causes us pain */ +- if (p_len > 1 && path[p_len - 1] == '/') +- p_len--; ++ if (p_len > 1) { ++ while (p_len > 1 && path[p_len - 1] == '/') ++ p_len--; ++ } + m_key_len = m_root_len + p_len; + if (m_key_len > PATH_MAX) { + error(ap->logopt, MODPREFIX "multi mount key too long"); +@@ -961,53 +970,318 @@ static int parse_mapent(const char *ent, + return (p - ent); + } + +-static int mount_subtree_offsets(struct autofs_point *ap, struct mapent_cache *mc, struct mapent *me) ++static int move_mount(struct autofs_point *ap, ++ const char *mm_tmp_root, const char *mm_root, ++ unsigned int move) + { +- struct mapent *mm; +- char *m_key; +- int ret, start; +- char *base, *m_root; + char buf[MAX_ERR_BUF]; ++ int err; + +- mm = me->multi; ++ if (move == MOUNT_MOVE_NONE) ++ return 1; ++ ++ err = mkdir_path(mm_root, 0555); ++ if (err < 0 && errno != EEXIST) { ++ error(ap->logopt, ++ "failed to create move target mount point %s", mm_root); ++ return 0; ++ } + +- if (!mm) ++ if (move == MOUNT_MOVE_AUTOFS) ++ err = mount(mm_tmp_root, mm_root, NULL, MS_MOVE, NULL); ++ else ++ err = spawn_mount(ap->logopt, ++ "--move", mm_tmp_root, mm_root, NULL); ++ if (err) { ++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF); ++ error(ap->logopt, ++ "failed to move mount from %s to %s: %s", ++ mm_tmp_root, mm_root, estr); + return 0; ++ } ++ ++ debug(ap->logopt, ++ "moved mount tree from %s to %s", mm_tmp_root, mm_root); ++ ++ return 1; ++} ++ ++static void cleanup_multi_root(struct autofs_point *ap, const char *root, ++ const char *path, unsigned int move) ++{ ++ if (move == MOUNT_MOVE_NONE) ++ return; ++ ++ if (move == MOUNT_MOVE_OTHER) ++ spawn_umount(ap->logopt, root, NULL); ++ else { ++ struct autofs_point *submount; ++ ++ mounts_mutex_lock(ap); ++ submount = __master_find_submount(ap, path); ++ if (!submount) { ++ mounts_mutex_unlock(ap); ++ return; ++ } ++ ++ alarm_delete(submount); ++ st_remove_tasks(submount); ++ st_wait_state(submount, ST_READY); ++ ++ submount->parent->submnt_count--; ++ list_del_init(&submount->mounts); ++ ++ ioctl(submount->ioctlfd, AUTOFS_IOC_CATATONIC, 0); ++ ++ mounts_mutex_unlock(ap); ++ ++ if (submount->thid) { ++ pthread_cancel(submount->thid); ++ close_mount_fds(submount); ++ umount(root); ++ destroy_logpri_fifo(submount); ++ master_free_mapent_sources(submount->entry, 1); ++ master_free_mapent(ap->entry); ++ } ++ } ++ return; ++} + +- cache_multi_lock(me->parent); ++static void cleanup_multi_triggers(struct autofs_point *ap, ++ struct mapent *me, const char *root, int start, ++ const char *base) ++{ ++ char path[PATH_MAX + 1]; ++ char offset[PATH_MAX + 1]; ++ char *poffset = offset; ++ struct mapent *oe; ++ struct list_head *mm_root, *pos; ++ const char o_root[] = "/"; ++ const char *mm_base; + +- m_key = mm->key; ++ mm_root = &me->multi->multi_list; + +- if (*m_key == '/') { +- m_root = m_key; +- start = strlen(m_key); ++ if (!base) ++ mm_base = o_root; ++ else ++ mm_base = base; ++ ++ pos = NULL; ++ ++ /* Make sure "none" of the offsets have an active mount. */ ++ while ((poffset = cache_get_offset(mm_base, poffset, start, mm_root, &pos))) { ++ oe = cache_lookup_offset(mm_base, poffset, start, &me->multi_list); ++ /* root offset is a special case */ ++ if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1) ++ continue; ++ ++ strcpy(path, root); ++ strcat(path, poffset); ++ if (umount(path)) { ++ error(ap->logopt, "error recovering from mount fail"); ++ error(ap->logopt, "cannot umount offset %s", path); ++ } ++ } ++ ++ return; ++} ++ ++static int check_fstype_autofs_option(const char *options) ++{ ++ char *tok, *tokbuf; ++ int found; ++ ++ /* ++ * Look for fstype= in options and return true if ++ * the last occurrence is fstype=autofs. ++ */ ++ found = 0; ++ tokbuf = alloca(strlen(options) + 2); ++ strcpy(tokbuf, options); ++ tok = strtok_r(tokbuf, ",", &tokbuf); ++ if (tok) { ++ do { ++ if (strstr(tok, "fstype=")) { ++ if (strstr(tok, "autofs")) ++ found = 1; ++ else ++ found = 0; ++ } ++ } while ((tok = strtok_r(NULL, ",", &tokbuf))); ++ } ++ ++ return found; ++} ++ ++static int mount_subtree(struct autofs_point *ap, struct mapent *me, ++ const char *name, char *loc, char *options, void *ctxt) ++{ ++ struct mapent *mm; ++ struct mapent *ro; ++ char t_dir[] = "/tmp/autoXXXXXX"; ++ char *mm_root, *mm_base, *mm_key; ++ const char *mm_tmp_root, *target; ++ unsigned int mm_tmp_root_len; ++ int start, ret = 0, rv; ++ unsigned int move; ++ ++ rv = 0; ++ ++ if (!me || !me->multi) { ++ int loclen = strlen(loc); ++ int namelen = strlen(name); ++ const char *root = ap->path; ++ ++ if (!strcmp(ap->path, "/-")) ++ root = name; ++ ++ rv = sun_mount(ap, root, name, namelen, loc, loclen, options, ctxt); ++ ++ goto done; ++ } ++ ++ mm = me->multi; ++ mm_key = mm->key; ++ move = MOUNT_MOVE_NONE; ++ ++ if (*mm_key == '/') { ++ mm_root = mm_key; ++ start = strlen(mm_key); + } else { +- start = strlen(ap->path) + strlen(m_key) + 1; +- m_root = alloca(start + 1); +- if (!m_root) { +- char *estr; +- cache_multi_unlock(me->parent); +- estr = strerror_r(errno, buf, MAX_ERR_BUF); +- error(ap->logopt, MODPREFIX "alloca: %s", estr); +- return -1; +- } +- strcpy(m_root, ap->path); +- strcat(m_root, "/"); +- strcat(m_root, m_key); +- } +- +- base = &me->key[start]; +- +- ret = mount_multi_triggers(ap, m_root, me->multi, base); +- if (ret == -1) { +- cache_multi_unlock(me->parent); +- error(ap->logopt, MODPREFIX "failed to mount offset triggers"); +- return -1; ++ start = strlen(ap->path) + strlen(mm_key) + 1; ++ mm_root = alloca(start + 3); ++ strcpy(mm_root, ap->path); ++ strcat(mm_root, "/"); ++ strcat(mm_root, mm_key); + } + +- cache_multi_unlock(me->parent); ++ mm_tmp_root = mkdtemp(t_dir); ++ if (!mm_tmp_root) ++ return 1; ++ mm_tmp_root_len = strlen(mm_tmp_root); ++ ++ if (me == me->multi) { ++ /* name = NULL */ ++ /* destination = mm_root */ ++ target = mm_root; ++ mm_base = "/"; + +- return ret; ++ /* Mount root offset if it exists */ ++ ro = cache_lookup_offset(mm_base, mm_base, strlen(mm_root), &me->multi_list); ++ if (ro) { ++ char *myoptions, *ro_loc, *tmp; ++ int namelen = name ? strlen(name) : 0; ++ const char *root; ++ int ro_len; ++ ++ rv = parse_mapent(ro->mapent, ++ options, &myoptions, &ro_loc, ap->logopt); ++ if (!rv) { ++ warn(ap->logopt, ++ MODPREFIX "failed to parse root offset"); ++ cache_delete_offset_list(me->mc, name); ++ rmdir(mm_tmp_root); ++ return 1; ++ } ++ ro_len = strlen(ro_loc); ++ ++ move = MOUNT_MOVE_OTHER; ++ if (check_fstype_autofs_option(myoptions)) ++ move = MOUNT_MOVE_AUTOFS; ++ ++ root = mm_tmp_root; ++ tmp = alloca(mm_tmp_root_len + 1); ++ strcpy(tmp, mm_tmp_root); ++ tmp[mm_tmp_root_len] = '/'; ++ tmp[mm_tmp_root_len + 1] = '\0'; ++ root = tmp; ++ ++ rv = sun_mount(ap, root, name, namelen, ro_loc, ro_len, myoptions, ctxt); ++ ++ free(myoptions); ++ free(ro_loc); ++ } ++ ++ if (ro && rv == 0) { ++ ret = mount_multi_triggers(ap, me, mm_tmp_root, start, mm_base); ++ if (ret == -1) { ++ error(ap->logopt, MODPREFIX ++ "failed to mount offset triggers"); ++ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base); ++ cleanup_multi_root(ap, mm_tmp_root, mm_root, move); ++ rmdir(mm_tmp_root); ++ return 1; ++ } ++ } else if (rv <= 0) { ++ move = MOUNT_MOVE_NONE; ++ ret = mount_multi_triggers(ap, me, mm_root, start, mm_base); ++ if (ret == -1) { ++ error(ap->logopt, MODPREFIX ++ "failed to mount offset triggers"); ++ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base); ++ rmdir(mm_tmp_root); ++ return 1; ++ } ++ } ++ } else { ++ int loclen = strlen(loc); ++ int namelen = strlen(name); ++ ++ move = MOUNT_MOVE_OTHER; ++ if (check_fstype_autofs_option(options)) ++ move = MOUNT_MOVE_AUTOFS; ++ ++ /* name = mm_root + mm_base */ ++ /* destination = mm_root + mm_base = name */ ++ target = name; ++ mm_base = &me->key[start]; ++ ++ rv = sun_mount(ap, mm_tmp_root, name, namelen, loc, loclen, options, ctxt); ++ if (rv == 0) { ++ ret = mount_multi_triggers(ap, me->multi, mm_tmp_root, start, mm_base); ++ if (ret == -1) { ++ error(ap->logopt, MODPREFIX ++ "failed to mount offset triggers"); ++ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base); ++ cleanup_multi_root(ap, mm_tmp_root, mm_root, move); ++ rmdir(mm_tmp_root); ++ return 1; ++ } ++ } else if (rv < 0) { ++ move = MOUNT_MOVE_NONE; ++ ret = mount_multi_triggers(ap, me->multi, mm_root, start, mm_base); ++ if (ret == -1) { ++ error(ap->logopt, MODPREFIX ++ "failed to mount offset triggers"); ++ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base); ++ rmdir(mm_tmp_root); ++ return 1; ++ } ++ } ++ } ++ ++ if (!move_mount(ap, mm_tmp_root, target, move)) { ++ cleanup_multi_triggers(ap, me, mm_tmp_root, start, mm_base); ++ cleanup_multi_root(ap, mm_tmp_root, mm_root, move); ++ rmdir(mm_tmp_root); ++ return 1; ++ } ++ ++ rmdir(mm_tmp_root); ++ ++ /* Mount for base of tree failed */ ++ if (rv > 0) ++ return rv; ++ ++done: ++ /* ++ * Convert fail on nonstrict, non-empty multi-mount ++ * to success ++ */ ++ if (rv < 0 && ret > 0) ++ rv = 0; ++ ++ return rv; + } + + /* +@@ -1029,7 +1303,7 @@ int parse_mount(struct autofs_point *ap, + char buf[MAX_ERR_BUF]; + struct map_source *source; + struct mapent_cache *mc; +- struct mapent *me, *ro; ++ struct mapent *me = NULL; + char *pmapent, *options; + const char *p; + int mapent_len, rv = 0; +@@ -1154,7 +1428,7 @@ int parse_mount(struct autofs_point *ap, + char *m_root = NULL; + int m_root_len; + time_t age = time(NULL); +- int l, ret; ++ int l; + + /* If name starts with "/" it's a direct mount */ + if (*name == '/') { +@@ -1302,48 +1576,7 @@ int parse_mount(struct autofs_point *ap, + */ + cache_set_parents(me); + +- /* Mount root offset if it exists */ +- ro = cache_lookup_offset("/", "/", strlen(m_root), &me->multi_list); +- if (ro) { +- char *myoptions, *loc; +- +- rv = parse_mapent(ro->mapent, +- options, &myoptions, &loc, ap->logopt); +- if (!rv) { +- warn(ap->logopt, +- MODPREFIX "failed to mount root offset"); +- cache_delete_offset_list(mc, name); +- cache_multi_unlock(me); +- cache_unlock(mc); +- free(options); +- pthread_setcancelstate(cur_state, NULL); +- return 1; +- } +- +- rv = sun_mount(ap, m_root, +- "/", 1, loc, strlen(loc), myoptions, ctxt); +- +- free(myoptions); +- free(loc); +- } +- +- ret = mount_multi_triggers(ap, m_root, me, "/"); +- if (ret == -1) { +- warn(ap->logopt, +- MODPREFIX "failed to mount offset triggers"); +- cache_multi_unlock(me); +- cache_unlock(mc); +- free(options); +- pthread_setcancelstate(cur_state, NULL); +- return 1; +- } +- +- /* +- * Convert fail on nonstrict, non-empty multi-mount +- * to success +- */ +- if (rv < 0 && ret > 0) +- rv = 0; ++ rv = mount_subtree(ap, me, name, NULL, options, ctxt); + + cache_multi_unlock(me); + cache_unlock(mc); +@@ -1461,24 +1694,15 @@ mount_it: + MODPREFIX "core of entry: options=%s, loc=%.*s", + options, loclen, loc); + +- rv = sun_mount(ap, ap->path, name, name_len, loc, loclen, options, ctxt); ++ cache_readlock(mc); ++ cache_multi_lock(me); ++ ++ rv = mount_subtree(ap, me, name, loc, options, ctxt); + + free(loc); + free(options); + +- /* +- * If it's a multi-mount insert the triggers +- * These are always direct mount triggers so root = "" +- */ +- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); +- cache_readlock(mc); +- me = cache_lookup_distinct(mc, name); +- if (me) { +- int 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); + cache_unlock(mc); + pthread_setcancelstate(cur_state, NULL); + } diff --git a/autofs-5.0.3-fix-multi-source-messages.patch b/autofs-5.0.3-fix-multi-source-messages.patch new file mode 100644 index 0000000..00837ff --- /dev/null +++ b/autofs-5.0.3-fix-multi-source-messages.patch @@ -0,0 +1,170 @@ +autofs-5.0.3 - fix multi source messages + +From: Ian Kent + +There are incorrect "key not found" messages seen for master map +entries that have multiple sources (direct mounts). + +For example, for the direct mount entries: + +/- auto.one +/- auto.two + +if a mount lookup is done and is not found in auto.one we see a +not found message even though it may be found in auto.two. + +This patch moves the "key not found" reporting out to the higher +level lookup and reports status at the end of the lookup. +--- + + daemon/lookup.c | 3 +++ + modules/lookup_file.c | 11 ++--------- + modules/lookup_ldap.c | 10 ++-------- + modules/lookup_nisplus.c | 12 +++--------- + modules/lookup_program.c | 2 +- + modules/lookup_yp.c | 10 ++-------- + 6 files changed, 13 insertions(+), 35 deletions(-) + + +--- autofs-5.0.2.orig/daemon/lookup.c ++++ autofs-5.0.2/daemon/lookup.c +@@ -903,6 +903,9 @@ int lookup_nss_mount(struct autofs_point + send_map_update_request(ap); + pthread_cleanup_pop(1); + ++ if (result == NSS_STATUS_NOTFOUND) ++ error(ap->logopt, "key \"%s\" not found in map.", name); ++ + return !result; + } + +--- autofs-5.0.2.orig/modules/lookup_file.c ++++ autofs-5.0.2/modules/lookup_file.c +@@ -1074,7 +1074,7 @@ int lookup_mount(struct autofs_point *ap + me = cache_lookup_distinct(mc, key); + if (me && me->status >= time(NULL)) { + cache_unlock(mc); +- return NSS_STATUS_NOTFOUND; ++ return NSS_STATUS_UNAVAIL; + } + cache_unlock(mc); + +@@ -1105,11 +1105,6 @@ int lookup_mount(struct autofs_point *ap + if (status) { + if (status == NSS_STATUS_COMPLETED) + return NSS_STATUS_SUCCESS; +- +- error(ap->logopt, +- MODPREFIX "key \"%s\" not found in map", +- name); +- + return NSS_STATUS_NOTFOUND; + } + } +@@ -1154,9 +1149,7 @@ int lookup_mount(struct autofs_point *ap + } + cache_unlock(mc); + } +- } else +- error(ap->logopt, +- MODPREFIX "key \"%s\" not found in map.", name); ++ } + + if (ret) + return NSS_STATUS_TRYAGAIN; +--- autofs-5.0.2.orig/modules/lookup_ldap.c ++++ autofs-5.0.2/modules/lookup_ldap.c +@@ -2586,12 +2586,8 @@ int lookup_mount(struct autofs_point *ap + + status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt); + free(lkp_key); +- if (status) { +- error(ap->logopt, +- MODPREFIX "key \"%s\" not found in map", +- name); ++ if (status) + return status; +- } + } + + cache_readlock(mc); +@@ -2633,9 +2629,7 @@ int lookup_mount(struct autofs_point *ap + } + cache_unlock(mc); + } +- } else +- error(ap->logopt, +- MODPREFIX "key \"%s\" not found in map", name); ++ } + + if (ret) + return NSS_STATUS_TRYAGAIN; +--- autofs-5.0.2.orig/modules/lookup_nisplus.c ++++ autofs-5.0.2/modules/lookup_nisplus.c +@@ -520,12 +520,8 @@ int lookup_mount(struct autofs_point *ap + ap->entry->current = source; + + status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt); +- if (status) { +- error(ap->logopt, +- MODPREFIX "key \"%s\" not found in map", +- name); ++ if (status) + return status; +- } + } + + cache_readlock(mc); +@@ -566,12 +562,10 @@ int lookup_mount(struct autofs_point *ap + } + cache_unlock(mc); + } +- } else +- error(ap->logopt, +- MODPREFIX "key \"%s\" not found in map", name); ++ } + + if (ret) +- return NSS_STATUS_NOTFOUND; ++ return NSS_STATUS_TRYAGAIN; + + return NSS_STATUS_SUCCESS; + } +--- autofs-5.0.2.orig/modules/lookup_program.c ++++ autofs-5.0.2/modules/lookup_program.c +@@ -390,7 +390,7 @@ out_free: + me->status = now + ap->negative_timeout; + } + cache_unlock(mc); +- return NSS_STATUS_UNAVAIL; ++ return NSS_STATUS_TRYAGAIN; + } + + return NSS_STATUS_SUCCESS; +--- autofs-5.0.2.orig/modules/lookup_yp.c ++++ autofs-5.0.2/modules/lookup_yp.c +@@ -618,12 +618,8 @@ int lookup_mount(struct autofs_point *ap + + status = check_map_indirect(ap, lkp_key, strlen(lkp_key), ctxt); + free(lkp_key); +- if (status) { +- error(ap->logopt, +- MODPREFIX "key \"%s\" not found in map", +- name); ++ if (status) + return status; +- } + } + + cache_readlock(mc); +@@ -664,9 +660,7 @@ int lookup_mount(struct autofs_point *ap + } + cache_unlock(mc); + } +- } else +- error(ap->logopt, +- MODPREFIX "key \"%s\" not found in map", name); ++ } + + if (ret) + return NSS_STATUS_TRYAGAIN; diff --git a/autofs-5.0.3-fix-nfs4-colon-escape.patch b/autofs-5.0.3-fix-nfs4-colon-escape.patch new file mode 100644 index 0000000..1bff3f4 --- /dev/null +++ b/autofs-5.0.3-fix-nfs4-colon-escape.patch @@ -0,0 +1,28 @@ +autofs-5.0.3 - fix nfs4 colon escape handling + +From: Ian Kent + +When fstype=nfs4 is given for a mount entry that should be bind +mounted because it has a ":" escaped location the colon can be +discarded before the mount module is called. This causes an +incorrect mount fail return since the replicated selection code +expects the colon to be present for parsing. +--- + + modules/parse_sun.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + + +diff --git a/modules/parse_sun.c b/modules/parse_sun.c +index b548520..333f8a5 100644 +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -638,7 +638,7 @@ static int sun_mount(struct autofs_point *ap, const char *root, + } + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); +- if (!strcmp(fstype, "nfs")) { ++ if (!strcmp(fstype, "nfs") || !strcmp(fstype, "nfs4")) { + what = alloca(loclen + 1); + memcpy(what, loc, loclen); + what[loclen] = '\0'; diff --git a/autofs-5.0.3-fix-percent-hack.patch b/autofs-5.0.3-fix-percent-hack.patch new file mode 100644 index 0000000..e02a77a --- /dev/null +++ b/autofs-5.0.3-fix-percent-hack.patch @@ -0,0 +1,369 @@ +From jmoyer@redhat.com Thu Jul 17 10:12:13 2008 + +From: Ian Kent + +Hi, Ian, + +As I mentioned, the encode and decode routines for the % hack were +corrupting heap space. I put together a patch to fix things as they +stand today. The comments document the assumptions I made. + +I tested this code by compiling a program that only included +these functions and passing them arbitrary input and validating the +reuslts. I then compiled them into the automounter and verified that +no heap corruption occurred (by running automount -f on a fedora +system where such things are reported). + +Now, I don't think that we should ever have to encode the percent +hack. Shouldn't we just need to decode it, walking through all of the +returned entries until we find an exact match for the key being looked +up? + +Comments welcome. + +IMK: You're right, but we'll keep it for the moment. + +Cheers, +Jeff +--- + + modules/lookup_ldap.c | 267 +++++++++++++++++++++++++++++++++++-------------- + 1 files changed, 193 insertions(+), 74 deletions(-) + + +diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c +index 7777e90..3990f8c 100644 +--- a/modules/lookup_ldap.c ++++ b/modules/lookup_ldap.c +@@ -1512,6 +1512,65 @@ next: + return NSS_STATUS_SUCCESS; + } + ++static int get_percent_decoded_len(const char *name) ++{ ++ int escapes = 0; ++ int escaped = 0; ++ char *tmp = name; ++ int look_for_close = 0; ++ ++ while (*tmp) { ++ if (*tmp == '%') { ++ /* assume escapes aren't interpreted inside brackets */ ++ if (look_for_close) { ++ tmp++; ++ continue; ++ } ++ /* check for escaped % */ ++ if (escaped) { ++ tmp++; ++ escaped = 0; ++ continue; ++ } ++ escapes++; ++ tmp++; ++ if (*tmp == '[') { ++ escapes++; ++ tmp++; ++ look_for_close = 1; ++ } else ++ escaped = 1; ++ } else if (*tmp == ']' && look_for_close) { ++ escaped = 0; ++ escapes++; ++ tmp++; ++ look_for_close = 0; ++ } else { ++ tmp++; ++ escaped = 0; ++ } ++ } ++ ++ assert(strlen(name) > escapes); ++ return strlen(name) - escapes; ++} ++ ++/* ++ * Try to catch heap corruption if our logic happens to be incorrect. ++ */ ++static void validate_string_len(const char *orig, char *start, ++ char *end, unsigned int len) ++{ ++ debug(LOGOPT_NONE, MODPREFIX "string %s encoded as %s", orig, start); ++ /* make sure we didn't overflow the allocated space */ ++ if (end - start > len + 1) { ++ crit(LOGOPT_ANY, MODPREFIX "orig %s, len %d", orig, len); ++ crit(LOGOPT_ANY, MODPREFIX "en/decoded %s, len %d", start, ++ end - start); ++ } ++ assert(end-start <= len + 1); ++} ++ + /* + * Deal with encode and decode of % hack. + * Return +@@ -1519,131 +1578,191 @@ next: + * -1 => syntax error or alloc fail. + * 1 transofrmed value returned. + */ ++/* ++ * Assumptions: %'s must be escaped by %'s. %'s are not used to escape ++ * anything else except capital letters (so you can't escape a closing ++ * bracket, for example). ++ */ + static int decode_percent_hack(const char *name, char **key) + { + const char *tmp; + char *ptr, *new; ++ unsigned int len; ++ int escaped = 0, look_for_close = 0; + + if (!key) + return -1; + + *key = NULL; + +- tmp = name; +- while (*tmp && *tmp != '%' && *tmp != '[' && *tmp != ']') +- tmp++; +- if (!*tmp) +- return 0; ++ len = get_percent_decoded_len(name); ++ new = malloc(len + 1); ++ if (!new) ++ return -1; + ++ ptr = new; + tmp = name; + while (*tmp) { + if (*tmp == '%') { +- tmp++; +- if (!*tmp) +- return -1; +- if (*tmp != '[') ++ if (escaped) { ++ *ptr++ = *tmp++; ++ if (!look_for_close) ++ escaped = 0; + continue; ++ } + tmp++; +- while (*tmp && *tmp != ']') { +- if (*tmp == '%') +- tmp++; ++ if (*tmp == '[') { + tmp++; +- } +- if (!tmp) +- return -1; +- } +- tmp++; +- } +- +- new = malloc(strlen(name) + 1); +- if (!new) +- return -1; +- +- ptr = new; +- tmp = name; +- while (*tmp) { +- if (*tmp == '%' || *tmp == '[' || *tmp == ']') { ++ look_for_close = 1; ++ escaped = 1; ++ } else ++ escaped = 1; ++ } else if (*tmp == ']' && look_for_close) { + tmp++; +- if (*tmp && *tmp != '%') +- continue; ++ look_for_close = 0; ++ } else { ++ escaped = 0; ++ *ptr++ = *tmp++; + } +- *ptr++ = *tmp++; + } + *ptr = '\0'; +- + *key = new; + ++ validate_string_len(name, new, ptr, len); + return strlen(new); + } + +-static int encode_percent_hack(const char *name, char **key, unsigned int use_class) ++/* ++ * Calculate the length of a string replacing all capital letters with %letter. ++ * For example: ++ * Sale -> %Sale ++ * SALE -> %S%A%L%E ++ */ ++static int get_encoded_len_escaping_every_cap(const char *name) + { + const char *tmp; +- unsigned int len = 0; +- char *ptr, *new; ++ unsigned int escapes = 0; /* number of % escape characters */ + +- if (!key) +- return -1; ++ tmp = name; ++ while (*tmp) { ++ /* We'll need to escape percents */ ++ if (*tmp == '%' || isupper(*tmp)) ++ escapes++; ++ tmp++; ++ } + +- *key = NULL; ++ return strlen(name) + escapes; ++} ++ ++/* ++ * Calculate the length of a string replacing sequences (1 or more) of capital ++ * letters with %[letters]. For example: ++ * FOO -> %[FOO] ++ * Work -> %[W]ork ++ * WorksForMe -> %[W]orks%[F]or%[M]e ++ * aaBBaa -> aa%[BB]aa ++ */ ++static int get_encoded_len_escaping_sequences(const char *name) ++{ ++ const char *tmp; ++ unsigned int escapes = 0; + + tmp = name; + while (*tmp) { ++ /* escape percents */ + if (*tmp == '%') +- len++; ++ escapes++; + else if (isupper(*tmp)) { +- tmp++; +- len++; +- if (!use_class) +- len++; +- else { +- if (*tmp && isupper(*tmp)) +- len += 2; +- else +- return 0; +- while (*tmp && isupper(*tmp)) { +- len++; +- tmp++; +- } +- } ++ /* start an escape block %[...] */ ++ escapes += 3; /* %[] */ ++ while (*tmp && isupper(*tmp)) ++ tmp++; + continue; + } +- len++; + tmp++; + } +- if (len == strlen(name)) +- return 0; + +- new = malloc(len + 1); +- if (!new) +- return -1; ++ return strlen(name) + escapes; ++} ++ ++static void encode_individual(const char *name, char *new, unsigned int len) ++{ ++ const char *tmp; ++ char *ptr; + + ptr = new; + tmp = name; + while (*tmp) { +- if (*tmp == '%') ++ if (*tmp == '%' || isupper(*tmp)) + *ptr++ = '%'; +- else if (isupper(*tmp)) { +- char next = *tmp++; ++ *ptr++ = *tmp++; ++ } ++ *ptr = '\0'; ++ validate_string_len(name, new, ptr, len); ++} ++ ++static void encode_sequence(const char *name, char *new, unsigned int len) ++{ ++ const char *tmp; ++ char *ptr; ++ ++ ptr = new; ++ tmp = name; ++ while (*tmp) { ++ if (*tmp == '%') { + *ptr++ = '%'; +- if (*tmp && (!isupper(*tmp) || !use_class)) +- *ptr++ = next; +- else { +- *ptr++ = '['; +- *ptr++ = next; +- while (*tmp && isupper(*tmp)) +- *ptr++ = *tmp++; +- *ptr++ = ']'; ++ *ptr++ = *tmp++; ++ } else if (isupper(*tmp)) { ++ *ptr++ = '%'; ++ *ptr++ = '['; ++ *ptr++ = *tmp++; ++ ++ while (*tmp && isupper(*tmp)) { ++ *ptr++ = *tmp; ++ tmp++; + } +- continue; +- } +- *ptr++ = *tmp++; ++ *ptr++ = ']'; ++ } else ++ *ptr++ = *tmp++; + } + *ptr = '\0'; ++ validate_string_len(name, new, ptr, len); ++} + +- *key = new; ++/* ++ * use_class: 1 means encode string as %[CAPITALS], 0 means encode as ++ * %C%A%P%I%T%A%L%S ++ */ ++static int encode_percent_hack(const char *name, char **key, unsigned int use_class) ++{ ++ unsigned int len = 0; + +- return strlen(new); ++ if (!key) ++ return -1; ++ ++ if (use_class) ++ len = get_encoded_len_escaping_sequences(name); ++ else ++ len = get_encoded_len_escaping_every_cap(name); ++ ++ /* If there is no escaping to be done, return 0 */ ++ if (len == strlen(name)) ++ return 0; ++ ++ *key = malloc(len + 1); ++ if (!*key) ++ return -1; ++ ++ if (use_class) ++ encode_sequence(name, *key, len); ++ else ++ encode_individual(name, *key, len); ++ ++ if (strlen(*key) != len) ++ crit(LOGOPT_ANY, MODPREFIX "encoded key length mismatch: key " ++ "%s len %d strlen %d", *key, len, strlen(*key)); ++ ++ return strlen(*key); + } + + static int do_paged_query(struct ldap_search_params *sp, struct lookup_context *ctxt) diff --git a/autofs-5.0.3-fix-proximity-other-timeout.patch b/autofs-5.0.3-fix-proximity-other-timeout.patch new file mode 100644 index 0000000..e15937a --- /dev/null +++ b/autofs-5.0.3-fix-proximity-other-timeout.patch @@ -0,0 +1,36 @@ +autofs-5.0.3 - fix proximity other rpc ping timeout + +From: Ian Kent + +The timeout for the RCP ping for hosts that are on a network other +than the local subnet or network is mistakenly set quite short. This +can lead to unexplained intermittent failures for hosts on remote +networks. +--- + + modules/replicated.c | 4 ++-- + 1 files changed, 2 insertions(+), 2 deletions(-) + + +diff --git a/modules/replicated.c b/modules/replicated.c +index efbe6b4..925f641 100644 +--- a/modules/replicated.c ++++ b/modules/replicated.c +@@ -552,7 +552,7 @@ static int get_vers_and_cost(unsigned logopt, struct host *host, + + if (host->proximity == PROXIMITY_NET) + timeout = RPC_TIMEOUT * 2; +- else if (host->proximity == PROXIMITY_NET) ++ else if (host->proximity == PROXIMITY_OTHER) + timeout = RPC_TIMEOUT * 8; + + rpc_info.host = host->name; +@@ -609,7 +609,7 @@ static int get_supported_ver_and_cost(unsigned logopt, struct host *host, + + if (host->proximity == PROXIMITY_NET) + timeout = RPC_TIMEOUT * 2; +- else if (host->proximity == PROXIMITY_NET) ++ else if (host->proximity == PROXIMITY_OTHER) + timeout = RPC_TIMEOUT * 8; + + rpc_info.host = host->name; diff --git a/autofs-5.0.3-fix-rootless-direct-multi-mount-expire.patch b/autofs-5.0.3-fix-rootless-direct-multi-mount-expire.patch new file mode 100644 index 0000000..b50c2fb --- /dev/null +++ b/autofs-5.0.3-fix-rootless-direct-multi-mount-expire.patch @@ -0,0 +1,36 @@ +autofs-5.0.3 - don't close direct root + +From: Ian Kent + +For direct mount multi-mounts with no real mount at their base we +need to leave the file handle open so they will be expired. This +patch corrects the check done at mount completion to do this so +they will be expired. +--- + + daemon/direct.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + + +--- autofs-5.0.3.orig/daemon/direct.c ++++ autofs-5.0.3/daemon/direct.c +@@ -1311,8 +1311,17 @@ static void *do_mount_direct(void *arg) + !master_find_submount(ap, mt.name))) + close_fd = 1; + cache_writelock(mt.mc); +- if (!close_fd && (me = cache_lookup_distinct(mt.mc, mt.name))) +- me->ioctlfd = mt.ioctlfd; ++ if ((me = cache_lookup_distinct(mt.mc, mt.name))) { ++ /* ++ * Careful here, we need to leave the file handle open ++ * for direct mount multi-mounts with no real mount at ++ * their base so they will be expired. ++ */ ++ if (close_fd && me == me->multi) ++ close_fd = 0; ++ if (!close_fd) ++ me->ioctlfd = mt.ioctlfd; ++ } + send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); + cache_unlock(mt.mc); + if (close_fd) diff --git a/autofs-5.0.3-library-reload-fix.patch b/autofs-5.0.3-library-reload-fix.patch new file mode 100644 index 0000000..01cc782 --- /dev/null +++ b/autofs-5.0.3-library-reload-fix.patch @@ -0,0 +1,164 @@ +autofs-5.0.3 - library reload fix + +From: Ian Kent + +During a map re-read autofs needs to re-open its lookup libraries but +dependent shared libraries can't handle being unloaded and then re-loaded +by the same process. This patch preventis dependent libraries from being +unloaded during this re-open. +--- + + daemon/automount.c | 1 - + daemon/lookup.c | 21 +++++++++------------ + daemon/state.c | 3 +++ + include/master.h | 17 +++-------------- + lib/master.c | 28 ++++++++++++++++++++++------ + 5 files changed, 37 insertions(+), 33 deletions(-) + + +--- autofs-5.0.3.orig/daemon/automount.c ++++ autofs-5.0.3/daemon/automount.c +@@ -85,7 +85,6 @@ int aquire_flag_file(void); + void release_flag_file(void); + static int umount_all(struct autofs_point *ap, int force); + +-extern pthread_mutex_t master_mutex; + extern struct master *master_list; + + static int do_mkdir(const char *parent, const char *path, mode_t mode) +--- autofs-5.0.3.orig/daemon/lookup.c ++++ autofs-5.0.3/daemon/lookup.c +@@ -267,17 +267,17 @@ static int do_read_map(struct autofs_poi + struct lookup_mod *lookup; + int status; + +- if (!map->lookup) { +- lookup = open_lookup(map->type, "", +- map->format, map->argc, map->argv); +- if (!lookup) { +- debug(ap->logopt, "lookup module %s failed", map->type); +- return NSS_STATUS_UNAVAIL; +- } +- map->lookup = lookup; ++ lookup = open_lookup(map->type, "", map->format, map->argc, map->argv); ++ if (!lookup) { ++ debug(ap->logopt, "lookup module %s failed", map->type); ++ return NSS_STATUS_UNAVAIL; + } + +- lookup = map->lookup; ++ master_source_writelock(ap->entry); ++ if (map->lookup) ++ close_lookup(map->lookup); ++ map->lookup = lookup; ++ master_source_unlock(ap->entry); + + /* If we don't need to create directories then there's no use + * reading the map. We just need to test that the map is valid +@@ -463,8 +463,6 @@ int lookup_nss_read_map(struct autofs_po + * point in the master map) do the nss lookup to + * locate the map and read it. + */ +- pthread_cleanup_push(master_source_lock_cleanup, entry); +- master_source_readlock(entry); + if (source) + map = source; + else +@@ -557,7 +555,6 @@ int lookup_nss_read_map(struct autofs_po + + map = map->next; + } +- pthread_cleanup_pop(1); + + if (!result || at_least_one) + return 1; +--- autofs-5.0.3.orig/daemon/state.c ++++ autofs-5.0.3/daemon/state.c +@@ -387,9 +387,12 @@ static void *do_readmap(void *arg) + + info(ap->logopt, "re-reading map for %s", ap->path); + ++ pthread_cleanup_push(master_mutex_lock_cleanup, NULL); ++ master_mutex_lock(); + status = lookup_nss_read_map(ap, NULL, now); + if (!status) + pthread_exit(NULL); ++ pthread_cleanup_pop(1); + + if (ap->type == LKP_INDIRECT) { + lookup_prune_cache(ap, now); +--- autofs-5.0.3.orig/include/master.h ++++ autofs-5.0.3/include/master.h +@@ -70,6 +70,9 @@ int master_parse_entry(const char *, uns + + /* From master.c master parser utility routines */ + ++void master_mutex_lock(void); ++void master_mutex_unlock(void); ++void master_mutex_lock_cleanup(void *); + void master_set_default_timeout(void); + void master_set_default_ghost_mode(void); + int master_add_autofs_point(struct master_mapent *, time_t, unsigned, unsigned, int); +@@ -108,18 +111,4 @@ extern inline unsigned int master_get_lo + int master_list_empty(struct master *); + int master_kill(struct master *); + +-#define master_mutex_lock() \ +-do { \ +- int status = pthread_mutex_lock(&master_mutex); \ +- if (status) \ +- fatal(status); \ +-} while (0) +- +-#define master_mutex_unlock() \ +-do { \ +- int status = pthread_mutex_unlock(&master_mutex); \ +- if (status) \ +- fatal(status); \ +-} while (0) +- + #endif +--- autofs-5.0.3.orig/lib/master.c ++++ autofs-5.0.3/lib/master.c +@@ -41,8 +41,28 @@ static struct map_source * + __master_find_map_source(struct master_mapent *, + const char *, const char *, int, const char **); + +-pthread_mutex_t master_mutex = PTHREAD_MUTEX_INITIALIZER; +-pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER; ++static pthread_mutex_t master_mutex = PTHREAD_MUTEX_INITIALIZER; ++static pthread_mutex_t instance_mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++void master_mutex_lock(void) ++{ ++ int status = pthread_mutex_lock(&master_mutex); ++ if (status) ++ fatal(status); ++} ++ ++void master_mutex_unlock(void) ++{ ++ int status = pthread_mutex_unlock(&master_mutex); ++ if (status) ++ fatal(status); ++} ++ ++void master_mutex_lock_cleanup(void *arg) ++{ ++ master_mutex_unlock(); ++ return; ++} + + int master_add_autofs_point(struct master_mapent *entry, + time_t timeout, unsigned logopt, unsigned ghost, int submount) +@@ -1109,10 +1129,6 @@ int master_mount_mounts(struct master *m + continue; + } + +- master_source_writelock(ap->entry); +- lookup_close_lookup(ap); +- master_source_unlock(ap->entry); +- + cache_readlock(nc); + ne = cache_lookup_distinct(nc, this->path); + if (ne && this->age > ne->age) { diff --git a/autofs-5.0.3-lookup-next-soucre-stale-entry.patch b/autofs-5.0.3-lookup-next-soucre-stale-entry.patch new file mode 100644 index 0000000..4e66ef2 --- /dev/null +++ b/autofs-5.0.3-lookup-next-soucre-stale-entry.patch @@ -0,0 +1,108 @@ +autofs-5.0.3 - multi-map doesn't pickup NIS updates automatically + +From: Ian Kent + +In a multi-map configuration, autofs doesn't pick up NIS updates +automatically. This is caused by the lookup not checking alternate +sources for the given key (or wildcard) when doing a key lookup. +--- + + lib/cache.c | 2 ++ + modules/lookup_file.c | 11 ++++++++--- + modules/lookup_ldap.c | 11 ++++++++--- + modules/lookup_nisplus.c | 11 ++++++++--- + modules/lookup_yp.c | 11 ++++++++--- + 5 files changed, 34 insertions(+), 12 deletions(-) + + +--- autofs-5.0.2.orig/lib/cache.c ++++ autofs-5.0.2/lib/cache.c +@@ -700,6 +700,8 @@ int cache_update(struct mapent_cache *mc + int ret = CHE_OK; + + me = cache_lookup(mc, key); ++ while (me && me->source != ms) ++ me = cache_lookup_key_next(me); + if (!me || (*me->key == '*' && *key != '*')) { + ret = cache_add(mc, ms, key, mapent, age); + if (!ret) { +--- autofs-5.0.2.orig/modules/lookup_file.c ++++ autofs-5.0.2/modules/lookup_file.c +@@ -1116,9 +1116,14 @@ int lookup_mount(struct autofs_point *ap + + cache_readlock(mc); + me = cache_lookup(mc, key); +- /* Stale mapent => check for wildcard */ +- if (me && !me->mapent) +- me = cache_lookup_distinct(mc, "*"); ++ /* Stale mapent => check for entry in alternate source or wildcard */ ++ if (me && !me->mapent) { ++ while ((me = cache_lookup_key_next(me))) ++ if (me->source == source) ++ break; ++ if (!me) ++ me = cache_lookup_distinct(mc, "*"); ++ } + if (me && (me->source == source || *me->key == '/')) { + pthread_cleanup_push(cache_lock_cleanup, mc); + mapent_len = strlen(me->mapent); +--- autofs-5.0.2.orig/modules/lookup_ldap.c ++++ autofs-5.0.2/modules/lookup_ldap.c +@@ -2596,9 +2596,14 @@ int lookup_mount(struct autofs_point *ap + + cache_readlock(mc); + me = cache_lookup(mc, key); +- /* Stale mapent => check for wildcard */ +- if (me && !me->mapent) +- me = cache_lookup_distinct(mc, "*"); ++ /* Stale mapent => check for entry in alternate source or wildcard */ ++ if (me && !me->mapent) { ++ while ((me = cache_lookup_key_next(me))) ++ if (me->source == source) ++ break; ++ if (!me) ++ me = cache_lookup_distinct(mc, "*"); ++ } + if (me && (me->source == source || *me->key == '/')) { + mapent_len = strlen(me->mapent); + mapent = alloca(mapent_len + 1); +--- autofs-5.0.2.orig/modules/lookup_nisplus.c ++++ autofs-5.0.2/modules/lookup_nisplus.c +@@ -530,9 +530,14 @@ int lookup_mount(struct autofs_point *ap + + cache_readlock(mc); + me = cache_lookup(mc, key); +- /* Stale mapent => check for wildcard */ +- if (me && !me->mapent) +- me = cache_lookup_distinct(mc, "*"); ++ /* Stale mapent => check for entry in alternate source or wildcard */ ++ if (me && !me->mapent) { ++ while ((me = cache_lookup_key_next(me))) ++ if (me->source == source) ++ break; ++ if (!me) ++ me = cache_lookup_distinct(mc, "*"); ++ } + if (me && (me->source == source || *me->key == '/')) { + mapent_len = strlen(me->mapent); + mapent = alloca(mapent_len + 1); +--- autofs-5.0.2.orig/modules/lookup_yp.c ++++ autofs-5.0.2/modules/lookup_yp.c +@@ -628,9 +628,14 @@ int lookup_mount(struct autofs_point *ap + + cache_readlock(mc); + me = cache_lookup(mc, key); +- /* Stale mapent => check for wildcard */ +- if (me && !me->mapent) +- me = cache_lookup_distinct(mc, "*"); ++ /* Stale mapent => check for entry in alternate source or wildcard */ ++ if (me && !me->mapent) { ++ while ((me = cache_lookup_key_next(me))) ++ if (me->source == source) ++ break; ++ if (!me) ++ me = cache_lookup_distinct(mc, "*"); ++ } + if (me && (me->source == source || *me->key == '/')) { + mapent_len = strlen(me->mapent); + mapent = alloca(mapent_len + 1); diff --git a/autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch b/autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch new file mode 100644 index 0000000..760a22c --- /dev/null +++ b/autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch @@ -0,0 +1,288 @@ +autofs-5.0.3 - make handle_mounts startup condition distinct + +From: Ian Kent + +When starting a number of mounts we can get contention for the startup +condition used to synchronize the handle_mounts thread completion. This +patch makes the condition used distinct for each thread creation. +--- + + daemon/automount.c | 62 +++++++++++++++++++++++++++++++++++++++++++++---- + include/automount.h | 4 +++ + lib/master.c | 29 +++++++++++----------- + modules/mount_autofs.c | 35 +++++++++++++-------------- + 4 files changed, 92 insertions(+), 38 deletions(-) + + +--- autofs-5.0.2.orig/daemon/automount.c ++++ autofs-5.0.2/daemon/automount.c +@@ -1461,6 +1461,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; +@@ -1512,17 +1561,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); +@@ -1530,7 +1582,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); +@@ -1540,7 +1592,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 +--- autofs-5.0.2.orig/include/automount.h ++++ autofs-5.0.2/include/automount.h +@@ -331,10 +331,14 @@ int ncat_path(char *buf, size_t len, + 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; +--- autofs-5.0.2.orig/lib/master.c ++++ autofs-5.0.2/lib/master.c +@@ -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; + } +--- autofs-5.0.2.orig/modules/mount_autofs.c ++++ autofs-5.0.2/modules/mount_autofs.c +@@ -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; +@@ -210,34 +211,34 @@ int mount_mount(struct autofs_point *ap, + source->mc = cache_init(entry->ap, source); + if (!source->mc) { + error(ap->logopt, MODPREFIX "failed to init source cache"); ++ master_free_map_source(source, 0); + master_free_mapent(entry); + return 1; + } + + mounts_mutex_lock(ap); + +- status = pthread_mutex_lock(&suc.mutex); +- if (status) { +- crit(ap->logopt, +- MODPREFIX "failed to lock startup condition mutex!"); +- cache_release(source); ++ 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); ++ master_free_map_source(source, 1); + 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, &thread_attr, handle_mounts, &suc)) { + crit(ap->logopt, + MODPREFIX + "failed to create mount handler thread for %s", + fullpath); ++ handle_mounts_startup_cond_destroy(&suc); + mounts_mutex_unlock(ap); +- status = pthread_mutex_unlock(&suc.mutex); +- if (status) +- fatal(status); +- cache_release(source); ++ master_free_map_source(source, 1); + master_free_mapent(entry); + return 1; + } +@@ -246,8 +247,10 @@ int mount_mount(struct autofs_point *ap, + while (!suc.done) { + status = pthread_cond_wait(&suc.cond, &suc.mutex); + if (status) { ++ handle_mounts_startup_cond_destroy(&suc); + mounts_mutex_unlock(ap); +- pthread_mutex_unlock(&suc.mutex); ++ master_free_map_source(source, 1); ++ master_free_mapent(entry); + fatal(status); + } + } +@@ -255,10 +258,9 @@ int mount_mount(struct autofs_point *ap, + if (suc.status) { + crit(ap->logopt, + MODPREFIX "failed to create submount for %s", fullpath); ++ handle_mounts_startup_cond_destroy(&suc); + mounts_mutex_unlock(ap); +- status = pthread_mutex_unlock(&suc.mutex); +- if (status) +- fatal(status); ++ master_free_map_source(source, 1); + master_free_mapent(entry); + return 1; + } +@@ -266,12 +268,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 --git a/autofs-5.0.3-map-type-in-map-name-fix.patch b/autofs-5.0.3-map-type-in-map-name-fix.patch new file mode 100644 index 0000000..bb5fae2 --- /dev/null +++ b/autofs-5.0.3-map-type-in-map-name-fix.patch @@ -0,0 +1,27 @@ +autofs-5.0.3 - map type in map name fix + +From: Ian Kent + +Fix incorrect match of map type as a host name. +Actually the original patch didn't match upstream or RHEL +so this syncs the source with those. It appears the problem +was fixed here some time ago but slightly differently. +--- + + lib/master_tok.l | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + + +--- autofs-5.0.3.orig/lib/master_tok.l ++++ autofs-5.0.3/lib/master_tok.l +@@ -202,7 +202,9 @@ OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|-- + } + } + +- {MTYPE}/({DNSERVERSTR}|{DNATTRSTR}=)? { ++ {MTYPE} | ++ {MTYPE}/{DNSERVERSTR}{DNATTRSTR} | ++ {MTYPE}/{DNATTRSTR}= { + tlen = master_leng - 1; + if (bptr != buff && isblank(master_text[tlen])) { + strncat(buff, master_text, tlen); diff --git a/autofs-5.0.3-map-type-in-map-name.patch b/autofs-5.0.3-map-type-in-map-name.patch new file mode 100644 index 0000000..49de111 --- /dev/null +++ b/autofs-5.0.3-map-type-in-map-name.patch @@ -0,0 +1,56 @@ +--- + lib/master_tok.l | 27 +++++++++++++++++++++------ + 1 file changed, 21 insertions(+), 6 deletions(-) + +--- autofs-5.0.2.orig/lib/master_tok.l ++++ autofs-5.0.2/lib/master_tok.l +@@ -77,6 +77,7 @@ int my_yyinput(char *, int); + char buff[1024]; + char *bptr; + char *optr = buff; ++unsigned int tlen; + + %} + +@@ -190,13 +191,27 @@ OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|-- + {OPTWS}\\\n{OPTWS} {} + + {MULTI} { +- strcpy(master_lval.strtype, master_text); +- return(MULTITYPE); ++ tlen = master_leng - 1; ++ if (bptr != buff && isblank(master_text[tlen])) { ++ strncat(buff, master_text, tlen); ++ bptr += tlen; ++ yyless(tlen); ++ } else { ++ strcpy(master_lval.strtype, master_text); ++ return(MULTITYPE); ++ } + } + +- {MTYPE} { +- strcpy(master_lval.strtype, master_text); +- return(MAPTYPE); ++ {MTYPE}/({DNSERVERSTR}|{DNATTRSTR}=)? { ++ tlen = master_leng - 1; ++ if (bptr != buff && isblank(master_text[tlen])) { ++ strncat(buff, master_text, tlen); ++ bptr += tlen; ++ yyless(tlen); ++ } else { ++ strcpy(master_lval.strtype, master_text); ++ return(MAPTYPE); ++ } + } + + {MULTISEP} { return(DDASH); } +@@ -226,7 +241,7 @@ OPTNTOUT (-n{OPTWS}|-n{OPTWS}={OPTWS}|-- + yyless(0); + } + +- {DNSERVERSTR} { ++ {DNSERVERSTR}{DNATTRSTR} { + BEGIN(DNSTR); + yyless(0); + } diff --git a/autofs-5.0.3-mount-thread-create-cond-handling-fix.patch b/autofs-5.0.3-mount-thread-create-cond-handling-fix.patch new file mode 100644 index 0000000..ae8c006 --- /dev/null +++ b/autofs-5.0.3-mount-thread-create-cond-handling-fix.patch @@ -0,0 +1,206 @@ +autofs-5.0.3 - mount thread create condition handling fix + +From: Ian Kent + +Make the mount thread creation condition mutex specific to the +thread being created. +--- + + daemon/direct.c | 31 +++++++++++++++++++++++-------- + daemon/indirect.c | 31 +++++++++++++++++++++++-------- + 2 files changed, 46 insertions(+), 16 deletions(-) + + +--- autofs-5.0.2.orig/daemon/direct.c ++++ autofs-5.0.2/daemon/direct.c +@@ -50,7 +50,6 @@ pthread_key_t key_mnt_direct_params; + pthread_key_t key_mnt_offset_params; + pthread_once_t key_mnt_params_once = PTHREAD_ONCE_INIT; + +-static pthread_mutex_t ma_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_mutex_t ea_mutex = PTHREAD_MUTEX_INITIALIZER; + + static void key_mnt_params_destroy(void *arg) +@@ -1218,9 +1217,18 @@ static void mount_send_fail(void *arg) + close(mt->ioctlfd); + } + ++static void pending_mutex_destroy(void *arg) ++{ ++ struct pending_args *mt = (struct pending_args *) arg; ++ int status = pthread_mutex_destroy(&mt->mutex); ++ if (status) ++ fatal(status); ++} ++ + static void mount_mutex_unlock(void *arg) + { +- int status = pthread_mutex_unlock(&ma_mutex); ++ struct pending_args *mt = (struct pending_args *) arg; ++ int status = pthread_mutex_unlock(&mt->mutex); + if (status) + fatal(status); + } +@@ -1243,7 +1251,7 @@ static void *do_mount_direct(void *arg) + + args = (struct pending_args *) arg; + +- status = pthread_mutex_lock(&ma_mutex); ++ status = pthread_mutex_lock(&args->mutex); + if (status) + fatal(status); + +@@ -1256,7 +1264,7 @@ static void *do_mount_direct(void *arg) + if (status) + fatal(status); + +- mount_mutex_unlock(NULL); ++ mount_mutex_unlock(args); + + pthread_cleanup_push(mount_send_fail, &mt); + +@@ -1533,7 +1541,11 @@ int handle_packet_missing_direct(struct + if (status) + fatal(status); + +- status = pthread_mutex_lock(&ma_mutex); ++ status = pthread_mutex_init(&mt->mutex, NULL); ++ if (status) ++ fatal(status); ++ ++ status = pthread_mutex_lock(&mt->mutex); + if (status) + fatal(status); + +@@ -1553,8 +1565,9 @@ int handle_packet_missing_direct(struct + send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); + close(ioctlfd); + cache_unlock(mc); +- mount_mutex_unlock(NULL); ++ mount_mutex_unlock(mt); + pending_cond_destroy(mt); ++ pending_mutex_destroy(mt); + free_pending_args(mt); + pthread_setcancelstate(state, NULL); + return 1; +@@ -1562,13 +1575,14 @@ int handle_packet_missing_direct(struct + + cache_unlock(mc); + pthread_cleanup_push(free_pending_args, mt); ++ pthread_cleanup_push(pending_mutex_destroy, mt); + pthread_cleanup_push(pending_cond_destroy, mt); +- pthread_cleanup_push(mount_mutex_unlock, NULL); ++ pthread_cleanup_push(mount_mutex_unlock, mt); + pthread_setcancelstate(state, NULL); + + mt->signaled = 0; + while (!mt->signaled) { +- status = pthread_cond_wait(&mt->cond, &ma_mutex); ++ status = pthread_cond_wait(&mt->cond, &mt->mutex); + if (status) + fatal(status); + } +@@ -1576,6 +1590,7 @@ int handle_packet_missing_direct(struct + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); ++ pthread_cleanup_pop(1); + + return 0; + } +--- autofs-5.0.2.orig/daemon/indirect.c ++++ autofs-5.0.2/daemon/indirect.c +@@ -40,7 +40,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 int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts) +@@ -651,9 +650,18 @@ static void mount_send_fail(void *arg) + send_fail(mt->ap->logopt, mt->ap->ioctlfd, mt->wait_queue_token); + } + ++static void pending_mutex_destroy(void *arg) ++{ ++ struct pending_args *mt = (struct pending_args *) arg; ++ int status = pthread_mutex_destroy(&mt->mutex); ++ if (status) ++ fatal(status); ++} ++ + static void mount_mutex_unlock(void *arg) + { +- int status = pthread_mutex_unlock(&ma_mutex); ++ struct pending_args *mt = (struct pending_args *) arg; ++ int status = pthread_mutex_unlock(&mt->mutex); + if (status) + fatal(status); + } +@@ -676,7 +684,7 @@ static void *do_mount_indirect(void *arg + + args = (struct pending_args *) arg; + +- status = pthread_mutex_lock(&ma_mutex); ++ status = pthread_mutex_lock(&args->mutex); + if (status) + fatal(status); + +@@ -689,7 +697,7 @@ static void *do_mount_indirect(void *arg + if (status) + fatal(status); + +- mount_mutex_unlock(NULL); ++ mount_mutex_unlock(args); + + pthread_cleanup_push(mount_send_fail, &mt); + +@@ -884,7 +892,11 @@ int handle_packet_missing_indirect(struc + if (status) + fatal(status); + +- status = pthread_mutex_lock(&ma_mutex); ++ status = pthread_mutex_init(&mt->mutex, NULL); ++ if (status) ++ fatal(status); ++ ++ status = pthread_mutex_lock(&mt->mutex); + if (status) + fatal(status); + +@@ -901,21 +913,23 @@ int handle_packet_missing_indirect(struc + if (status) { + error(ap->logopt, "expire thread create failed"); + send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); +- mount_mutex_unlock(NULL); ++ mount_mutex_unlock(mt); + pending_cond_destroy(mt); ++ pending_mutex_destroy(mt); + free_pending_args(mt); + pthread_setcancelstate(state, NULL); + return 1; + } + + pthread_cleanup_push(free_pending_args, mt); ++ pthread_cleanup_push(pending_mutex_destroy, mt); + pthread_cleanup_push(pending_cond_destroy, mt); +- pthread_cleanup_push(mount_mutex_unlock, NULL); ++ pthread_cleanup_push(mount_mutex_unlock, mt); + pthread_setcancelstate(state, NULL); + + mt->signaled = 0; + while (!mt->signaled) { +- status = pthread_cond_wait(&mt->cond, &ma_mutex); ++ status = pthread_cond_wait(&mt->cond, &mt->mutex); + if (status) + fatal(status); + } +@@ -923,6 +937,7 @@ int handle_packet_missing_indirect(struc + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); ++ pthread_cleanup_pop(1); + + return 0; + } diff --git a/autofs-5.0.3-mtab-as-proc-mounts-fix.patch b/autofs-5.0.3-mtab-as-proc-mounts-fix.patch new file mode 100644 index 0000000..dc01908 --- /dev/null +++ b/autofs-5.0.3-mtab-as-proc-mounts-fix.patch @@ -0,0 +1,25 @@ +autofs-5.0.3 - check for mtab pointing to /proc/mounts fix + +From: Ian Kent + +Fix incorrect initialization in spawn_bind_mount() which +caused bind mounts to not be added to mtab. +--- + + daemon/spawn.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + + +diff --git a/daemon/spawn.c b/daemon/spawn.c +index 85cf9b8..17f92f4 100644 +--- a/daemon/spawn.c ++++ b/daemon/spawn.c +@@ -432,7 +432,7 @@ int spawn_bind_mount(unsigned logopt, ...) + char arg_fake[] = "-f"; + unsigned int options; + unsigned int retries = MTAB_LOCK_RETRIES; +- int update_mtab = 0, ret, printed = 0; ++ int update_mtab = 1, ret, printed = 0; + char buf[PATH_MAX]; + + /* If we use mount locking we can't validate the location */ diff --git a/autofs-5.0.3-mtab-as-proc-mounts.patch b/autofs-5.0.3-mtab-as-proc-mounts.patch new file mode 100644 index 0000000..81a2270 --- /dev/null +++ b/autofs-5.0.3-mtab-as-proc-mounts.patch @@ -0,0 +1,155 @@ +autofs-5.0.3 - check for mtab pointing to /proc/mounts + +From: Ian Kent + +autofs has problems if /etc/mtab points to /proc/mounts. +This patchs adds a check to see if this is the case. If it is then +autofs uses the mount(8) "-n" option which disables the normal mtab +update error checking. +--- + + daemon/spawn.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 60 insertions(+), 6 deletions(-) + + +--- autofs-5.0.2.orig/daemon/spawn.c ++++ autofs-5.0.2/daemon/spawn.c +@@ -305,11 +305,13 @@ int spawn_mount(unsigned logopt, ...) + char **argv, **p; + char prog[] = PATH_MOUNT; + char arg0[] = PATH_MOUNT; ++ char argn[] = "-n"; + /* In case we need to use the fake option to mount */ + char arg_fake[] = "-f"; + unsigned int options; + unsigned int retries = MTAB_LOCK_RETRIES; +- int ret, printed = 0; ++ int update_mtab = 1, ret, printed = 0; ++ char buf[PATH_MAX]; + + /* If we use mount locking we can't validate the location */ + #ifdef ENABLE_MOUNT_LOCKING +@@ -322,6 +324,17 @@ int spawn_mount(unsigned logopt, ...) + for (argc = 1; va_arg(arg, char *); argc++); + va_end(arg); + ++ ret = readlink(_PATH_MOUNTED, buf, PATH_MAX); ++ if (ret != -1) { ++ buf[ret] = '\0'; ++ if (!strcmp(buf, _PROC_MOUNTS)) { ++ debug(logopt, ++ "mtab link detected, passing -n to mount"); ++ argc++; ++ update_mtab = 0; ++ } ++ } ++ + /* Alloc 1 extra slot in case we need to use the "-f" option */ + if (!(argv = alloca(sizeof(char *) * argc + 2))) + return -1; +@@ -329,7 +342,12 @@ int spawn_mount(unsigned logopt, ...) + argv[0] = arg0; + + va_start(arg, logopt); +- p = argv + 1; ++ if (update_mtab) ++ p = argv + 1; ++ else { ++ argv[1] = argn; ++ p = argv + 2; ++ } + while ((*p = va_arg(arg, char *))) { + if (options == SPAWN_OPT_NONE && !strcmp(*p, "-o")) { + *(++p) = va_arg(arg, char *); +@@ -409,11 +427,13 @@ int spawn_bind_mount(unsigned logopt, .. + char prog[] = PATH_MOUNT; + char arg0[] = PATH_MOUNT; + char bind[] = "--bind"; ++ char argn[] = "-n"; + /* In case we need to use the fake option to mount */ + char arg_fake[] = "-f"; + unsigned int options; + unsigned int retries = MTAB_LOCK_RETRIES; +- int ret, printed = 0; ++ int update_mtab = 0, ret, printed = 0; ++ char buf[PATH_MAX]; + + /* If we use mount locking we can't validate the location */ + #ifdef ENABLE_MOUNT_LOCKING +@@ -430,6 +450,17 @@ int spawn_bind_mount(unsigned logopt, .. + for (argc = 2; va_arg(arg, char *); argc++); + va_end(arg); + ++ ret = readlink(_PATH_MOUNTED, buf, PATH_MAX); ++ if (ret != -1) { ++ buf[ret] = '\0'; ++ if (!strcmp(buf, _PROC_MOUNTS)) { ++ debug(logopt, ++ "mtab link detected, passing -n to mount"); ++ argc++; ++ update_mtab = 0; ++ } ++ } ++ + if (!(argv = alloca(sizeof(char *) * argc + 2))) + return -1; + +@@ -437,7 +468,12 @@ int spawn_bind_mount(unsigned logopt, .. + argv[1] = bind; + + va_start(arg, logopt); +- p = argv + 2; ++ if (update_mtab) ++ p = argv + 2; ++ else { ++ argv[2] = argn; ++ p = argv + 3; ++ } + while ((*p++ = va_arg(arg, char *))); + va_end(arg); + +@@ -499,10 +535,12 @@ int spawn_umount(unsigned logopt, ...) + char **argv, **p; + char prog[] = PATH_UMOUNT; + char arg0[] = PATH_UMOUNT; ++ char argn[] = "-n"; + unsigned int options; + unsigned int retries = MTAB_LOCK_RETRIES; +- int ret, printed = 0; ++ int update_mtab = 1, ret, printed = 0; + unsigned int wait = defaults_get_umount_wait(); ++ char buf[PATH_MAX]; + + #ifdef ENABLE_MOUNT_LOCKING + options = SPAWN_OPT_LOCK; +@@ -514,13 +552,29 @@ int spawn_umount(unsigned logopt, ...) + for (argc = 1; va_arg(arg, char *); argc++); + va_end(arg); + ++ ret = readlink(_PATH_MOUNTED, buf, PATH_MAX); ++ if (ret != -1) { ++ buf[ret] = '\0'; ++ if (!strcmp(buf, _PROC_MOUNTS)) { ++ debug(logopt, ++ "mtab link detected, passing -n to mount"); ++ argc++; ++ update_mtab = 0; ++ } ++ } ++ + if (!(argv = alloca(sizeof(char *) * argc + 1))) + return -1; + + argv[0] = arg0; + + va_start(arg, logopt); +- p = argv + 1; ++ if (update_mtab) ++ p = argv + 1; ++ else { ++ argv[1] = argn; ++ p = argv + 2; ++ } + while ((*p++ = va_arg(arg, char *))); + va_end(arg); + diff --git a/autofs-5.0.3-nisplus-partial-and-free.patch b/autofs-5.0.3-nisplus-partial-and-free.patch new file mode 100644 index 0000000..9333873 --- /dev/null +++ b/autofs-5.0.3-nisplus-partial-and-free.patch @@ -0,0 +1,54 @@ +autofs-5.0.3 - nisplus partial and free + +From: Jeff Bastian + +During a nisplus key lookup nis_list() can return NIS_PARTIAL +as well as possibly NIS_NOTFOUND or NIS_S_NOTFOUND when the key +doesn't exist. This patch adds this to the checks and fixes a use +after free of the result struct. +--- + + modules/lookup_nisplus.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + + +--- autofs-5.0.3.orig/modules/lookup_nisplus.c ++++ autofs-5.0.3/modules/lookup_nisplus.c +@@ -285,13 +285,15 @@ static int lookup_one(struct autofs_poin + + result = nis_list(tablename, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) { ++ nis_error rs = result->status; + nis_freeresult(result); + pthread_setcancelstate(cur_state, NULL); +- if (result->status == NIS_NOTFOUND || +- result->status == NIS_S_NOTFOUND) ++ if (rs == NIS_NOTFOUND || ++ rs == NIS_S_NOTFOUND || ++ rs == NIS_PARTIAL) + return CHE_MISSING; + +- return -result->status; ++ return -rs; + } + + +@@ -338,13 +340,15 @@ static int lookup_wild(struct autofs_poi + + result = nis_list(tablename, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); + if (result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) { ++ nis_error rs = result->status; + nis_freeresult(result); + pthread_setcancelstate(cur_state, NULL); +- if (result->status == NIS_NOTFOUND || +- result->status == NIS_S_NOTFOUND) ++ if (rs == NIS_NOTFOUND || ++ rs == NIS_S_NOTFOUND || ++ rs == NIS_PARTIAL) + return CHE_MISSING; + +- return -result->status; ++ return -rs; + } + + this = NIS_RES_OBJECT(result); diff --git a/autofs-5.0.3-nss-source-any.patch b/autofs-5.0.3-nss-source-any.patch new file mode 100644 index 0000000..5bccce0 --- /dev/null +++ b/autofs-5.0.3-nss-source-any.patch @@ -0,0 +1,147 @@ +autofs-5.0.3 - ignore nsswitch sources that aren't supported + +From: Ian Kent + +Allow any source name in nsswitch and ignore those we don't support. +This has the side affect of also ignoring any action associated with +a source that isn't supported by autofs. +--- + + lib/nss_parse.y | 31 ++++++++++++++++--------------- + lib/nss_tok.l | 22 ++++++++++++---------- + 2 files changed, 28 insertions(+), 25 deletions(-) + + +--- autofs-5.0.2.orig/lib/nss_parse.y ++++ autofs-5.0.2/lib/nss_parse.y +@@ -64,7 +64,6 @@ char strval[128]; + %token SOURCE + %token STATUS + %token ACTION +-%token OTHER + + %start file + +@@ -83,7 +82,9 @@ sources: nss_source + + nss_source: SOURCE + { +- if (strcmp($1, "winbind")) ++ if (!strcmp($1, "files") || !strcmp($1, "yp") || ++ !strcmp($1, "nis") || !strcmp($1, "ldap") || ++ !strcmp($1, "nisplus") || !strcmp($1, "hesiod")) + src = add_source(nss_list, $1); + else + nss_ignore($1); +@@ -91,7 +92,9 @@ nss_source: SOURCE + { + enum nsswitch_status a; + +- if (strcmp($1, "winbind")) { ++ if (!strcmp($1, "files") || !strcmp($1, "yp") || ++ !strcmp($1, "nis") || !strcmp($1, "ldap") || ++ !strcmp($1, "nisplus") || !strcmp($1, "hesiod")) { + src = add_source(nss_list, $1); + for (a = 0; a < NSS_STATUS_MAX; a++) { + if (act[a].action != NSS_ACTION_UNKNOWN) { +@@ -101,12 +104,10 @@ nss_source: SOURCE + } + } else + nss_ignore($1); +-} | SOURCE LBRACKET status_exp_list SOURCE { nss_error($4); YYABORT; } +- | SOURCE LBRACKET status_exp_list OTHER { nss_error($4); YYABORT; } +- | SOURCE LBRACKET status_exp_list NL { nss_error("no closing bracket"); YYABORT; } +- | SOURCE LBRACKET OTHER { nss_error($3); YYABORT; } +- | SOURCE OTHER { nss_error("no opening bracket"); YYABORT; } +- | error OTHER { nss_error($2); YYABORT; }; ++} | SOURCE LBRACKET status_exp_list SOURCE { nss_error("missing close bracket"); YYABORT; } ++ | SOURCE LBRACKET status_exp_list NL { nss_error("missing close bracket"); YYABORT; } ++ | SOURCE LBRACKET SOURCE { nss_error($3); YYABORT; } ++ | error SOURCE { nss_error($2); YYABORT; }; + + status_exp_list: status_exp + | status_exp status_exp_list +@@ -117,17 +118,17 @@ status_exp: STATUS EQUAL ACTION + } | BANG STATUS EQUAL ACTION + { + set_action(act, $2, $4, 1); +-} | STATUS EQUAL OTHER {nss_error($3); YYABORT; } +- | STATUS OTHER {nss_error($2); YYABORT; } +- | BANG STATUS EQUAL OTHER {nss_error($4); YYABORT; } +- | BANG STATUS OTHER {nss_error($3); YYABORT; } +- | BANG OTHER {nss_error($2); YYABORT; }; ++} | STATUS EQUAL SOURCE {nss_error($3); YYABORT; } ++ | STATUS SOURCE {nss_error($2); YYABORT; } ++ | BANG STATUS EQUAL SOURCE {nss_error($4); YYABORT; } ++ | BANG STATUS SOURCE {nss_error($3); YYABORT; } ++ | BANG SOURCE {nss_error($2); YYABORT; }; + + %% + + static int nss_ignore(const char *s) + { +- logmsg("ignored invalid nsswitch config near [ %s ]", s); ++ logmsg("ignored unsupported autofs nsswitch source \"%s\"", s); + return(0); + } + +--- autofs-5.0.2.orig/lib/nss_tok.l ++++ autofs-5.0.2/lib/nss_tok.l +@@ -62,13 +62,13 @@ extern unsigned int nss_automount_found; + + %option nounput + +-%x AUTOMOUNT ++%x AUTOMOUNT ACTIONSTR + + WS [[:blank:]]+ + + automount ([Aa][Uu][Tt][Oo][Mm][Oo][Uu][Nn][Tt]) + +-source files|yp|nis|nisplus|ldap|hesiod|winbind ++source [[:alnum:]@$%^&*()-+_":;?,<>./'{}~`]+ + + success ([Ss][Uu][Cc][Cc][Ee][Ss][Ss]) + notfound ([Nn][Oo][Tt][Ff][Oo][Uu][Nn][Dd]) +@@ -82,8 +82,6 @@ return ([Rr][Ee][Tt][Uu][Rr][Nn]) + + action ({continue}|{return}) + +-other [[:alnum:]@$%^&*()-+_":;?,<>./'{}~`]+ +- + %% + + ^{automount}: { +@@ -101,6 +99,14 @@ other [[:alnum:]@$%^&*()-+_":;?,<>./'{} + return SOURCE; + } + ++ "[" { BEGIN(ACTIONSTR); yyless(0); } ++ ++ \n { BEGIN(INITIAL); return NL; } ++} ++ ++{ ++ {WS} { } ++ + {status} { + strcpy(nss_lval.strval, nss_text); + return STATUS; +@@ -112,15 +118,11 @@ other [[:alnum:]@$%^&*()-+_":;?,<>./'{} + } + + "[" { return LBRACKET; } +- "]" { return RBRACKET; } ++ "]" { BEGIN(AUTOMOUNT); return RBRACKET; } + "=" { return EQUAL; } + "!" { return BANG; } + +- {other} { +- strcpy(nss_lval.strval, nss_text); +- return OTHER; +- } +- ++ . { BEGIN(AUTOMOUNT); yyless(0); } + \n { BEGIN(INITIAL); return NL; } + } + diff --git a/autofs-5.0.3-override-is-running-check.patch b/autofs-5.0.3-override-is-running-check.patch new file mode 100644 index 0000000..33ad62e --- /dev/null +++ b/autofs-5.0.3-override-is-running-check.patch @@ -0,0 +1,104 @@ +autofs-5.0.3 - add command line option to override is running check + +From: Ian Kent + +autofs common usage is to have a single instance of the daemon running +and it checks for this and exits if another instance is found to be +running. But there are situations were people need to run multiple +instances and this patch adds a command line option to overrid the +check. Please note that this doesn't mean that autofs will function +properly and it is the users responsibility to check that the +configuration in use will function properly. +--- + + daemon/automount.c | 14 +++++++++++--- + man/automount.8 | 10 ++++++++++ + 2 files changed, 21 insertions(+), 3 deletions(-) + + +--- autofs-5.0.2.orig/daemon/automount.c ++++ autofs-5.0.2/daemon/automount.c +@@ -1694,6 +1694,8 @@ static void usage(void) + " specify global mount options\n" + " -l --set-log-priority priority path [path,...]\n" + " set daemon log verbosity\n" ++ " -C --dont-check-daemon\n" ++ " don't check if daemon is already running\n" + " -V --version print version, build config and exit\n" + , program); + } +@@ -1814,7 +1816,7 @@ int main(int argc, char *argv[]) + { + int res, opt, status; + int logpri = -1; +- unsigned ghost, logging; ++ unsigned ghost, logging, daemon_check; + unsigned foreground, have_global_options; + time_t timeout; + time_t age = time(NULL); +@@ -1833,6 +1835,7 @@ int main(int argc, char *argv[]) + {"global-options", 1, 0, 'O'}, + {"version", 0, 0, 'V'}, + {"set-log-priority", 1, 0, 'l'}, ++ {"dont-check-daemon", 0, 0, 'C'}, + {0, 0, 0, 0} + }; + +@@ -1851,9 +1854,10 @@ int main(int argc, char *argv[]) + global_options = NULL; + have_global_options = 0; + foreground = 0; ++ daemon_check = 1; + + opterr = 0; +- while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:n:", long_options, NULL)) != EOF) { ++ while ((opt = getopt_long(argc, argv, "+hp:t:vdD:fVrO:l:n:C", long_options, NULL)) != EOF) { + switch (opt) { + case 'h': + usage(); +@@ -1922,6 +1926,10 @@ int main(int argc, char *argv[]) + } + break; + ++ case 'C': ++ daemon_check = 0; ++ break; ++ + case '?': + case ':': + printf("%s: Ambiguous or unknown options\n", program); +@@ -1965,7 +1973,7 @@ int main(int argc, char *argv[]) + exit(exit_code); + } + +- if (is_automount_running() > 0) { ++ if (daemon_check && is_automount_running() > 0) { + fprintf(stderr, "%s: program is already running.\n", + program); + exit(1); +--- autofs-5.0.2.orig/man/automount.8 ++++ autofs-5.0.2/man/automount.8 +@@ -81,6 +81,9 @@ be disabled, returning the daemon to ver + .P + The \fIpath\fP argument corresponds to the automounted + path name as specified in the master map. ++.TP ++.I "\-C, \-\-dont-check-daemon" ++Don't check if the daemon is currently running (see NOTES). + .SH ARGUMENTS + \fBautomount\fP takes one optional argument, the name of the master map to + use. +@@ -122,6 +125,13 @@ until they are no longer in use by the p + If automount managed filesystems are found mounted when autofs is + started they will be recoverd unless they are no longer present in + the map in which case they need to umounted manually. ++.P ++If the option to disable the check to see if the daemon is already ++running is used be aware that autofs currently may not function correctly ++for certain types of automount maps. The mounts of the seperate daemons ++might interfere with one another. The implications of running multiple ++daemon instances needs to be checked and tested before we can say this ++is supported. + .SH "SEE ALSO" + .BR autofs (5), + .BR autofs (8), diff --git a/autofs-5.0.3-refactor-mount-request-vars.patch b/autofs-5.0.3-refactor-mount-request-vars.patch new file mode 100644 index 0000000..27799b9 --- /dev/null +++ b/autofs-5.0.3-refactor-mount-request-vars.patch @@ -0,0 +1,1202 @@ +autofs-5.0.3 - refactor mount request vars + +From: Ian Kent + +There is code duplication between the direct and indirect mount +modules that sets up the variables available to maps. This patch +reorganizes and moves that code to a common location. + +Signed-off-by: Ian Kent +--- + + daemon/direct.c | 131 ---------------- + daemon/indirect.c | 131 ---------------- + include/automount.h | 56 ------ + include/mounts.h | 91 +++++++++++ + include/parse_subs.h | 3 + lib/mounts.c | 410 +++++++++++++++++++++++++++++++++++++++++++++------ + lib/parse_subs.c | 230 ---------------------------- + 7 files changed, 458 insertions(+), 594 deletions(-) + create mode 100644 include/mounts.h + + +--- autofs-5.0.2.orig/daemon/direct.c ++++ autofs-5.0.2/daemon/direct.c +@@ -35,8 +35,6 @@ + #include + #include + #include +-#include +-#include + + #include "automount.h" + +@@ -1237,15 +1235,6 @@ static void *do_mount_direct(void *arg) + { + struct pending_args *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; + +@@ -1291,126 +1280,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. +- */ +- +- 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(tsv->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->home) { +- 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(tsv->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); +- } ++ set_tsd_user_vars(ap->logopt, mt.uid, mt.gid); + +-cont: + status = lookup_nss_mount(ap, NULL, mt.name, mt.len); + /* + * Direct mounts are always a single mount. If it fails there's +--- autofs-5.0.2.orig/daemon/indirect.c ++++ autofs-5.0.2/daemon/indirect.c +@@ -33,8 +33,6 @@ + #include + #include + #include +-#include +-#include + + #include "automount.h" + +@@ -672,15 +670,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; + + args = (struct pending_args *) arg; + +@@ -722,125 +712,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. +- */ +- +- 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(tsv->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->home) { +- 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(tsv->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; +- } ++ set_tsd_user_vars(ap->logopt, mt.uid, mt.gid); + +- 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) { +--- autofs-5.0.2.orig/include/automount.h ++++ autofs-5.0.2/include/automount.h +@@ -28,6 +28,7 @@ + #include "macros.h" + #include "log.h" + #include "rpc_subs.h" ++#include "mounts.h" + #include "parse_subs.h" + + #ifdef WITH_DMALLOC +@@ -323,61 +324,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); +-char *find_mnt_ino(const char *table, dev_t dev, ino_t ino); +-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); +- + /* Core automount definitions */ + + #define MNT_DETACH 0x00000002 /* Just detach from the tree */ +--- /dev/null ++++ autofs-5.0.2/include/mounts.h +@@ -0,0 +1,91 @@ ++/* ----------------------------------------------------------------------- * ++ * ++ * 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_ANY 0x0000 ++#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, 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); ++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 *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); ++void set_tsd_user_vars(unsigned int, uid_t, gid_t); ++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 +--- autofs-5.0.2.orig/include/parse_subs.h ++++ autofs-5.0.2/include/parse_subs.h +@@ -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 +--- autofs-5.0.2.orig/lib/mounts.c ++++ autofs-5.0.2/lib/mounts.c +@@ -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)"; +@@ -119,7 +128,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; +@@ -462,51 +471,6 @@ int has_fstab_option(const char *opt) + return ret; + } + +-char *find_mnt_ino(const char *table, dev_t dev, ino_t ino) +-{ +- struct mntent mnt_wrk; +- struct mntent *mnt; +- char buf[PATH_MAX * 3]; +- char *path = NULL; +- unsigned long l_dev = (unsigned long) dev; +- unsigned long l_ino = (unsigned long) ino; +- FILE *tab; +- +- tab = setmntent(table, "r"); +- if (!tab) { +- char *estr = strerror_r(errno, buf, (size_t) PATH_MAX - 1); +- logerr("setmntent: %s", estr); +- return 0; +- } +- +- 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) +- 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); +- break; +- } +- } +- endmntent(tab); +- +- return path; +-} +- + char *get_offset(const char *prefix, char *offset, + struct list_head *head, struct list_head **pos) + { +@@ -982,3 +946,355 @@ int tree_is_mounted(struct mnt_list *mnt + return mounted; + } + ++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->home) { ++ 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; ++} ++ ++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 ret, 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 || !oe->mapent) ++ goto cont; ++ ++ debug(ap->logopt, "mount offset %s", oe->key); ++ ++ ret = mount_autofs_offset(ap, oe); ++ if (ret >= MOUNT_OFFSET_OK) ++ mounted++; ++ else { ++ if (ret != MOUNT_OFFSET_IGNORE) ++ warn(ap->logopt, "failed to mount offset"); ++ else { ++ debug(ap->logopt, ++ "ignoring \"nohide\" trigger %s", ++ oe->key); ++ free(oe->mapent); ++ oe->mapent = NULL; ++ } ++ } ++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 || !oe->mapent || (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 || !oe->mapent || (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, "/") < 0) ++ 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; ++} ++ +--- autofs-5.0.2.orig/lib/parse_subs.c ++++ autofs-5.0.2/lib/parse_subs.c +@@ -18,10 +18,7 @@ + #include + #include + #include +-#include +-#include + #include +-#include + #include "automount.h" + + /* +@@ -304,230 +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 ret, 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 || !oe->mapent) +- goto cont; +- +- debug(ap->logopt, "mount offset %s", oe->key); +- +- ret = mount_autofs_offset(ap, oe); +- if (ret >= MOUNT_OFFSET_OK) +- mounted++; +- else { +- if (ret != MOUNT_OFFSET_IGNORE) +- warn(ap->logopt, "failed to mount offset"); +- else { +- debug(ap->logopt, +- "ignoring \"nohide\" trigger %s", +- oe->key); +- free(oe->mapent); +- oe->mapent = NULL; +- } +- } +-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 || !oe->mapent || (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 || !oe->mapent || (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, "/") < 0) +- 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 --git a/autofs-5.0.3-remove-redundant-dns-name-lookups.patch b/autofs-5.0.3-remove-redundant-dns-name-lookups.patch new file mode 100644 index 0000000..553f6ee --- /dev/null +++ b/autofs-5.0.3-remove-redundant-dns-name-lookups.patch @@ -0,0 +1,218 @@ +autofs-5.0.3 - eliminate redundant DNS name lookups + +From: Ian Kent + +When autofs tries to lookup a DNS host name where one or more DNS +servers aren't available the mount can take a long time. This is +caused by autofs doing the name lookups more often than it needs +to. This patch removes a number of these redundant name lookups. +--- + + include/replicated.h | 1 + + include/rpc_subs.h | 4 +++- + lib/rpc_subs.c | 22 ++++++++++++++++++++-- + modules/replicated.c | 25 +++++++++++++++++++------ + 4 files changed, 43 insertions(+), 9 deletions(-) + + +--- autofs-5.0.2.orig/include/replicated.h ++++ autofs-5.0.2/include/replicated.h +@@ -52,6 +52,7 @@ + struct host { + char *name; + char *addr; ++ size_t addr_len; + char *path; + unsigned int version; + unsigned int proximity; +--- autofs-5.0.2.orig/include/rpc_subs.h ++++ autofs-5.0.2/include/rpc_subs.h +@@ -46,6 +46,8 @@ + + struct conn_info { + const char *host; ++ const char *addr; ++ size_t addr_len; + unsigned short port; + unsigned long program; + unsigned long version; +@@ -61,7 +63,7 @@ int rpc_udp_getclient(struct conn_info * + void rpc_destroy_udp_client(struct conn_info *); + int rpc_tcp_getclient(struct conn_info *, unsigned int, unsigned int); + void rpc_destroy_tcp_client(struct conn_info *); +-int rpc_portmap_getclient(struct conn_info *, const char *, const char *, unsigned int); ++int rpc_portmap_getclient(struct conn_info *, const char *, const char *, size_t, const char *, unsigned int); + unsigned short rpc_portmap_getport(struct conn_info *, struct pmap *); + int rpc_ping_proto(struct conn_info *); + int rpc_ping(const char *, long, long, unsigned int); +--- autofs-5.0.2.orig/lib/rpc_subs.c ++++ autofs-5.0.2/lib/rpc_subs.c +@@ -86,6 +86,11 @@ static CLIENT *create_udp_client(struct + memset(&raddr, 0, sizeof(raddr)); + + raddr.sin_family = AF_INET; ++ if (info->addr) { ++ memcpy(&raddr.sin_addr.s_addr, info->addr, info->addr_len); ++ goto got_addr; ++ } ++ + if (inet_aton(info->host, &raddr.sin_addr)) + goto got_addr; + +@@ -295,6 +300,11 @@ static CLIENT *create_tcp_client(struct + memset(&addr, 0, sizeof(addr)); + + addr.sin_family = AF_INET; ++ if (info->addr) { ++ memcpy(&addr.sin_addr.s_addr, info->addr, info->addr_len); ++ goto got_addr; ++ } ++ + if (inet_aton(info->host, &addr.sin_addr)) + goto got_addr; + +@@ -407,8 +417,8 @@ void rpc_destroy_tcp_client(struct conn_ + } + + int rpc_portmap_getclient(struct conn_info *info, +- const char *host, const char *proto, +- unsigned int option) ++ const char *host, const char *addr, size_t addr_len, ++ const char *proto, unsigned int option) + { + struct protoent *pe_proto; + CLIENT *client; +@@ -418,6 +428,8 @@ int rpc_portmap_getclient(struct conn_in + return 0; + + info->host = host; ++ info->addr = addr; ++ info->addr_len = addr_len; + info->program = PMAPPROG; + info->port = PMAPPORT; + info->version = PMAPVERS; +@@ -462,6 +474,8 @@ unsigned short rpc_portmap_getport(struc + client = info->client; + else { + pmap_info.host = info->host; ++ pmap_info.addr = info->addr; ++ pmap_info.addr_len = info->addr_len; + pmap_info.port = PMAPPORT; + pmap_info.program = PMAPPROG; + pmap_info.version = PMAPVERS; +@@ -589,6 +603,8 @@ static unsigned int __rpc_ping(const cha + struct pmap parms; + + info.host = host; ++ info.addr = NULL; ++ info.addr_len = 0; + info.program = NFS_PROGRAM; + info.version = version; + info.send_sz = 0; +@@ -769,6 +785,8 @@ exports rpc_get_exports(const char *host + int status; + + info.host = host; ++ info.addr = NULL; ++ info.addr_len = 0; + info.program = MOUNTPROG; + info.version = MOUNTVERS; + info.send_sz = 0; +--- autofs-5.0.2.orig/modules/replicated.c ++++ autofs-5.0.2/modules/replicated.c +@@ -225,7 +225,9 @@ static unsigned int get_proximity(const + return PROXIMITY_OTHER; + } + +-static struct host *new_host(const char *name, const char *addr, unsigned int proximity, unsigned int weight) ++static struct host *new_host(const char *name, ++ const char *addr, size_t addr_len, ++ unsigned int proximity, unsigned int weight) + { + struct host *new; + char *tmp1, *tmp2; +@@ -237,11 +239,12 @@ static struct host *new_host(const char + if (!tmp1) + return NULL; + +- tmp2 = strdup(addr); ++ tmp2 = malloc(addr_len); + if (!tmp2) { + free(tmp1); + return NULL; + } ++ memcpy(tmp2, addr, addr_len); + + new = malloc(sizeof(struct host)); + if (!new) { +@@ -253,6 +256,7 @@ static struct host *new_host(const char + memset(new, 0, sizeof(struct host)); + + new->name = tmp1; ++ new->addr_len = addr_len; + new->addr = tmp2; + new->proximity = proximity; + new->weight = weight; +@@ -437,7 +441,8 @@ static unsigned int get_nfs_info(unsigne + v3_ver: + if (!have_port_opt) { + status = rpc_portmap_getclient(pm_info, +- host->name, proto, RPC_CLOSE_DEFAULT); ++ host->name, host->addr, host->addr_len, ++ proto, RPC_CLOSE_DEFAULT); + if (!status) + goto done_ver; + } +@@ -551,6 +556,8 @@ static int get_vers_and_cost(unsigned lo + timeout = RPC_TIMEOUT * 8; + + rpc_info.host = host->name; ++ rpc_info.addr = host->addr; ++ rpc_info.addr_len = host->addr_len; + rpc_info.program = NFS_PROGRAM; + rpc_info.timeout.tv_sec = timeout; + rpc_info.close_option = RPC_CLOSE_DEFAULT; +@@ -606,6 +613,8 @@ static int get_supported_ver_and_cost(un + timeout = RPC_TIMEOUT * 8; + + rpc_info.host = host->name; ++ rpc_info.addr = host->addr; ++ rpc_info.addr_len = host->addr_len; + rpc_info.program = NFS_PROGRAM; + rpc_info.timeout.tv_sec = timeout; + rpc_info.close_option = RPC_CLOSE_DEFAULT; +@@ -652,7 +661,8 @@ static int get_supported_ver_and_cost(un + return 0; + } else { + int ret = rpc_portmap_getclient(&pm_info, +- host->name, proto, RPC_CLOSE_DEFAULT); ++ host->name, host->addr, host->addr_len, ++ proto, RPC_CLOSE_DEFAULT); + if (!ret) + return 0; + +@@ -868,7 +878,7 @@ static int add_host_addrs(struct host ** + if (prx == PROXIMITY_ERROR) + return 0; + +- if (!(new = new_host(host, thost, prx, weight))) ++ if (!(new = new_host(host, thost, sizeof(saddr.sin_addr), prx, weight))) + return 0; + + if (!add_host(list, new)) +@@ -891,11 +901,14 @@ static int add_host_addrs(struct host ** + } + + for (haddr = phe->h_addr_list; *haddr; haddr++) { ++ struct in_addr tt; ++ + prx = get_proximity(*haddr, phe->h_length); + if (prx == PROXIMITY_ERROR) + return 0; + +- if (!(new = new_host(host, *haddr, prx, weight))) ++ memcpy(&tt, *haddr, sizeof(struct in_addr)); ++ if (!(new = new_host(host, *haddr, phe->h_length, prx, weight))) + return 0; + + if (!add_host(list, new)) { diff --git a/autofs-5.0.3-submount-shutdown-recovery-12-fix.patch b/autofs-5.0.3-submount-shutdown-recovery-12-fix.patch new file mode 100644 index 0000000..a59f3ab --- /dev/null +++ b/autofs-5.0.3-submount-shutdown-recovery-12-fix.patch @@ -0,0 +1,32 @@ +autofs-5.0.3 - submount shutdown recovery fix + +From: Ian Kent + +I was sure I fixed this in the final patch but evidently +not. +--- + + daemon/direct.c | 2 -- + 1 files changed, 0 insertions(+), 2 deletions(-) + + +diff --git a/daemon/direct.c b/daemon/direct.c +index 34e882b..afb354e 100644 +--- a/daemon/direct.c ++++ b/daemon/direct.c +@@ -1129,7 +1129,6 @@ int handle_packet_expire_direct(struct autofs_point *ap, autofs_packet_expire_di + */ + crit(ap->logopt, "can't find map entry for (%lu,%lu)", + (unsigned long) pkt->dev, (unsigned long) pkt->ino); +- cache_unlock(mc); + master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + return 1; +@@ -1374,7 +1373,6 @@ int handle_packet_missing_direct(struct autofs_point *ap, autofs_packet_missing_ + */ + logerr("can't find map entry for (%lu,%lu)", + (unsigned long) pkt->dev, (unsigned long) pkt->ino); +- cache_unlock(mc); + master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + return 1; diff --git a/autofs-5.0.3-submount-shutdown-recovery-12.patch b/autofs-5.0.3-submount-shutdown-recovery-12.patch new file mode 100644 index 0000000..8822888 --- /dev/null +++ b/autofs-5.0.3-submount-shutdown-recovery-12.patch @@ -0,0 +1,1890 @@ +autofs-5.0.3 - fix submount shutdown handling. + +From: Ian Kent + +When using submount maps on a busy system autofs can hang. + +This problem comes about because of processes walking into the +submount filesystem when it is in the process of shutting down. +While this race has been fixed for other types of mounts it +still isn't possible to to block processes from walking into +submounts that are expiring so we need to be able to recover +when this happens. + +This patch improves the submount shutdown logic and allows +submounts that become busy during shutdown to recover. +--- + + daemon/automount.c | 208 +++++++++++++++++++------------------------ + daemon/direct.c | 97 ++++++++++++++------ + daemon/indirect.c | 114 ++++++++++++++++++----- + daemon/lookup.c | 11 -- + daemon/state.c | 235 +++++++++++++++++++++++++++++++++---------------- + include/automount.h | 17 --- + include/master.h | 5 - + include/state.h | 9 + + lib/alarm.c | 14 -- + lib/master.c | 182 +++++++------------------------------ + modules/mount_autofs.c | 2 + 11 files changed, 458 insertions(+), 436 deletions(-) + + +--- autofs-5.0.2.orig/daemon/automount.c ++++ autofs-5.0.2/daemon/automount.c +@@ -369,6 +369,18 @@ int count_mounts(unsigned logopt, const + + static void check_rm_dirs(struct autofs_point *ap, const char *path, int incl) + { ++ /* ++ * If we're a submount the kernel can't know we're trying to ++ * shutdown and so cannot block processes walking into the ++ * mount point directory. If this is the call to umount_multi() ++ * made during shutdown (incl == 0) we have to leave any mount ++ * point directories in place so we can recover if needed. The ++ * umount itself will clean these directories up for us ++ * automagically. ++ */ ++ if (!incl && ap->submount) ++ return; ++ + if ((!ap->ghost) || + (ap->state == ST_SHUTDOWN_PENDING || + ap->state == ST_SHUTDOWN_FORCE || +@@ -390,8 +402,6 @@ static void update_map_cache(struct auto + else + key = path; + +- pthread_cleanup_push(master_source_lock_cleanup, ap->entry); +- master_source_readlock(ap->entry); + map = ap->entry->maps; + while (map) { + struct mapent *me = NULL; +@@ -413,7 +423,6 @@ static void update_map_cache(struct auto + + map = map->next; + } +- pthread_cleanup_pop(1); + + return; + } +@@ -918,38 +927,22 @@ static int get_pkt(struct autofs_point * + } + + if (fds[1].revents & POLLIN) { +- enum states next_state, post_state; ++ enum states next_state; + size_t read_size = sizeof(next_state); + int state_pipe; + +- next_state = post_state = ST_INVAL; ++ next_state = ST_INVAL; + +- state_mutex_lock(ap); ++ st_mutex_lock(); + + state_pipe = ap->state_pipe[0]; + + if (fullread(state_pipe, &next_state, read_size)) { +- state_mutex_unlock(ap); ++ st_mutex_unlock(); + continue; + } + +- if (next_state != ST_INVAL && next_state != ap->state) { +- if (next_state != ST_SHUTDOWN) +- post_state = next_state; +- else +- ap->state = ST_SHUTDOWN; +- } +- +- state_mutex_unlock(ap); +- +- if (post_state != ST_INVAL) { +- if (post_state == ST_SHUTDOWN_PENDING || +- post_state == ST_SHUTDOWN_FORCE) { +- alarm_delete(ap); +- st_remove_tasks(ap); +- } +- st_add_task(ap, post_state); +- } ++ st_mutex_unlock(); + + if (next_state == ST_SHUTDOWN) + return -1; +@@ -985,11 +978,14 @@ int do_expire(struct autofs_point *ap, c + + info(ap->logopt, "expiring path %s", buf); + ++ pthread_cleanup_push(master_source_lock_cleanup, ap->entry); ++ master_source_readlock(ap->entry); + ret = umount_multi(ap, buf, 1); + if (ret == 0) + info(ap->logopt, "expired %s", buf); + else + warn(ap->logopt, "couldn't complete expire of %s", buf); ++ pthread_cleanup_pop(1); + + return ret; + } +@@ -1069,7 +1065,7 @@ static int mount_autofs(struct autofs_po + if (status < 0) + return -1; + +- ap->state = ST_READY; ++ st_add_task(ap, ST_READY); + + return 0; + } +@@ -1423,44 +1419,6 @@ static void return_start_status(void *ar + fatal(status); + } + +-static void mutex_operation_wait(pthread_mutex_t *mutex) +-{ +- int status; +- +- /* +- * Unlock a mutex, but wait for a pending operation +- * if one is in progress +- */ +- status = pthread_mutex_trylock(mutex); +- if (status) { +- if (status == EBUSY) { +- /* Mutex locked - do we own it */ +- status = pthread_mutex_unlock(mutex); +- if (status) { +- if (status != EPERM) +- fatal(status); +- } else +- return; +- +- status = pthread_mutex_lock(mutex); +- if (status) +- fatal(status); +- } else +- fatal(status); +- +- /* Operation complete, release it */ +- status = pthread_mutex_unlock(mutex); +- if (status) +- fatal(status); +- } else { +- status = pthread_mutex_unlock(mutex); +- if (status) +- fatal(status); +- } +- +- return; +-} +- + int handle_mounts_startup_cond_init(struct startup_cond *suc) + { + int status; +@@ -1526,22 +1484,25 @@ static void handle_mounts_cleanup(void * + if (!submount && strcmp(ap->path, "/-") && ap->dir_created) + clean = 1; + +- /* If we have been canceled then we may hold the state mutex. */ +- mutex_operation_wait(&ap->state_mutex); ++ if (submount) { ++ /* We are finishing up */ ++ ap->parent->submnt_count--; ++ list_del_init(&ap->mounts); ++ } + +- alarm_delete(ap); +- st_remove_tasks(ap); ++ master_remove_mapent(ap->entry); ++ master_source_unlock(ap->entry); + +- umount_autofs(ap, 1); ++ if (submount) { ++ mounts_mutex_unlock(ap->parent); ++ master_source_unlock(ap->parent->entry); ++ } ++ master_mutex_unlock(); + + destroy_logpri_fifo(ap); +- master_signal_submount(ap, MASTER_SUBMNT_JOIN); +- master_remove_mapent(ap->entry); + master_free_mapent_sources(ap->entry, 1); + master_free_mapent(ap->entry); + +- sched_yield(); +- + if (clean) { + if (rmdir(path) == -1) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); +@@ -1572,8 +1533,6 @@ void *handle_mounts(void *arg) + pthread_cleanup_push(return_start_status, suc); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); + +- state_mutex_lock(ap); +- + status = pthread_mutex_lock(&suc->mutex); + if (status) { + logerr("failed to lock startup condition mutex!"); +@@ -1583,7 +1542,6 @@ void *handle_mounts(void *arg) + if (mount_autofs(ap) < 0) { + crit(ap->logopt, "mount of %s failed!", ap->path); + suc->status = 1; +- state_mutex_unlock(ap); + umount_autofs(ap, 1); + pthread_setcancelstate(cancel_state, NULL); + pthread_exit(NULL); +@@ -1600,56 +1558,70 @@ void *handle_mounts(void *arg) + if (!ap->submount && ap->exp_timeout) + alarm_add(ap, ap->exp_runfreq + rand() % ap->exp_runfreq); + +- pthread_cleanup_push(handle_mounts_cleanup, ap); + pthread_setcancelstate(cancel_state, NULL); + +- state_mutex_unlock(ap); +- + while (ap->state != ST_SHUTDOWN) { + if (handle_packet(ap)) { +- int ret, result; ++ int ret, cur_state; ++ ++ /* ++ * If we're a submount we need to ensure our parent ++ * doesn't try to mount us again until our shutdown ++ * is complete and that any outstanding mounts are ++ * completed before we try to shutdown. ++ */ ++ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); ++ ++ master_mutex_lock(); ++ ++ if (ap->submount) { ++ master_source_writelock(ap->parent->entry); ++ mounts_mutex_lock(ap->parent); ++ } ++ ++ master_source_writelock(ap->entry); ++ ++ if (ap->state != ST_SHUTDOWN) { ++ if (!ap->submount) ++ alarm_add(ap, ap->exp_runfreq); ++ /* Return to ST_READY is done immediately */ ++ st_add_task(ap, ST_READY); ++ master_source_unlock(ap->entry); ++ if (ap->submount) { ++ mounts_mutex_unlock(ap->parent); ++ master_source_unlock(ap->parent->entry); ++ } ++ ++ master_mutex_unlock(); ++ ++ pthread_setcancelstate(cur_state, NULL); ++ continue; ++ } ++ ++ alarm_delete(ap); ++ st_remove_tasks(ap); ++ st_wait_task(ap, ST_ANY, 0); + +- state_mutex_lock(ap); + /* + * For a direct mount map all mounts have already gone +- * by the time we get here. ++ * by the time we get here and since we only ever ++ * umount direct mounts at shutdown there is no need ++ * to check for possible recovery. + */ + if (ap->type == LKP_DIRECT) { +- status = 1; +- state_mutex_unlock(ap); ++ umount_autofs(ap, 1); + break; + } + + /* +- * If the ioctl fails assume the kernel doesn't have +- * AUTOFS_IOC_ASKUMOUNT and just continue. ++ * If umount_autofs returns non-zero it wasn't able ++ * to complete the umount and has left the mount intact ++ * so we can continue. This can happen if a lookup ++ * occurs while we're trying to umount. + */ +- ret = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &result); +- if (ret == -1) { +- state_mutex_unlock(ap); ++ ret = umount_autofs(ap, 1); ++ if (!ret) + break; +- } +- +- /* OK to exit */ +- if (ap->state == ST_SHUTDOWN) { +- if (result) { +- state_mutex_unlock(ap); +- break; +- } +-#ifdef ENABLE_IGNORE_BUSY_MOUNTS +- /* +- * There weren't any active mounts but if the +- * filesystem is busy there may be a mount +- * request in progress so return to the ready +- * state unless a shutdown has been explicitly +- * requested. +- */ +- if (ap->shutdown) { +- state_mutex_unlock(ap); +- break; +- } +-#endif +- } + + /* Failed shutdown returns to ready */ + warn(ap->logopt, +@@ -1657,14 +1629,22 @@ void *handle_mounts(void *arg) + ap->path); + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); +- nextstate(ap->state_pipe[1], ST_READY); ++ /* Return to ST_READY is done immediately */ ++ st_add_task(ap, ST_READY); ++ master_source_unlock(ap->entry); ++ if (ap->submount) { ++ mounts_mutex_unlock(ap->parent); ++ master_source_unlock(ap->parent->entry); ++ } ++ ++ master_mutex_unlock(); ++ ++ pthread_setcancelstate(cur_state, NULL); + +- state_mutex_unlock(ap); + } + } + +- pthread_cleanup_pop(1); +- sched_yield(); ++ handle_mounts_cleanup(ap); + + return NULL; + } +--- autofs-5.0.2.orig/daemon/direct.c ++++ autofs-5.0.2/daemon/direct.c +@@ -216,8 +216,6 @@ int umount_autofs_direct(struct autofs_p + + mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/"); + pthread_cleanup_push(mnts_cleanup, mnts); +- pthread_cleanup_push(master_source_lock_cleanup, ap->entry); +- master_source_readlock(ap->entry); + nc = ap->entry->master->nc; + cache_readlock(nc); + pthread_cleanup_push(cache_lock_cleanup, nc); +@@ -244,7 +242,6 @@ int umount_autofs_direct(struct autofs_p + } + pthread_cleanup_pop(1); + pthread_cleanup_pop(1); +- pthread_cleanup_pop(1); + + return 0; + } +@@ -572,9 +569,10 @@ int umount_autofs_offset(struct autofs_p + return 1; + } else if (!status) { + if (ap->state != ST_SHUTDOWN_FORCE) { +- error(ap->logopt, +- "ask umount returned busy for %s", +- me->key); ++ if (ap->shutdown) ++ error(ap->logopt, ++ "ask umount returned busy for %s", ++ me->key); + return 1; + } else { + me->ioctlfd = -1; +@@ -904,7 +902,10 @@ void *expire_proc_direct(void *arg) + * All direct mounts must be present in the map + * entry cache. + */ ++ pthread_cleanup_push(master_source_lock_cleanup, ap->entry); ++ master_source_readlock(ap->entry); + me = lookup_source_mapent(ap, next->path, LKP_DISTINCT); ++ pthread_cleanup_pop(1); + if (!me) + continue; + +@@ -1110,6 +1111,8 @@ int handle_packet_expire_direct(struct a + struct pending_args *mt; + char buf[MAX_ERR_BUF]; + pthread_t thid; ++ struct timespec wait; ++ struct timeval now; + int status, state; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); +@@ -1124,7 +1127,7 @@ int handle_packet_expire_direct(struct a + * and since it got mounted we have to trust that + * there is an entry in the cache. + */ +- master_source_readlock(ap->entry); ++ master_source_writelock(ap->entry); + map = ap->entry->maps; + while (map) { + mc = map->mc; +@@ -1135,7 +1138,6 @@ int handle_packet_expire_direct(struct a + cache_unlock(mc); + map = map->next; + } +- master_source_unlock(ap->entry); + + if (!me) { + /* +@@ -1144,10 +1146,28 @@ int handle_packet_expire_direct(struct a + */ + crit(ap->logopt, "can't find map entry for (%lu,%lu)", + (unsigned long) pkt->dev, (unsigned long) pkt->ino); ++ cache_unlock(mc); ++ master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + return 1; + } + ++ /* Can't expire it if it isn't mounted */ ++ if (me->ioctlfd == -1) { ++ int ioctlfd = open(me->key, O_RDONLY); ++ if (ioctlfd == -1) { ++ crit(ap->logopt, "can't open ioctlfd for %s", ++ me->key); ++ pthread_setcancelstate(state, NULL); ++ return 1; ++ } ++ send_ready(ap->logopt, ioctlfd, pkt->wait_queue_token); ++ close(ioctlfd); ++ cache_unlock(mc); ++ master_source_unlock(ap->entry); ++ pthread_setcancelstate(state, NULL); ++ return 0; ++ } + + mt = malloc(sizeof(struct pending_args)); + if (!mt) { +@@ -1155,6 +1175,7 @@ int handle_packet_expire_direct(struct a + error(ap->logopt, "malloc: %s", estr); + send_fail(ap->logopt, me->ioctlfd, pkt->wait_queue_token); + cache_unlock(mc); ++ master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + return 1; + } +@@ -1184,6 +1205,7 @@ int handle_packet_expire_direct(struct a + error(ap->logopt, "expire thread create failed"); + send_fail(ap->logopt, mt->ioctlfd, pkt->wait_queue_token); + cache_unlock(mc); ++ master_source_unlock(ap->entry); + expire_mutex_unlock(NULL); + pending_cond_destroy(mt); + free_pending_args(mt); +@@ -1192,14 +1214,18 @@ int handle_packet_expire_direct(struct a + } + + cache_unlock(mc); ++ master_source_unlock(ap->entry); + + pthread_cleanup_push(expire_mutex_unlock, NULL); + pthread_setcancelstate(state, NULL); + + mt->signaled = 0; + while (!mt->signaled) { ++ gettimeofday(&now, NULL); ++ wait.tv_sec = now.tv_sec + 2; ++ wait.tv_nsec = now.tv_usec * 1000; + status = pthread_cond_wait(&mt->cond, &ea_mutex); +- if (status) ++ if (status && status != ETIMEDOUT) + fatal(status); + } + +@@ -1263,6 +1289,9 @@ static void *do_mount_direct(void *arg) + if (status == -1) { + error(ap->logopt, + "can't stat direct mount trigger %s", mt.name); ++ send_fail(ap->logopt, ++ mt.ioctlfd, mt.wait_queue_token); ++ close(mt.ioctlfd); + pthread_setcancelstate(state, NULL); + pthread_exit(NULL); + } +@@ -1272,6 +1301,8 @@ static void *do_mount_direct(void *arg) + error(ap->logopt, + "direct trigger not valid or already mounted %s", + mt.name); ++ send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); ++ close(mt.ioctlfd); + pthread_setcancelstate(state, NULL); + pthread_exit(NULL); + } +@@ -1290,19 +1321,12 @@ static void *do_mount_direct(void *arg) + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + if (status) { + struct mapent *me; +- int real_mount, set_fd; +- cache_readlock(mt.mc); ++ cache_writelock(mt.mc); + me = cache_lookup_distinct(mt.mc, mt.name); +- real_mount = is_mounted(_PATH_MOUNTED, me->key, MNTS_REAL); +- set_fd = (real_mount || me->multi == me); +- cache_unlock(mt.mc); +- if (set_fd) { ++ if (me) + me->ioctlfd = mt.ioctlfd; +- send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); +- } else { +- send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); +- close(mt.ioctlfd); +- } ++ send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token); ++ cache_unlock(mt.mc); + info(ap->logopt, "mounted %s", mt.name); + } else { + send_fail(ap->logopt, mt.ioctlfd, mt.wait_queue_token); +@@ -1325,11 +1349,21 @@ int handle_packet_missing_direct(struct + struct pending_args *mt; + char buf[MAX_ERR_BUF]; + int status = 0; ++ struct timespec wait; ++ struct timeval now; + int ioctlfd, len, cl_flags, state; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); + +- master_source_readlock(ap->entry); ++ /* ++ * If our parent is a direct or offset mount that has been ++ * covered by a mount and another lookup occurs after the ++ * mount but before the device and inode are set in the ++ * cache entry we will not be able to find the mapent. So ++ * we must take the source writelock to ensure the parent ++ * has mount is complete before we look for the entry. ++ */ ++ master_source_writelock(ap->entry); + map = ap->entry->maps; + while (map) { + /* +@@ -1349,7 +1383,6 @@ int handle_packet_missing_direct(struct + cache_unlock(mc); + map = map->next; + } +- master_source_unlock(ap->entry); + + if (!me) { + /* +@@ -1358,6 +1391,8 @@ int handle_packet_missing_direct(struct + */ + logerr("can't find map entry for (%lu,%lu)", + (unsigned long) pkt->dev, (unsigned long) pkt->ino); ++ cache_unlock(mc); ++ master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + return 1; + } +@@ -1371,6 +1406,7 @@ int handle_packet_missing_direct(struct + + if (ioctlfd == -1) { + cache_unlock(mc); ++ master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + crit(ap->logopt, "failed to create ioctl fd for %s", me->key); + /* TODO: how do we clear wait q in kernel ?? */ +@@ -1386,12 +1422,11 @@ int handle_packet_missing_direct(struct + (unsigned long) pkt->wait_queue_token, me->key, pkt->pid); + + /* Ignore packet if we're trying to shut down */ +- if (ap->shutdown || +- ap->state == ST_SHUTDOWN_FORCE || +- ap->state == ST_SHUTDOWN) { ++ if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) { + send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); + close(ioctlfd); + cache_unlock(mc); ++ master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + return 1; + } +@@ -1402,6 +1437,7 @@ int handle_packet_missing_direct(struct + send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); + close(ioctlfd); + cache_unlock(mc); ++ master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + return 1; + } +@@ -1413,6 +1449,7 @@ int handle_packet_missing_direct(struct + send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); + close(ioctlfd); + cache_unlock(mc); ++ master_source_unlock(ap->entry); + pthread_setcancelstate(state, NULL); + return 1; + } +@@ -1447,6 +1484,7 @@ int handle_packet_missing_direct(struct + send_fail(ap->logopt, ioctlfd, pkt->wait_queue_token); + close(ioctlfd); + cache_unlock(mc); ++ master_source_unlock(ap->entry); + mount_mutex_unlock(mt); + pending_cond_destroy(mt); + pending_mutex_destroy(mt); +@@ -1456,6 +1494,8 @@ int handle_packet_missing_direct(struct + } + + cache_unlock(mc); ++ master_source_unlock(ap->entry); ++ + pthread_cleanup_push(free_pending_args, mt); + pthread_cleanup_push(pending_mutex_destroy, mt); + pthread_cleanup_push(pending_cond_destroy, mt); +@@ -1464,8 +1504,11 @@ int handle_packet_missing_direct(struct + + mt->signaled = 0; + while (!mt->signaled) { +- status = pthread_cond_wait(&mt->cond, &mt->mutex); +- if (status) ++ gettimeofday(&now, NULL); ++ wait.tv_sec = now.tv_sec + 2; ++ wait.tv_nsec = now.tv_usec * 1000; ++ status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait); ++ if (status && status != ETIMEDOUT) + fatal(status); + } + +--- autofs-5.0.2.orig/daemon/indirect.c ++++ autofs-5.0.2/daemon/indirect.c +@@ -230,11 +230,8 @@ int mount_autofs_indirect(struct autofs_ + return 0; + } + +-int umount_autofs_indirect(struct autofs_point *ap) ++static void close_mount_fds(struct autofs_point *ap) + { +- char buf[MAX_ERR_BUF]; +- int ret, rv, retries; +- + /* + * Since submounts look after themselves the parent never knows + * it needs to close the ioctlfd for offset mounts so we have +@@ -244,6 +241,25 @@ int umount_autofs_indirect(struct autofs + if (ap->submount) + lookup_source_close_ioctlfd(ap->parent, ap->path); + ++ close(ap->state_pipe[0]); ++ close(ap->state_pipe[1]); ++ ap->state_pipe[0] = -1; ++ ap->state_pipe[1] = -1; ++ ++ if (ap->pipefd >= 0) ++ close(ap->pipefd); ++ ++ if (ap->kpipefd >= 0) ++ close(ap->kpipefd); ++ ++ return; ++} ++ ++int umount_autofs_indirect(struct autofs_point *ap) ++{ ++ char buf[MAX_ERR_BUF]; ++ int ret, rv, retries; ++ + /* If we are trying to shutdown make sure we can umount */ + rv = ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret); + if (rv == -1) { +@@ -251,24 +267,20 @@ int umount_autofs_indirect(struct autofs + logerr("ioctl failed: %s", estr); + return 1; + } else if (!ret) { ++#if defined(ENABLE_IGNORE_BUSY_MOUNTS) || defined(ENABLE_FORCED_SHUTDOWN) ++ if (!ap->shutdown) ++ return 1; + error(ap->logopt, "ask umount returned busy %s", ap->path); ++#else + return 1; ++#endif + } + +- ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0); ++ if (ap->shutdown) ++ ioctl(ap->ioctlfd, AUTOFS_IOC_CATATONIC, 0); ++ + close(ap->ioctlfd); + ap->ioctlfd = -1; +- close(ap->state_pipe[0]); +- close(ap->state_pipe[1]); +- ap->state_pipe[0] = -1; +- ap->state_pipe[1] = -1; +- +- if (ap->pipefd >= 0) +- close(ap->pipefd); +- +- if (ap->kpipefd >= 0) +- close(ap->kpipefd); +- + sched_yield(); + + retries = UMOUNT_RETRIES; +@@ -285,24 +297,61 @@ int umount_autofs_indirect(struct autofs + case EINVAL: + error(ap->logopt, + "mount point %s does not exist", ap->path); ++ close_mount_fds(ap); + return 0; + break; + case EBUSY: +- error(ap->logopt, ++ debug(ap->logopt, + "mount point %s is in use", ap->path); +- if (ap->state == ST_SHUTDOWN_FORCE) ++ if (ap->state == ST_SHUTDOWN_FORCE) { ++ close_mount_fds(ap); + goto force_umount; +- else +- return 0; ++ } else { ++ int cl_flags; ++ /* ++ * If the umount returns EBUSY there may be ++ * a mount request in progress so we need to ++ * recover unless we have been explicitly ++ * asked to shutdown and configure option ++ * ENABLE_IGNORE_BUSY_MOUNTS is enabled. ++ */ ++#ifdef ENABLE_IGNORE_BUSY_MOUNTS ++ if (ap->shutdown) { ++ close_mount_fds(ap); ++ return 0; ++ } ++#endif ++ ap->ioctlfd = open(ap->path, O_RDONLY); ++ if (ap->ioctlfd < 0) { ++ warn(ap->logopt, ++ "could not recover autofs path %s", ++ ap->path); ++ close_mount_fds(ap); ++ return 0; ++ } ++ ++ if ((cl_flags = fcntl(ap->ioctlfd, F_GETFD, 0)) != -1) { ++ cl_flags |= FD_CLOEXEC; ++ fcntl(ap->ioctlfd, F_SETFD, cl_flags); ++ } ++ } + break; + case ENOTDIR: + error(ap->logopt, "mount point is not a directory"); ++ close_mount_fds(ap); + return 0; + break; + } + return 1; + } + ++ /* ++ * We have successfully umounted the mount so we now close ++ * the descriptors. The kernel end of the kernel pipe will ++ * have been put during the umount super block cleanup. ++ */ ++ close_mount_fds(ap); ++ + force_umount: + if (rv != 0) { + warn(ap->logopt, +@@ -439,9 +488,12 @@ void *expire_proc_indirect(void *arg) + * Otherwise it's a top level indirect mount (possibly + * with offsets in it) and we use the usual ioctlfd. + */ ++ pthread_cleanup_push(master_source_lock_cleanup, ap->entry); ++ master_source_readlock(ap->entry); + me = lookup_source_mapent(ap, next->path, LKP_DISTINCT); + if (!me && ind_key) + me = lookup_source_mapent(ap, ind_key, LKP_NORMAL); ++ pthread_cleanup_pop(1); + if (!me) + continue; + +@@ -586,6 +638,8 @@ int handle_packet_expire_indirect(struct + struct pending_args *mt; + char buf[MAX_ERR_BUF]; + pthread_t thid; ++ struct timespec wait; ++ struct timeval now; + int status, state; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); +@@ -632,8 +686,11 @@ int handle_packet_expire_indirect(struct + + mt->signaled = 0; + while (!mt->signaled) { +- status = pthread_cond_wait(&mt->cond, &ea_mutex); +- if (status) ++ gettimeofday(&now, NULL); ++ wait.tv_sec = now.tv_sec + 2; ++ wait.tv_nsec = now.tv_usec * 1000; ++ status = pthread_cond_timedwait(&mt->cond, &ea_mutex, &wait); ++ if (status && status != ETIMEDOUT) + fatal(status); + } + +@@ -735,6 +792,8 @@ int handle_packet_missing_indirect(struc + pthread_t thid; + char buf[MAX_ERR_BUF]; + struct pending_args *mt; ++ struct timespec wait; ++ struct timeval now; + int status, state; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state); +@@ -743,9 +802,7 @@ int handle_packet_missing_indirect(struc + (unsigned long) pkt->wait_queue_token, pkt->name, pkt->pid); + + /* Ignore packet if we're trying to shut down */ +- if (ap->shutdown || +- ap->state == ST_SHUTDOWN_FORCE || +- ap->state == ST_SHUTDOWN) { ++ if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) { + send_fail(ap->logopt, ap->ioctlfd, pkt->wait_queue_token); + pthread_setcancelstate(state, NULL); + return 0; +@@ -802,8 +859,11 @@ int handle_packet_missing_indirect(struc + + mt->signaled = 0; + while (!mt->signaled) { +- status = pthread_cond_wait(&mt->cond, &mt->mutex); +- if (status) ++ gettimeofday(&now, NULL); ++ wait.tv_sec = now.tv_sec + 2; ++ wait.tv_nsec = now.tv_usec * 1000; ++ status = pthread_cond_timedwait(&mt->cond, &mt->mutex, &wait); ++ if (status && status != ETIMEDOUT) + fatal(status); + } + +--- autofs-5.0.2.orig/daemon/lookup.c ++++ autofs-5.0.2/daemon/lookup.c +@@ -935,16 +935,10 @@ void lookup_close_lookup(struct autofs_p + if (!map) + return; + +- /* +- * Make sure we don't kill the context if a mount +- * request has come in while were shutting down. +- */ +- master_source_writelock(ap->entry); + while (map) { + lookup_close_lookup_instances(map); + map = map->next; + } +- master_source_unlock(ap->entry); + + return; + } +@@ -1122,7 +1116,6 @@ struct mapent *lookup_source_mapent(stru + struct mapent_cache *mc; + struct mapent *me = NULL; + +- master_source_readlock(entry); + map = entry->maps; + while (map) { + mc = map->mc; +@@ -1136,7 +1129,6 @@ struct mapent *lookup_source_mapent(stru + cache_unlock(mc); + map = map->next; + } +- master_source_unlock(entry); + + return me; + } +@@ -1149,8 +1141,6 @@ int lookup_source_close_ioctlfd(struct a + struct mapent *me; + int ret = 0; + +- pthread_cleanup_push(master_source_lock_cleanup, entry); +- master_source_readlock(entry); + map = entry->maps; + while (map) { + mc = map->mc; +@@ -1168,7 +1158,6 @@ int lookup_source_close_ioctlfd(struct a + cache_unlock(mc); + map = map->next; + } +- pthread_cleanup_pop(1); + + return ret; + } +--- autofs-5.0.2.orig/daemon/state.c ++++ autofs-5.0.2/daemon/state.c +@@ -37,19 +37,19 @@ static LIST_HEAD(state_queue); + static void st_set_thid(struct autofs_point *, pthread_t); + static void st_set_done(struct autofs_point *ap); + +-#define st_mutex_lock() \ +-do { \ +- int status = pthread_mutex_lock(&mutex); \ +- if (status) \ +- fatal(status); \ +-} while (0) +- +-#define st_mutex_unlock() \ +-do { \ +- int status = pthread_mutex_unlock(&mutex); \ +- if (status) \ +- fatal(status); \ +-} while (0) ++void st_mutex_lock(void) ++{ ++ int status = pthread_mutex_lock(&mutex); ++ if (status) ++ fatal(status); ++} ++ ++void st_mutex_unlock(void) ++{ ++ int status = pthread_mutex_unlock(&mutex); ++ if (status) ++ fatal(status); ++} + + int do_mount_autofs_direct(struct autofs_point *, struct mnt_list *, struct mapent *); + +@@ -96,21 +96,19 @@ void expire_cleanup(void *arg) + pthread_t thid = pthread_self(); + struct expire_args *ec; + struct autofs_point *ap; +- int statefd, success; ++ int success; + enum states next = ST_INVAL; + + ec = (struct expire_args *) arg; + ap = ec->ap; + success = ec->status; + +- state_mutex_lock(ap); ++ st_mutex_lock(); + + debug(ap->logopt, + "got thid %lu path %s stat %d", + (unsigned long) thid, ap->path, success); + +- statefd = ap->state_pipe[1]; +- + /* Check to see if expire process finished */ + if (thid == ap->exp_thread) { + int rv, idle; +@@ -199,11 +197,11 @@ void expire_cleanup(void *arg) + } + + if (next != ST_INVAL) +- nextstate(statefd, next); ++ __st_add_task(ap, next); + + st_set_done(ap); + +- state_mutex_unlock(ap); ++ st_mutex_unlock(); + + return; + } +@@ -216,9 +214,6 @@ static unsigned int st_ready(struct auto + ap->shutdown = 0; + ap->state = ST_READY; + +- if (ap->submount) +- master_signal_submount(ap, MASTER_SUBMNT_CONTINUE); +- + return 1; + } + +@@ -333,18 +328,18 @@ static void do_readmap_cleanup(void *arg + ra = (struct readmap_args *) arg; + + ap = ra->ap; +- ap->readmap_thread = 0; + +- state_mutex_lock(ap); ++ st_mutex_lock(); + +- nextstate(ap->state_pipe[1], ST_READY); ++ ap->readmap_thread = 0; ++ st_ready(ap); + st_set_done(ap); + +- state_mutex_unlock(ap); +- + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); + ++ st_mutex_unlock(); ++ + free(ra); + + return; +@@ -499,10 +494,8 @@ static unsigned int st_readmap(struct au + ra = malloc(sizeof(struct readmap_args)); + if (!ra) { + error(ap->logopt, "failed to malloc reamap cond struct"); +- state_mutex_lock(ap); +- nextstate(ap->state_pipe[1], ST_READY); +- state_mutex_unlock(ap); + /* It didn't work: return to ready */ ++ st_ready(ap); + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); + return 0; +@@ -528,10 +521,8 @@ static unsigned int st_readmap(struct au + error(ap->logopt, "read map thread create failed"); + st_readmap_cleanup(ra); + free(ra); +- state_mutex_lock(ap); +- nextstate(ap->state_pipe[1], ST_READY); +- state_mutex_unlock(ap); + /* It didn't work: return to ready */ ++ st_ready(ap); + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); + return 0; +@@ -570,7 +561,7 @@ static unsigned int st_prepare_shutdown( + /* It didn't work: return to ready */ + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); +- nextstate(ap->state_pipe[1], ST_READY); ++ st_ready(ap); + return 0; + + case EXP_STARTED: +@@ -596,7 +587,7 @@ static unsigned int st_force_shutdown(st + /* It didn't work: return to ready */ + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); +- nextstate(ap->state_pipe[1], ST_READY); ++ st_ready(ap); + return 0; + + case EXP_STARTED: +@@ -605,6 +596,18 @@ static unsigned int st_force_shutdown(st + return 0; + } + ++static unsigned int st_shutdown(struct autofs_point *ap) ++{ ++ debug(ap->logopt, "state %d path %s", ap->state, ap->path); ++ ++ assert(ap->state == ST_SHUTDOWN_PENDING || ap->state == ST_SHUTDOWN_FORCE); ++ ++ ap->state = ST_SHUTDOWN; ++ nextstate(ap->state_pipe[1], ST_SHUTDOWN); ++ ++ return 0; ++} ++ + static unsigned int st_prune(struct autofs_point *ap) + { + debug(ap->logopt, "state %d path %s", ap->state, ap->path); +@@ -617,7 +620,7 @@ static unsigned int st_prune(struct auto + case EXP_PARTIAL: + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); +- nextstate(ap->state_pipe[1], ST_READY); ++ st_ready(ap); + return 0; + + case EXP_STARTED: +@@ -638,7 +641,7 @@ static unsigned int st_expire(struct aut + case EXP_PARTIAL: + if (!ap->submount) + alarm_add(ap, ap->exp_runfreq); +- nextstate(ap->state_pipe[1], ST_READY); ++ st_ready(ap); + return 0; + + case EXP_STARTED: +@@ -665,43 +668,35 @@ static struct state_queue *st_alloc_task + return task; + } + +-/* Insert alarm entry on ordered list. */ +-int st_add_task(struct autofs_point *ap, enum states state) ++/* ++ * Insert alarm entry on ordered list. ++ * State queue mutex and ap state mutex, in that order, must be held. ++ */ ++int __st_add_task(struct autofs_point *ap, enum states state) + { + struct list_head *head; + struct list_head *p, *q; + struct state_queue *new; +- enum states ap_state; + unsigned int empty = 1; + int status; + + /* Task termination marker, poke state machine */ + if (state == ST_READY) { +- state_mutex_lock(ap); + st_ready(ap); +- state_mutex_unlock(ap); +- +- st_mutex_lock(); + + signaled = 1; + status = pthread_cond_signal(&cond); + if (status) + fatal(status); + +- st_mutex_unlock(); +- + return 1; + } + +- state_mutex_lock(ap); +- ap_state = ap->state; +- if (ap_state == ST_SHUTDOWN) { +- state_mutex_unlock(ap); ++ if (ap->state == ST_SHUTDOWN) + return 1; +- } +- state_mutex_unlock(ap); + +- st_mutex_lock(); ++ if (state == ST_SHUTDOWN) ++ return st_shutdown(ap); + + head = &state_queue; + +@@ -718,8 +713,8 @@ int st_add_task(struct autofs_point *ap, + + /* Don't add duplicate tasks */ + if ((task->state == state && !task->done) || +- (ap_state == ST_SHUTDOWN_PENDING || +- ap_state == ST_SHUTDOWN_FORCE)) ++ (ap->state == ST_SHUTDOWN_PENDING || ++ ap->state == ST_SHUTDOWN_FORCE)) + break; + + /* No pending tasks */ +@@ -736,8 +731,8 @@ int st_add_task(struct autofs_point *ap, + p_task = list_entry(q, struct state_queue, pending); + + if (p_task->state == state || +- (ap_state == ST_SHUTDOWN_PENDING || +- ap_state == ST_SHUTDOWN_FORCE)) ++ (ap->state == ST_SHUTDOWN_PENDING || ++ ap->state == ST_SHUTDOWN_FORCE)) + goto done; + } + +@@ -760,11 +755,24 @@ done: + if (status) + fatal(status); + ++ return 1; ++} ++ ++int st_add_task(struct autofs_point *ap, enum states state) ++{ ++ int ret; ++ ++ st_mutex_lock(); ++ ret = __st_add_task(ap, state); + st_mutex_unlock(); + +- return 1; ++ return ret; + } + ++/* ++ * Remove state queue tasks for ap. ++ * State queue mutex and ap state mutex, in that order, must be held. ++ */ + void st_remove_tasks(struct autofs_point *ap) + { + struct list_head *head; +@@ -772,14 +780,10 @@ void st_remove_tasks(struct autofs_point + struct state_queue *task, *waiting; + int status; + +- st_mutex_lock(); +- + head = &state_queue; + +- if (list_empty(head)) { +- st_mutex_unlock(); ++ if (list_empty(head)) + return; +- } + + p = head->next; + while (p != head) { +@@ -816,12 +820,107 @@ void st_remove_tasks(struct autofs_point + if (status) + fatal(status); + ++ return; ++} ++ ++static int st_task_active(struct autofs_point *ap, enum states state) ++{ ++ struct list_head *head; ++ struct list_head *p, *q; ++ struct state_queue *task, *waiting; ++ unsigned int active = 0; ++ ++ st_mutex_lock(); ++ ++ head = &state_queue; ++ ++ list_for_each(p, head) { ++ task = list_entry(p, struct state_queue, list); ++ ++ if (task->ap != ap) ++ continue; ++ ++ if (task->state == state) { ++ active = 1; ++ break; ++ } ++ ++ if (state == ST_ANY) { ++ active = 1; ++ break; ++ } ++ ++ list_for_each(q, &task->pending) { ++ waiting = list_entry(q, struct state_queue, pending); ++ ++ if (waiting->state == state) { ++ active = 1; ++ break; ++ } ++ ++ if (state == ST_ANY) { ++ active = 1; ++ break; ++ } ++ } ++ } ++ + st_mutex_unlock(); + +- return; ++ return active; ++} ++ ++int st_wait_task(struct autofs_point *ap, enum states state, unsigned int seconds) ++{ ++ unsigned int wait = 0; ++ unsigned int duration = 0; ++ int ret = 0; + ++ while (1) { ++ struct timespec t = { 0, 200000000 }; ++ struct timespec r; ++ ++ while (nanosleep(&t, &r) == -1 && errno == EINTR) ++ memcpy(&t, &r, sizeof(struct timespec)); ++ ++ if (wait++ == 4) { ++ wait = 0; ++ duration++; ++ } ++ ++ if (!st_task_active(ap, state)) { ++ ret = 1; ++ break; ++ } ++ ++ if (seconds && duration >= seconds) ++ break; ++ } ++ ++ return ret; + } + ++int st_wait_state(struct autofs_point *ap, enum states state) ++{ ++ while (1) { ++ struct timespec t = { 0, 200000000 }; ++ struct timespec r; ++ ++ while (nanosleep(&t, &r) == -1 && errno == EINTR) ++ memcpy(&t, &r, sizeof(struct timespec)); ++ ++ st_mutex_lock(); ++ if (ap->state == state) { ++ st_mutex_unlock(); ++ return 1; ++ } ++ st_mutex_unlock(); ++ } ++ ++ return 0; ++} ++ ++ + static int run_state_task(struct state_queue *task) + { + struct autofs_point *ap; +@@ -831,8 +930,6 @@ static int run_state_task(struct state_q + ap = task->ap; + next_state = task->state; + +- state_mutex_lock(ap); +- + state = ap->state; + + if (next_state != state) { +@@ -862,8 +959,6 @@ static int run_state_task(struct state_q + } + } + +- state_mutex_unlock(ap); +- + return ret; + } + +@@ -888,8 +983,6 @@ static void st_set_done(struct autofs_po + struct list_head *p, *head; + struct state_queue *task; + +- st_mutex_lock(); +- + head = &state_queue; + list_for_each(p, head) { + task = list_entry(p, struct state_queue, list); +@@ -899,8 +992,6 @@ static void st_set_done(struct autofs_po + } + } + +- st_mutex_unlock(); +- + return; + } + +--- autofs-5.0.2.orig/include/automount.h ++++ autofs-5.0.2/include/automount.h +@@ -399,7 +399,6 @@ struct autofs_point { + unsigned logopt; /* Per map logging */ + pthread_t exp_thread; /* Thread that is expiring */ + pthread_t readmap_thread; /* Thread that is reading maps */ +- pthread_mutex_t state_mutex; /* Protect state changes */ + enum states state; /* Current state */ + int state_pipe[2]; /* State change router pipe */ + unsigned dir_created; /* Directory created for this mount? */ +@@ -407,8 +406,6 @@ struct autofs_point { + * host from which to mount */ + struct autofs_point *parent; /* Owner of mounts list for submount */ + pthread_mutex_t mounts_mutex; /* Protect mount lists */ +- pthread_cond_t mounts_cond; /* Submounts condition variable */ +- unsigned int mounts_signaled; /* Submount signals task complete */ + struct list_head mounts; /* List of autofs mounts at current level */ + unsigned int submount; /* Is this a submount */ + unsigned int shutdown; /* Shutdown notification */ +@@ -446,20 +443,6 @@ int handle_packet_missing_direct(struct + void rm_unwanted(unsigned logopt, const char *path, int incl, dev_t dev); + int count_mounts(unsigned logopt, const char *path, dev_t dev); + +-#define state_mutex_lock(ap) \ +-do { \ +- int _st_lock = pthread_mutex_lock(&ap->state_mutex); \ +- if (_st_lock) \ +- fatal(_st_lock); \ +-} while(0) +- +-#define state_mutex_unlock(ap) \ +-do{ \ +- int _st_unlock = pthread_mutex_unlock(&ap->state_mutex); \ +- if (_st_unlock) \ +- fatal(_st_unlock); \ +-} while (0) +- + #define mounts_mutex_lock(ap) \ + do { \ + int _m_lock = pthread_mutex_lock(&ap->mounts_mutex); \ +--- autofs-5.0.2.orig/include/master.h ++++ autofs-5.0.2/include/master.h +@@ -20,10 +20,6 @@ + #ifndef MASTER_H + #define MASTER_H + +-#define MASTER_SUBMNT_WAIT 0 +-#define MASTER_SUBMNT_CONTINUE 1 +-#define MASTER_SUBMNT_JOIN 2 +- + struct map_source { + char *type; + char *format; +@@ -104,7 +100,6 @@ struct master *master_new(const char *, + int master_read_master(struct master *, time_t, int); + int master_submount_list_empty(struct autofs_point *ap); + int master_notify_submount(struct autofs_point *, const char *path, enum states); +-void master_signal_submount(struct autofs_point *, unsigned int); + void master_notify_state_change(struct master *, int); + int master_mount_mounts(struct master *, time_t, int); + extern inline unsigned int master_get_logopt(void); +--- autofs-5.0.2.orig/include/state.h ++++ autofs-5.0.2/include/state.h +@@ -38,7 +38,8 @@ + * + */ + enum states { +- ST_INVAL = -1, ++ ST_ANY = -2, ++ ST_INVAL, + ST_INIT, + ST_READY, + ST_EXPIRE, +@@ -81,12 +82,18 @@ struct readmap_args { + time_t now; /* Time when map is read */ + }; + ++void st_mutex_lock(void); ++void st_mutex_unlock(void); ++ + void expire_cleanup(void *); + void expire_proc_cleanup(void *); + void nextstate(int, enum states); + + int st_add_task(struct autofs_point *, enum states); ++int __st_add_task(struct autofs_point *, enum states); + void st_remove_tasks(struct autofs_point *); ++int st_wait_task(struct autofs_point *, enum states, unsigned int); ++int st_wait_state(struct autofs_point *ap, enum states state); + int st_start_handler(void); + + #endif +--- autofs-5.0.2.orig/lib/alarm.c ++++ autofs-5.0.2/lib/alarm.c +@@ -178,7 +178,6 @@ static void *alarm_handler(void *arg) + head = &alarms; + + while (1) { +- + if (list_empty(head)) { + /* No alarms, wait for one to be added */ + status = pthread_cond_wait(&cond, &mutex); +@@ -211,19 +210,8 @@ static void *alarm_handler(void *arg) + + if (!first->cancel) { + struct autofs_point *ap = first->ap; +- /* +- * We need to unlock the alarm list in case +- * some other thread holds the state_mutex +- *_lock(ap), and is currently trying to do +- * some alarm_* function (i.e if we don't +- * unlock, we might deadlock). +- */ + alarm_unlock(); +- +- state_mutex_lock(ap); +- nextstate(ap->state_pipe[1], ST_EXPIRE); +- state_mutex_unlock(ap); +- ++ st_add_task(ap, ST_EXPIRE); + alarm_lock(); + } + free(first); +--- autofs-5.0.2.orig/lib/master.c ++++ autofs-5.0.2/lib/master.c +@@ -90,41 +90,20 @@ int master_add_autofs_point(struct maste + ap->logopt = logopt; + + ap->parent = NULL; ++ ap->thid = 0; + ap->submnt_count = 0; + ap->submount = submount; + INIT_LIST_HEAD(&ap->mounts); + INIT_LIST_HEAD(&ap->submounts); + ap->shutdown = 0; + +- status = pthread_mutex_init(&ap->state_mutex, NULL); +- if (status) { +- free(ap->path); +- free(ap); +- return 0; +- } +- + status = pthread_mutex_init(&ap->mounts_mutex, NULL); + if (status) { +- status = pthread_mutex_destroy(&ap->state_mutex); +- if (status) +- fatal(status); + free(ap->path); + free(ap); + return 0; + } + +- status = pthread_cond_init(&ap->mounts_cond, NULL); +- if (status) { +- status = pthread_mutex_destroy(&ap->mounts_mutex); +- if (status) +- fatal(status); +- status = pthread_mutex_destroy(&ap->state_mutex); +- if (status) +- fatal(status); +- free(ap->path); +- free(ap); +- return 0; +- } + entry->ap = ap; + + return 1; +@@ -137,18 +116,10 @@ void master_free_autofs_point(struct aut + if (!ap) + return; + +- status = pthread_mutex_destroy(&ap->state_mutex); +- if (status) +- fatal(status); +- + status = pthread_mutex_destroy(&ap->mounts_mutex); + if (status) + fatal(status); + +- status = pthread_cond_destroy(&ap->mounts_cond); +- if (status) +- fatal(status); +- + free(ap->path); + free(ap); + } +@@ -295,11 +266,9 @@ struct map_source *master_find_map_sourc + { + struct map_source *source = NULL; + +- master_mutex_lock(); +- ++ master_source_readlock(entry); + source = __master_find_map_source(entry, type, format, argc, argv); +- +- master_mutex_unlock(); ++ master_source_unlock(entry); + + return source; + } +@@ -519,13 +488,7 @@ void send_map_update_request(struct auto + if (!need_update) + return; + +- status = pthread_mutex_lock(&ap->state_mutex); +- if (status) +- fatal(status); +- nextstate(ap->state_pipe[1], ST_READMAP); +- status = pthread_mutex_unlock(&ap->state_mutex); +- if (status) +- fatal(status); ++ st_add_task(ap, ST_READMAP); + + return; + } +@@ -695,17 +658,13 @@ void master_remove_mapent(struct master_ + if (entry->ap->submount) + return; + +- master_mutex_lock(); + if (!list_empty(&entry->list)) + list_del_init(&entry->list); +- master_mutex_unlock(); + return; + } + + void master_free_mapent_sources(struct master_mapent *entry, unsigned int free_cache) + { +- master_source_writelock(entry); +- + if (entry->maps) { + struct map_source *m, *n; + +@@ -718,8 +677,6 @@ void master_free_mapent_sources(struct m + entry->maps = NULL; + } + +- master_source_unlock(entry); +- + return; + } + +@@ -827,10 +784,9 @@ int master_submount_list_empty(struct au + int master_notify_submount(struct autofs_point *ap, const char *path, enum states state) + { + struct list_head *head, *p; +- struct autofs_point *this; +- pthread_t thid; ++ struct autofs_point *this = NULL; + size_t plen = strlen(path); +- int status, ret = 1; ++ int ret = 1; + + mounts_mutex_lock(ap); + +@@ -869,64 +825,30 @@ int master_notify_submount(struct autofs + + /* Now we have a submount to expire */ + +- state_mutex_lock(this); ++ st_mutex_lock(); + + if (this->state == ST_SHUTDOWN) { +- state_mutex_unlock(this); ++ this = NULL; ++ st_mutex_unlock(); + break; + } + +- nextstate(this->state_pipe[1], state); +- +- state_mutex_unlock(this); +- +- thid = this->thid; +- ap->mounts_signaled = MASTER_SUBMNT_WAIT; +- while (ap->mounts_signaled == MASTER_SUBMNT_WAIT) { +- status = pthread_cond_wait(&ap->mounts_cond, &ap->mounts_mutex); +- if (status) +- fatal(status); +- } +- +- if (ap->mounts_signaled == MASTER_SUBMNT_JOIN) { +- status = pthread_join(thid, NULL); +- if (status) +- fatal(status); +- } else +- ret = 0; ++ this->shutdown = ap->shutdown; + +- break; +- } +- +- mounts_mutex_unlock(ap); ++ __st_add_task(this, state); + +- return ret; +-} +- +-void master_signal_submount(struct autofs_point *ap, unsigned int join) +-{ +- int status; +- +- if (!ap->parent || !ap->submount) +- return; ++ st_mutex_unlock(); ++ mounts_mutex_unlock(ap); + +- mounts_mutex_lock(ap->parent); ++ st_wait_task(this, state, 0); + +- ap->parent->mounts_signaled = join; ++ return ret; + +- if (join == MASTER_SUBMNT_JOIN) { +- /* We are finishing up */ +- ap->parent->submnt_count--; +- list_del(&ap->mounts); + } + +- status = pthread_cond_signal(&ap->parent->mounts_cond); +- if (status) +- fatal(status); +- +- mounts_mutex_unlock(ap->parent); ++ mounts_mutex_unlock(ap); + +- return; ++ return ret; + } + + void master_notify_state_change(struct master *master, int sig) +@@ -934,7 +856,7 @@ void master_notify_state_change(struct m + struct master_mapent *entry; + struct autofs_point *ap; + struct list_head *p; +- int state_pipe, cur_state; ++ int cur_state; + unsigned int logopt; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); +@@ -948,13 +870,11 @@ void master_notify_state_change(struct m + ap = entry->ap; + logopt = ap->logopt; + +- state_mutex_lock(ap); ++ st_mutex_lock(); + + if (ap->state == ST_SHUTDOWN) + goto next; + +- state_pipe = ap->state_pipe[1]; +- + switch (sig) { + case SIGTERM: + case SIGINT: +@@ -962,7 +882,7 @@ void master_notify_state_change(struct m + ap->state != ST_SHUTDOWN_FORCE) { + next = ST_SHUTDOWN_PENDING; + ap->shutdown = 1; +- nextstate(state_pipe, next); ++ __st_add_task(ap, next); + } + break; + #ifdef ENABLE_FORCED_SHUTDOWN +@@ -970,14 +890,15 @@ void master_notify_state_change(struct m + if (ap->state != ST_SHUTDOWN_FORCE && + ap->state != ST_SHUTDOWN_PENDING) { + next = ST_SHUTDOWN_FORCE; +- nextstate(state_pipe, next); ++ ap->shutdown = 1; ++ __st_add_task(ap, next); + } + break; + #endif + case SIGUSR1: + assert(ap->state == ST_READY); + next = ST_PRUNE; +- nextstate(state_pipe, next); ++ __st_add_task(ap, next); + break; + } + next: +@@ -986,7 +907,7 @@ next: + "sig %d switching %s from %d to %d", + sig, ap->path, ap->state, next); + +- state_mutex_unlock(ap); ++ st_mutex_unlock(); + } + + master_mutex_unlock(); +@@ -1024,7 +945,6 @@ static int master_do_mount(struct master + handle_mounts_startup_cond_destroy(&suc); + return 0; + } +- entry->thid = thid; + + while (!suc.done) { + status = pthread_cond_wait(&suc.cond, &suc.mutex); +@@ -1037,45 +957,18 @@ static int master_do_mount(struct master + handle_mounts_startup_cond_destroy(&suc); + return 0; + } ++ entry->thid = thid; + + handle_mounts_startup_cond_destroy(&suc); + + return 1; + } + +-static void shutdown_entry(struct master_mapent *entry) +-{ +- int state_pipe; +- struct autofs_point *ap; +- struct stat st; +- int ret; +- +- ap = entry->ap; +- +- debug(ap->logopt, "%s", entry->path); +- +- state_mutex_lock(ap); +- +- state_pipe = ap->state_pipe[1]; +- +- ret = fstat(state_pipe, &st); +- if (ret == -1) +- goto next; +- +- nextstate(state_pipe, ST_SHUTDOWN_PENDING); +-next: +- state_mutex_unlock(ap); +- +- return; +-} +- + static void check_update_map_sources(struct master_mapent *entry, int readall) + { + struct map_source *source, *last; +- int state_pipe, map_stale = 0; + struct autofs_point *ap; +- struct stat st; +- int ret; ++ int map_stale = 0; + + if (readall) + map_stale = 1; +@@ -1128,17 +1021,8 @@ static void check_update_map_sources(str + master_source_unlock(entry); + + /* The map sources have changed */ +- if (map_stale) { +- state_mutex_lock(ap); +- +- state_pipe = entry->ap->state_pipe[1]; +- +- ret = fstat(state_pipe, &st); +- if (ret != -1) +- nextstate(state_pipe, ST_READMAP); +- +- state_mutex_unlock(ap); +- } ++ if (map_stale) ++ st_add_task(ap, ST_READMAP); + + return; + } +@@ -1169,17 +1053,19 @@ int master_mount_mounts(struct master *m + + /* A master map entry has gone away */ + if (this->age < age) { +- shutdown_entry(this); ++ st_add_task(ap, ST_SHUTDOWN_PENDING); + continue; + } + ++ master_source_writelock(ap->entry); + lookup_close_lookup(ap); ++ master_source_unlock(ap->entry); + + cache_readlock(nc); + ne = cache_lookup_distinct(nc, this->path); + if (ne && this->age > ne->age) { + cache_unlock(nc); +- shutdown_entry(this); ++ st_add_task(ap, ST_SHUTDOWN_PENDING); + continue; + } + nested = cache_partial_match(nc, this->path); +@@ -1195,7 +1081,7 @@ int master_mount_mounts(struct master *m + + check_update_map_sources(this, readall); + +- state_mutex_lock(ap); ++ st_mutex_lock(); + + state_pipe = this->ap->state_pipe[1]; + +@@ -1203,7 +1089,7 @@ int master_mount_mounts(struct master *m + ret = fstat(state_pipe, &st); + save_errno = errno; + +- state_mutex_unlock(ap); ++ st_mutex_unlock(); + + if (ret == -1 && save_errno == EBADF) + if (!master_do_mount(this)) { +--- autofs-5.0.2.orig/modules/mount_autofs.c ++++ autofs-5.0.2/modules/mount_autofs.c +@@ -242,7 +242,6 @@ int mount_mount(struct autofs_point *ap, + master_free_mapent(entry); + return 1; + } +- nap->thid = thid; + + while (!suc.done) { + status = pthread_cond_wait(&suc.cond, &suc.mutex); +@@ -264,6 +263,7 @@ int mount_mount(struct autofs_point *ap, + master_free_mapent(entry); + return 1; + } ++ nap->thid = thid; + + ap->submnt_count++; + list_add(&nap->mounts, &ap->submounts); diff --git a/autofs-5.0.3-update-replicated-doco.patch b/autofs-5.0.3-update-replicated-doco.patch new file mode 100644 index 0000000..c13d4c4 --- /dev/null +++ b/autofs-5.0.3-update-replicated-doco.patch @@ -0,0 +1,87 @@ +autofs-5.0.3 - update replicated server selection documentation + +From: Ian Kent + +Update the replicated server selection README documentation to +reflect the selection rules now used. +--- + + README.replicated-server | 51 ++++++++++++++++++++++------------------------- + 1 file changed, 24 insertions(+), 27 deletions(-) + + +--- autofs-5.0.2.orig/README.replicated-server ++++ autofs-5.0.2/README.replicated-server +@@ -3,48 +3,45 @@ Supported forms for mount paths are: + Normal single-host (these are unchanged) + host:/path/path + ++Single host entries are not probed for a server response. ++ + Multiple replicated hosts, same path: + host1,host2,hostn:/path/path + +-This will do an initial RPC call with a .1 second timeout to all hosts to +-find best match. If this fails, it will try a 10 second timeout, if this +-fails it takes the first host. +- + Multiple hosts, some with same path, some with another + host1,host2:/blah host3:/some/other/path + +-Works as expected +- + Multiple replicated hosts, different (potentially) paths: + host1:/path/pathA host2:/path/pathB + +-Same as above with RPC calls.. +- + Mutliple weighted, replicated hosts same path: +- + host1(5),host2(6),host3(1):/path/path + +-Will pick lowest weighted host that responds to RPC call. +-RPC time is not counted, only whether the call got a reply +-at all. Initially does a .1 second timeout, if all hosts +-fail this, moves to 10 second timeout. If one of the hosts +-is localhost, the automounter will choose that regardless of +-its weight. (This has been done to remain compatible with +-Sun's automounter) +- + Multiple weighted, replicated hosts different (potentially) + paths: + host1(3):/path/pathA host2(5):/path/pathB + +-Same as above with RPC calls/weighting. +- +-Anything else is questionable and unsupported, but these +-variations will also work: +- host1(3),host:/blah +- +-Unsupported and I don't know why you would use this, but will +-work. Weighted host always gets precedence if it responds to RPC ++For these formats a priority ordered list of hosts is created by using ++the following selection rules. + +-Anything else, I ain't making no promises. ++1) Highest priority in selection is proximity. ++ Proximity, in order of precedence is: ++ - PROXIMITY_LOCAL, host corresponds to a local interface. ++ - PROXIMITY_SUBNET, host is located in a subnet reachable ++ through a local interface. ++ - PROXIMITY_NETWORK, host is located in a network reachable ++ through a local interface. ++ - PROXIMITY_OTHER, host is on a network not directlty ++ reachable through a local interface. ++ ++2) NFS version and protocol is selected by caclculating the largest ++ number of hosts supporting an NFS version and protocol that ++ have the closest proximity. These hosts are added to the list ++ in response time order. Hosts may have a corresponding weight ++ which essentially increases response time and so influences the ++ host order. ++ ++3) Hosts at further proximity that support the selected NFS version ++ and protocol are also added to the list in response time order as ++ in 2 above. + +-Jason diff --git a/autofs-5.0.3-use-dev-urandom.patch b/autofs-5.0.3-use-dev-urandom.patch new file mode 100644 index 0000000..4be007a --- /dev/null +++ b/autofs-5.0.3-use-dev-urandom.patch @@ -0,0 +1,24 @@ +autofs-5.0.3 - use /dev/urandom instead of /dev/random + +From: Ian Kent + +It has been reported that some headless systems hang when using +/dev/random. It's also been pointed out that /dev/urandom is +sufficient for the needs of autofs. +--- + + modules/replicated.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + + +--- autofs-5.0.2.orig/modules/replicated.c ++++ autofs-5.0.2/modules/replicated.c +@@ -79,7 +79,7 @@ void seed_random(void) + int fd; + unsigned int seed; + +- fd = open("/dev/random", O_RDONLY); ++ fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + srandom(time(NULL)); + return; diff --git a/autofs-5.0.3-wait-submount-expire-complete.patch b/autofs-5.0.3-wait-submount-expire-complete.patch new file mode 100644 index 0000000..45d9684 --- /dev/null +++ b/autofs-5.0.3-wait-submount-expire-complete.patch @@ -0,0 +1,48 @@ +autofs-5.0.3 - wait submount expire complete + +From: Ian Kent + +When expiring a submount expires away and proceeds to shutdown we +can reach the end of the expire of the parent before the submount +goes away. This can cause an incomplete expire during shutdown in +some cases so, for the case the submount goes to state ST_SHUTDOWN, +we need to wait until the submount either goes away or fails to +shutdown before continuing. +--- + + lib/master.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + + +--- autofs-5.0.3.orig/lib/master.c ++++ autofs-5.0.3/lib/master.c +@@ -870,6 +870,29 @@ int master_notify_submount(struct autofs + + st_wait_task(this, state, 0); + ++ /* ++ * If our submount gets to state ST_SHUTDOWN we need to ++ * wait until it goes away or changes to ST_READY. ++ */ ++ mounts_mutex_lock(ap); ++ st_mutex_lock(); ++ while ((this = __master_find_submount(ap, path))) { ++ struct timespec t = { 0, 300000000 }; ++ struct timespec r; ++ ++ if (this->state != ST_SHUTDOWN) ++ break; ++ ++ st_mutex_unlock(); ++ mounts_mutex_unlock(ap); ++ while (nanosleep(&t, &r) == -1 && errno == EINTR) ++ memcpy(&t, &r, sizeof(struct timespec)); ++ mounts_mutex_lock(ap); ++ st_mutex_lock(); ++ } ++ st_mutex_unlock(); ++ mounts_mutex_unlock(ap); ++ + return ret; + + } diff --git a/autofs.spec b/autofs.spec index 83d091b..4bf3b7f 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.2 -Release: 29 +Release: 30 Epoch: 1 License: GPL Group: System Environment/Daemons @@ -82,6 +82,52 @@ Patch68: autofs-5.0.3-expire-works-too-hard.patch Patch69: autofs-5.0.3-unlink-mount-return-fix.patch Patch70: autofs-5.0.2-init-cb-on-load.patch Patch71: autofs-5.0.3-mount-thread-create-cond-handling.patch +Patch72: autofs-5.0.3-map-type-in-map-name.patch +Patch73: autofs-5.0.3-check-for-kernel-automount.patch +Patch74: autofs-5.0.3-nss-source-any.patch +Patch75: autofs-5.0.3-dont-abuse-ap-ghost-field.patch +Patch76: autofs-5.0.3-lookup-next-soucre-stale-entry.patch +Patch77: autofs-5.0.3-remove-redundant-dns-name-lookups.patch +Patch78: autofs-5.0.3-mount-thread-create-cond-handling-fix.patch +Patch79: autofs-5.0.3-allow-dir-create-on-nfs-root.patch +Patch80: autofs-5.0.3-check-direct-path-len.patch +Patch81: autofs-5.0.3-fix-get-user-info-check.patch +Patch82: autofs-5.0.3-fix-couple-of-memory-leaks.patch +Patch83: autofs-5.0.3-override-is-running-check.patch +Patch84: autofs-5.0.3-dont-use-proc-for-is-running-check.patch +Patch85: autofs-5.0.3-fix-included-browse-map-not-found.patch +Patch86: autofs-5.0.3-fix-multi-source-messages.patch +Patch87: autofs-5.0.3-clear-stale-on-map-read.patch +Patch88: autofs-5.0.3-fix-proximity-other-timeout.patch +Patch89: autofs-5.0.3-refactor-mount-request-vars.patch +Patch90: autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch +Patch91: autofs-5.0.3-submount-shutdown-recovery-12.patch +Patch92: autofs-5.0.3-dont-block-on-expire.patch +Patch93: autofs-5.0.3-add-umount_wait-parameter.patch +Patch94: autofs-5.0.3-fix-multi-mount-race.patch +Patch95: autofs-5.0.3-submount-shutdown-recovery-12-fix.patch +Patch96: autofs-5.0.3-fix-nfs4-colon-escape.patch +Patch97: autofs-5.0.3-check-replicated-list-after-probe.patch +Patch98: autofs-5.0.3-add-replicated-debug-logging.patch +Patch99: autofs-5.0.3-update-replicated-doco.patch +Patch100: autofs-5.0.3-use-dev-urandom.patch +Patch101: autofs-5.0.3-mtab-as-proc-mounts.patch +Patch102: autofs-5.0.3-fix-ifc-buff-size.patch +Patch103: autofs-5.0.3-fix-percent-hack.patch +Patch104: autofs-5.0.3-mtab-as-proc-mounts-fix.patch +Patch105: autofs-5.0.2-handle-zero-length-nis-key-update.patch +Patch106: autofs-5.0.3-fix-ifc-buff-size-fix-2.patch +Patch107: autofs-5.0.3-check-for-kernel-automount-fix.patch +Patch108: autofs-5.0.3-fix-fd-leak-at-multi-mount-fail.patch +Patch109: autofs-5.0.3-fix-incorrect-multi-mount-mountpoint.patch +Patch110: autofs-5.0.3-map-type-in-map-name-fix.patch +Patch111: autofs-5.0.3-dont-readmap-on-hup-for-new-mount.patch +Patch112: autofs-5.0.3-nisplus-partial-and-free.patch +Patch113: autofs-5.0.3-fix-rootless-direct-multi-mount-expire.patch +Patch114: autofs-5.0.3-wait-submount-expire-complete.patch +Patch115: autofs-5.0.3-add-missing-uris-list-locking.patch +Patch116: autofs-5.0.3-library-reload-fix.patch +Patch117: autofs-5.0.3-expire-thread-create-cond-handling.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 @@ -195,6 +241,52 @@ echo %{version}-%{release} > .version %patch69 -p1 %patch70 -p1 %patch71 -p1 +%patch72 -p1 +%patch73 -p1 +%patch74 -p1 +%patch75 -p1 +%patch76 -p1 +%patch77 -p1 +%patch78 -p1 +%patch79 -p1 +%patch80 -p1 +%patch81 -p1 +%patch82 -p1 +%patch83 -p1 +%patch84 -p1 +%patch85 -p1 +%patch86 -p1 +%patch87 -p1 +%patch88 -p1 +%patch89 -p1 +%patch90 -p1 +%patch91 -p1 +%patch92 -p1 +%patch93 -p1 +%patch94 -p1 +%patch95 -p1 +%patch96 -p1 +%patch97 -p1 +%patch98 -p1 +%patch99 -p1 +%patch100 -p1 +%patch101 -p1 +%patch102 -p1 +%patch103 -p1 +%patch104 -p1 +%patch105 -p1 +%patch106 -p1 +%patch107 -p1 +%patch108 -p1 +%patch109 -p1 +%patch110 -p1 +%patch111 -p1 +%patch112 -p1 +%patch113 -p1 +%patch114 -p1 +%patch115 -p1 +%patch116 -p1 +%patch117 -p1 %build #CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=/usr --libdir=%{_libdir} @@ -247,6 +339,55 @@ fi %{_libdir}/autofs/ %changelog +* Mon Nov 10 2008 Ian Kent - 5.0.2-30 +- sync. with F-9 bug fixes. + - fix lexer ambiguity in match when map type name is included in map name. + - check for nohide mounts. + - ignore nsswitch sources that aren't supported. + - don't abuse the ap->ghost field on NFS mount. + - multi-map doesn't pickup NIS updates automatically. + - eliminate redundant DNS name lookups. + - mount thread create condition handling fix. + - allow directory create on NFS root. + - check direct mount path length. + - fix incorrect in check in get user info. + - fix a couple of memory leaks. + - don't close file handle for rootless direct mounti-mount at mount. + - wait submount expire thread completion when expire successful. + - add inadvertantly ommitted server list locking in LDAP module. + - add map-type-in-map-name fix patch to sync with upstream and RHEL. + - don't readmap on HUP for new mount. + - add NIS_PARTIAL to map entry not found check and fix use after free bug. + - fix fd leak at multi-mount non-fatal mount fail. + - fix incorrect multi-mount mountpoint calcualtion. + - add upstream bug fixes + - bug fix for mtab check. + - bug fix for zero length nis key. + - update for ifc buffer handling. + - bug fix for kernel automount handling. + - add command line option to override is running check. + - don't use proc fs for is running check. + - fix fail on included browse map not found. + - fix incorrect multi source messages. + - clear stale flag on map read. + - fix proximity other rpc ping timeout. + - refactor mount request vars code. + - make handle_mounts startup condition distinct. + - fix submount shutdown handling. + - try not to block on expire. + - add configuration paramter UMOUNT_WAIT. + - fix multi mount race. + - fix nfs4 colon escape handling. + - check replicated list after probe. + - add replicated server selection debug logging. + - update replicated server selection documentation. + - use /dev/urandom instead of /dev/random. + - check for mtab pointing to /proc/mounts. + - fix interface config buffer size. + - fix percent hack heap corruption. + - fix segv during library re-open. + - fix incorrect pthreads condition handling for expire requests. + * Wed Apr 23 2008 Ian Kent - 5.0.2-29 - fix incorrect pthreads condition handling for mount requests.