rpms/autofs/devel autofs-5.0.3-add-replicated-debug-logging.patch, NONE, 1.1 autofs-5.0.3-add-umount_wait-parameter.patch, NONE, 1.1 autofs-5.0.3-check-replicated-list-after-probe.patch, NONE, 1.1 autofs-5.0.3-clear-stale-on-map-read.patch, NONE, 1.1 autofs-5.0.3-dont-block-on-expire.patch, NONE, 1.1 autofs-5.0.3-dont-use-proc-for-is-running-check.patch, NONE, 1.1 autofs-5.0.3-fix-ifc-buff-size.patch, NONE, 1.1 autofs-5.0.3-fix-included-browse-map-not-found.patch, NONE, 1.1 autofs-5.0.3-fix-multi-mount-race.patch, NONE, 1.1 autofs-5.0.3-fix-multi-source-messages.patch, NONE, 1.1 autofs-5.0.3-fix-nfs4-colon-escape.patch, NONE, 1.1 autofs-5.0.3-fix-percent-hack.patch, NONE, 1.1 autofs-5.0.3-fix-proximity-other-timeout.patch, NONE, 1.1 autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch, NONE, 1.1 autofs-5.0.3-mtab-as-proc-mounts.patch, NONE, 1.1 autofs-5.0.3-override-is-running-check.patch, NONE, 1.1 autofs-5.0.3-refactor-mount-request-vars.patch, NONE, 1.1 autofs-5.0.3-submount-shutdown-recovery-12-fix.patch, NONE, 1.1 autofs-5.0.3-submount-shutdown-recovery-12.patch, NONE, 1.1 autofs-5.0.3-update-replicated-doco.patch, NONE, 1.1 autofs-5.0.3-use-dev-urandom.patch, NONE, 1.1 autofs.spec, 1.249, 1.250

Ian Kent iankent at fedoraproject.org
Mon Aug 25 04:47:37 UTC 2008


Author: iankent

Update of /cvs/pkgs/rpms/autofs/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv27267

Modified Files:
	autofs.spec 
Added Files:
	autofs-5.0.3-add-replicated-debug-logging.patch 
	autofs-5.0.3-add-umount_wait-parameter.patch 
	autofs-5.0.3-check-replicated-list-after-probe.patch 
	autofs-5.0.3-clear-stale-on-map-read.patch 
	autofs-5.0.3-dont-block-on-expire.patch 
	autofs-5.0.3-dont-use-proc-for-is-running-check.patch 
	autofs-5.0.3-fix-ifc-buff-size.patch 
	autofs-5.0.3-fix-included-browse-map-not-found.patch 
	autofs-5.0.3-fix-multi-mount-race.patch 
	autofs-5.0.3-fix-multi-source-messages.patch 
	autofs-5.0.3-fix-nfs4-colon-escape.patch 
	autofs-5.0.3-fix-percent-hack.patch 
	autofs-5.0.3-fix-proximity-other-timeout.patch 
	autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch 
	autofs-5.0.3-mtab-as-proc-mounts.patch 
	autofs-5.0.3-override-is-running-check.patch 
	autofs-5.0.3-refactor-mount-request-vars.patch 
	autofs-5.0.3-submount-shutdown-recovery-12-fix.patch 
	autofs-5.0.3-submount-shutdown-recovery-12.patch 
	autofs-5.0.3-update-replicated-doco.patch 
	autofs-5.0.3-use-dev-urandom.patch 
Log Message:
* Mon Aug 25 2008 Ian Kent <ikent at redhat.com> - 5.0.3-21
- add upstream bug fix patches
  - 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.


autofs-5.0.3-add-replicated-debug-logging.patch:

--- NEW FILE autofs-5.0.3-add-replicated-debug-logging.patch ---
autofs-5.0.3 - add replicated server selection debug logging

From: Ian Kent <raven at themaw.net>

Add some debug logging to the replicated server selection code.
---

 CHANGELOG            |    1 +
 modules/replicated.c |   86 ++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 67 insertions(+), 20 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index a7b41ec..af3318a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -30,6 +30,7 @@
 - avoid stat of possibly dead mount points and limit time to wait for
   umount during expire.
 - make mount of multi-mounts wuth a root offset atomic.
+- add replicated server selection debug logging.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/modules/replicated.c b/modules/replicated.c
index 271907c..e41713e 100644
--- a/modules/replicated.c
+++ b/modules/replicated.c
@@ -404,6 +404,10 @@ static unsigned int get_nfs_info(unsigned logopt, struct host *host,
 	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(unsigned logopt, struct host *host,
 		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(unsigned logopt, struct host *host,
 	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(unsigned logopt, struct host *host,
 		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, struct host **list,
 	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;

autofs-5.0.3-add-umount_wait-parameter.patch:

--- NEW FILE autofs-5.0.3-add-umount_wait-parameter.patch ---
autofs-5.0.3 - add configuration paramter UMOUNT_WAIT

From: Ian Kent <raven at themaw.net>

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"

autofs-5.0.3-check-replicated-list-after-probe.patch:

--- NEW FILE autofs-5.0.3-check-replicated-list-after-probe.patch ---
autofs-5.0.3 - check replicated list after probe

From: Ian Kent <raven at themaw.net>

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 files changed, 9 insertions(+), 0 deletions(-)


diff --git a/modules/replicated.c b/modules/replicated.c
index 925f641..271907c 100644
--- a/modules/replicated.c
+++ b/modules/replicated.c
@@ -768,6 +768,15 @@ int prune_host_list(unsigned logopt, struct host **list,
 		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 */

autofs-5.0.3-clear-stale-on-map-read.patch:

--- NEW FILE autofs-5.0.3-clear-stale-on-map-read.patch ---
autofs-5.0.3 - clear stale flag on map read

From: Ian Kent <raven at themaw.net>

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

autofs-5.0.3-dont-block-on-expire.patch:

--- NEW FILE autofs-5.0.3-dont-block-on-expire.patch ---
autofs-5.0.3 - try not to block on expire

From: Ian Kent <raven at themaw.net>

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.
---

 CHANGELOG          |    2 ++
 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 ++----------------------------------------
 8 files changed, 112 insertions(+), 110 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index ff04985..ff44cc7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -27,6 +27,8 @@
 - don't use proc file system when checking if the daemon is running.
 - make handle_mounts startup condition distinct.
 - fix submount shutdown recovery handling.
+- avoid stat of possibly dead mount points and limit time to wait for
+  umount during expire.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 68bf1d3..5bd5f6d 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -247,9 +247,17 @@ static int walk_tree(const char *base, int (*fn) (unsigned logopt,
 						  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, int (*fn) (unsigned logopt,
 			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 logopt, const char *file, const struct stat *
 	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, const char *file, const struct stat *st,
 {
 	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 autofs_point *ap, const char *path, unsi
 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, const char *path, int incl)
 	}
 	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;
 
diff --git a/daemon/direct.c b/daemon/direct.c
index 334a4b6..7fb78a3 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -152,7 +152,7 @@ int do_umount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, stru
 
 	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_point *ap, struct mapent *me)
 
 	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_point *ap, struct mapent *me)
 			 * 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);
-		debug(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;
 			}
diff --git a/daemon/indirect.c b/daemon/indirect.c
index 17bed3e..e832cd4 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -285,7 +285,7 @@ int umount_autofs_indirect(struct autofs_point *ap)
 
 	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);
-		debug(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);
diff --git a/daemon/spawn.c b/daemon/spawn.c
index 78d69c6..e3c355e 100644
--- a/daemon/spawn.c
+++ b/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, unsigned int options, const char *prog, con
 			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, unsigned int options, const char *prog, con
 			}
 		} 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, unsigned int options, const char *prog, con
 
 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 *prog, ...)
 	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
diff --git a/include/master.h b/include/master.h
index 86ae045..a397a75 100644
--- a/include/master.h
+++ b/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 *);
diff --git a/lib/master.c b/lib/master.c
index 522b919..71ba04a 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -602,6 +602,29 @@ struct master_mapent *master_find_mapent(struct master *master, const char *path
 	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;
diff --git a/lib/mounts.c b/lib/mounts.c
index a4bf86c..d77a6b0 100644
--- a/lib/mounts.c
+++ b/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);

autofs-5.0.3-dont-use-proc-for-is-running-check.patch:

--- NEW FILE autofs-5.0.3-dont-use-proc-for-is-running-check.patch ---
autofs-5.0.3 - don't use proc for is running check

From: Ian Kent <raven at themaw.net>

Using /proc/<pid>/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.
---

 CHANGELOG          |    1 
 Makefile.conf.in   |    3 +
 aclocal.m4         |   16 ++++
 configure          |   35 +++++++++
 configure.in       |   17 +++++
 daemon/Makefile    |    5 +
 daemon/automount.c |   95 ++++++++------------------
 daemon/flag.c      |  192 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 294 insertions(+), 70 deletions(-)
 create mode 100644 daemon/flag.c


diff --git a/CHANGELOG b/CHANGELOG
index f40a941..3921552 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -24,6 +24,7 @@
 - fix incorrect if check in get user info.
 - fix couple of memory leaks.
 - add command line option to override check for daemon already running.
+- don't use proc file system when checking if the daemon is running.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/Makefile.conf.in b/Makefile.conf.in
index 09c3129..d88f5ee 100644
--- a/Makefile.conf.in
+++ b/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@
 
diff --git a/aclocal.m4 b/aclocal.m4
index a1105ae..9ef4050 100644
--- a/aclocal.m4
+++ b/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               ##
diff --git a/configure b/configure
index 0d3268c..9278196 100755
--- a/configure
+++ b/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
diff --git a/configure.in b/configure.in
index 27b9bec..5ba3a49 100644
--- a/configure.in
+++ b/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()
diff --git a/daemon/Makefile b/daemon/Makefile
index 528a684..9c2d858 100644
--- a/daemon/Makefile
+++ b/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=\"$(autofslibdir)\"
 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
diff --git a/daemon/automount.c b/daemon/automount.c
index 48ac30a..dbf267c 100644
--- a/daemon/automount.c
+++ b/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_point *ap)
 	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 foreground)
 	}
 
 	/* 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 foreground)
 		}
 		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 foreground)
 		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_destroy(void *arg)
 	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)
diff --git a/daemon/flag.c b/daemon/flag.c
new file mode 100644
index 0000000..d8ca61b
--- /dev/null
+++ b/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 <raven at themaw.net>
+ *
+ * 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 <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <alloca.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+
+#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;
+}
+

autofs-5.0.3-fix-ifc-buff-size.patch:

--- NEW FILE autofs-5.0.3-fix-ifc-buff-size.patch ---
autofs-5.0.3 - fix interface config buffer size

From: Ian Kent <raven at themaw.net>

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.
---

 CHANGELOG            |    1 +
 modules/replicated.c |   51 ++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 44 insertions(+), 8 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index d2fe0a6..5b0f265 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -34,6 +34,7 @@
 - update replicated server selection documentation.
 - use /dev/urandom instead of /dev/random.
 - check for mtab pointing to /proc/mounts.
+- dynamically allocate interface config buffer.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/modules/replicated.c b/modules/replicated.c
index 362ab1b..ad1ede2 100644
--- a/modules/replicated.c
+++ b/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 char *host_addr, int addr_len)
 		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 char *host_addr, int addr_len)
 	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 char *host_addr, int addr_len)
 			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 char *host_addr, int addr_len)
 	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 *host_addr, int addr_len)
 				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 char *host_addr, int addr_len)
 
 			if ((ia & mask) == (ha & mask)) {
 				close(sock);
+				free(ifc.ifc_req);
 				return PROXIMITY_SUBNET;
 			}
 
@@ -208,6 +241,7 @@ static unsigned int get_proximity(const char *host_addr, int addr_len)
 
 			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 char *host_addr, int addr_len)
 	}
 
 	close(sock);
+	free(ifc.ifc_req);
 
 	return PROXIMITY_OTHER;
 }

autofs-5.0.3-fix-included-browse-map-not-found.patch:

--- NEW FILE autofs-5.0.3-fix-included-browse-map-not-found.patch ---
autofs-5.0.3 - fix fail on included browse map not found

From: Ian Kent <raven at themaw.net>

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);
 

autofs-5.0.3-fix-multi-mount-race.patch:

--- NEW FILE autofs-5.0.3-fix-multi-mount-race.patch ---
autofs-5.0.3 - fix multi mount race.

From: Ian Kent <raven at themaw.net>

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       <server1>:/<path1>
     /om2       <server2>:/<path2>
     /om2/om21  <server3>:/<path3>
     /om2/om22  <server3>:/<path4>

when a path walk hits mm1/om2 <serverr2>:/<path2> 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 <server3>:/<path3> mount. So the walk follows
the stack up to the mount at <server3>:/<path3>, 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.
---

 CHANGELOG               |    1 
 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     |  408 ++++++++++++++++++++++++++++++++++++-----------
 18 files changed, 517 insertions(+), 344 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index ff44cc7..a7b41ec 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -29,6 +29,7 @@
 - fix submount shutdown recovery handling.
 - avoid stat of possibly dead mount points and limit time to wait for
   umount during expire.
+- make mount of multi-mounts wuth a root offset atomic.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 5bd5f6d..5b6a561 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -489,7 +489,7 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
 		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_point *ap, int force)
 	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 *ap, int force)
 	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_point *ap)
 	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_point *ap)
 	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;
 
diff --git a/daemon/direct.c b/daemon/direct.c
index 7fb78a3..34e882b 100644
--- a/daemon/direct.c
+++ b/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_point *ap, struct mapent *me)
 	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_point *ap, struct mapent *me)
 			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_point *ap, struct mapent *me)
 			 * 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_point *ap, struct mapent *me)
 			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_point *ap, struct mapent *me)
 
 	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_point *ap, struct mapent *me)
 	} 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_point *ap, struct mapent *me)
 	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_point *ap, struct mapent *me)
 
 	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;
 }
diff --git a/daemon/indirect.c b/daemon/indirect.c
index e832cd4..168d915 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -83,7 +83,7 @@ static int unlink_mount_tree(struct autofs_point *ap, struct mnt_list *mnts)
 	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(struct autofs_point *ap)
 		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(struct autofs_point *ap)
 	} 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(struct autofs_point *ap)
 	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(struct autofs_point *ap)
 
 	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(struct autofs_point *ap)
 	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_point *ap)
 		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_point *ap)
 	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 autofs_point *ap)
 	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_point *ap)
 	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_point *ap)
 		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_point *ap)
 					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_point *ap)
 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;
diff --git a/daemon/lookup.c b/daemon/lookup.c
index 85ac519..db3b636 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -565,7 +565,7 @@ int lookup_nss_read_map(struct autofs_point *ap, struct map_source *source, time
 	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) {
diff --git a/daemon/state.c b/daemon/state.c
index 122177c..0042a74 100644
--- a/daemon/state.c
+++ b/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, "/");
diff --git a/include/automount.h b/include/automount.h
index 8ff24a7..61cdac6 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -230,7 +230,7 @@ int lookup_nss_read_master(struct master *master, time_t age);
 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, const char *name, int namelen);
 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);
diff --git a/include/master.h b/include/master.h
index a397a75..e62c67b 100644
--- a/include/master.h
+++ b/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 *);
diff --git a/include/mounts.h b/include/mounts.h
index 7120351..ca4f9f3 100644
--- a/include/mounts.h
+++ b/include/mounts.h
@@ -85,7 +85,7 @@ int tree_find_mnt_ents(struct mnt_list *mnts, struct list_head *list, const char
 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
diff --git a/lib/master.c b/lib/master.c
index 71ba04a..d971ad6 100644
--- a/lib/master.c
+++ b/lib/master.c
@@ -602,27 +602,32 @@ struct master_mapent *master_find_mapent(struct master *master, const char *path
 	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_mapent *entry)
 	}
 
 	suc.ap = ap;
+	suc.root = ap->path;
 	suc.done = 0;
 	suc.status = 0;
 
diff --git a/lib/mounts.c b/lib/mounts.c
index d77a6b0..f6fc389 100644
--- a/lib/mounts.c
+++ b/lib/mounts.c
@@ -1105,7 +1105,8 @@ int umount_ent(struct autofs_point *ap, const char *path)
 	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_point *ap, char *root, struct mapent *me,
 	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_point *ap, char *root, struct mapent *me,
 		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_point *ap, char *root, struct mapent *me
 		 * 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_point *ap, char *root, struct mapent *me
 		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++;
diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
index d6cbda8..8a7dd78 100644
--- a/modules/mount_autofs.c
+++ b/modules/mount_autofs.c
@@ -48,7 +48,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
 {
 	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, const char *root, const char *name,
 	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, const char *root, const char *name,
 	}
 
 	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, const char *root, const char *name,
 	}
 
 	suc.ap = nap;
+	suc.root = mountpoint;
 	suc.done = 0;
 	suc.status = 0;
 
@@ -235,7 +236,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
 		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, const char *root, const char *name,
 
 	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);
diff --git a/modules/mount_bind.c b/modules/mount_bind.c
index e4a04d0..396a3ca 100644
--- a/modules/mount_bind.c
+++ b/modules/mount_bind.c
@@ -74,34 +74,24 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
 	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, const char *root, const char *name, int
 		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",
diff --git a/modules/mount_changer.c b/modules/mount_changer.c
index 08d9147..e838fcf 100644
--- a/modules/mount_changer.c
+++ b/modules/mount_changer.c
@@ -49,34 +49,24 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
 	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);
 
diff --git a/modules/mount_ext2.c b/modules/mount_ext2.c
index 8cf9937..7589991 100644
--- a/modules/mount_ext2.c
+++ b/modules/mount_ext2.c
@@ -43,32 +43,22 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
 	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, const char *root, const char *name, int
 	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"))
diff --git a/modules/mount_generic.c b/modules/mount_generic.c
index 85b4391..4b1213e 100644
--- a/modules/mount_generic.c
+++ b/modules/mount_generic.c
@@ -42,32 +42,22 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
 	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, const char *root, const char *name, int
 	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",
diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
index d7f42a7..0b253d8 100644
--- a/modules/mount_nfs.c
+++ b/modules/mount_nfs.c
@@ -64,7 +64,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
 	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, const char *root, const char *name, int
 	/* 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, const char *root, const char *name, int
 	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
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index d839694..b548520 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -31,12 +31,18 @@
 #include <sys/vfs.h>
 #include <sys/utsname.h>
 #include <netinet/in.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
 
 #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_context = {
 	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, const char *name,
 
 	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, char *g_options, char **options, char *
 	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;
 
-	if (!mm)
+	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;
+	}
 
-	cache_multi_lock(me->parent);
+	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;
+	}
 
-	m_key = mm->key;
+	debug(ap->logopt,
+	      "moved mount tree from %s to %s", mm_tmp_root, mm_root);
 
-	if (*m_key == '/') {
-		m_root = m_key;
-		start = strlen(m_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;
+	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);
 		}
-		strcpy(m_root, ap->path);
-		strcat(m_root, "/");
-		strcat(m_root, m_key);
 	}
+	return;
+}
 
-	base = &me->key[start];
+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;
+
+	mm_root = &me->multi->multi_list;
+
+	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;
+}
 
-	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;
+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)));
 	}
 
-	cache_multi_unlock(me->parent);
+	return found;
+}
 
-	return ret;
+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(mm_key) + 1;
+		mm_root = alloca(start + 3);
+		strcpy(mm_root, ap->path);
+		strcat(mm_root, "/");
+		strcat(mm_root, mm_key);
+	}
+
+	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 = "/";
+
+		/* 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, const char *name,
 	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, const char *name,
 		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, const char *name,
 		 */
 		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);
 	}

autofs-5.0.3-fix-multi-source-messages.patch:

--- NEW FILE autofs-5.0.3-fix-multi-source-messages.patch ---
autofs-5.0.3 - fix multi source messages

From: Ian Kent <raven at themaw.net>

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(-)


diff --git a/daemon/lookup.c b/daemon/lookup.c
index 3c22a35..d33aadc 100644
--- a/daemon/lookup.c
+++ b/daemon/lookup.c
@@ -903,6 +903,9 @@ int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const c
 	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;
 }
 
diff --git a/modules/lookup_file.c b/modules/lookup_file.c
index 894f6fd..807ceab 100644
--- a/modules/lookup_file.c
+++ b/modules/lookup_file.c
@@ -1074,7 +1074,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
 	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, const char *name, int name_len, void *
 		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, const char *name, int name_len, void *
 			}
 			cache_unlock(mc);
 		}
-	} else
-		error(ap->logopt,
-		      MODPREFIX "key \"%s\" not found in map.", name);
+	}
 
 	if (ret)
 		return NSS_STATUS_TRYAGAIN;
diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
index 5cc2148..7777e90 100644
--- a/modules/lookup_ldap.c
+++ b/modules/lookup_ldap.c
@@ -2586,12 +2586,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
 
 		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, const char *name, int name_len, void *
 			}
 			cache_unlock(mc);
 		}
-	} else
-		error(ap->logopt,
-		      MODPREFIX "key \"%s\" not found in map", name);
+	}
 
 	if (ret)
 		return NSS_STATUS_TRYAGAIN;
diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
index 3c19fd3..4666161 100644
--- a/modules/lookup_nisplus.c
+++ b/modules/lookup_nisplus.c
@@ -520,12 +520,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
 		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, const char *name, int name_len, void *
 			}
 			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;
 }
diff --git a/modules/lookup_program.c b/modules/lookup_program.c
index 7c266d6..daf874d 100644
--- a/modules/lookup_program.c
+++ b/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;
diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
index 14f981c..ee06551 100644
--- a/modules/lookup_yp.c
+++ b/modules/lookup_yp.c
@@ -626,12 +626,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
 
 		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);
@@ -672,9 +668,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
 			}
 			cache_unlock(mc);
 		}
-	 } else
-		error(ap->logopt,
-		      MODPREFIX "key \"%s\" not found in map", name);
+	 }
 
 	if (ret)
 		return NSS_STATUS_TRYAGAIN;

autofs-5.0.3-fix-nfs4-colon-escape.patch:

--- NEW FILE autofs-5.0.3-fix-nfs4-colon-escape.patch ---
autofs-5.0.3 - fix nfs4 colon escape handling

From: Ian Kent <raven at themaw.net>

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';

autofs-5.0.3-fix-percent-hack.patch:

--- NEW FILE autofs-5.0.3-fix-percent-hack.patch ---
>From jmoyer at redhat.com Thu Jul 17 10:12:13 2008

From: Ian Kent <raven at themaw.net>

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)

autofs-5.0.3-fix-proximity-other-timeout.patch:

--- NEW FILE autofs-5.0.3-fix-proximity-other-timeout.patch ---
autofs-5.0.3 - fix proximity other rpc ping timeout

From: Ian Kent <raven at themaw.net>

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;

autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch:

--- NEW FILE autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch ---
autofs-5.0.3 - make handle_mounts startup condition distinct

From: Ian Kent <raven at themaw.net>

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.
---

 CHANGELOG              |    1 +
 daemon/automount.c     |   62 ++++++++++++++++++++++++++++++++++++++++++++----
 include/automount.h    |    4 +++
 lib/master.c           |   29 +++++++++++-----------
 modules/mount_autofs.c |   35 +++++++++++++--------------
 5 files changed, 93 insertions(+), 38 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 3921552..9da7be3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -25,6 +25,7 @@
 - fix couple of memory leaks.
 - add command line option to override check for daemon already running.
 - don't use proc file system when checking if the daemon is running.
+- make handle_mounts startup condition distinct.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index dbf267c..086affb 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -1461,6 +1461,55 @@ static void mutex_operation_wait(pthread_mutex_t *mutex)
 	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 *arg)
 
 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
diff --git a/include/automount.h b/include/automount.h
index da1bf8f..1a20cd9 100644
--- a/include/automount.h
+++ b/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;
diff --git a/lib/master.c b/lib/master.c
index 4a34dd4..edd3bdc 100644
--- a/lib/master.c
+++ b/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_mapent *entry)
 
 	if (suc.status) {
 		error(ap->logopt, "failed to startup mount");
-		status = pthread_mutex_unlock(&suc.mutex);
-		if (status)
-			fatal(status);
+		handle_mounts_startup_cond_destroy(&suc);
 		return 0;
 	}
 
-	status = pthread_mutex_unlock(&suc.mutex);
-	if (status)
-		fatal(status);
+	handle_mounts_startup_cond_destroy(&suc);
 
 	return 1;
 }
diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
index 356fb14..6f66564 100644
--- a/modules/mount_autofs.c
+++ b/modules/mount_autofs.c
@@ -46,6 +46,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
 		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, const char *root, const char *name,
 	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, const char *root, const char *name,
 	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, const char *root, const char *name,
 	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, const char *root, const char *name,
 	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;
 }
 

autofs-5.0.3-mtab-as-proc-mounts.patch:

--- NEW FILE autofs-5.0.3-mtab-as-proc-mounts.patch ---
autofs-5.0.3 - check for mtab pointing to /proc/mounts

From: Ian Kent <raven at themaw.net>

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.
---

 CHANGELOG      |    1 +
 daemon/spawn.c |   66 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 61 insertions(+), 6 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 50c9a27..d2fe0a6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -33,6 +33,7 @@
 - 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.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/daemon/spawn.c b/daemon/spawn.c
index 6b26c41..85cf9b8 100644
--- a/daemon/spawn.c
+++ b/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);
 

autofs-5.0.3-override-is-running-check.patch:

--- NEW FILE autofs-5.0.3-override-is-running-check.patch ---
autofs-5.0.3 - add command line option to override is running check

From: Ian Kent <raven at themaw.net>

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.
---

 CHANGELOG          |    1 +
 daemon/automount.c |   14 +++++++++++---
 man/automount.8    |   10 ++++++++++
 3 files changed, 22 insertions(+), 3 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index 5901c75..f40a941 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -23,6 +23,7 @@
 - fix direct mount path length not being checked.
 - fix incorrect if check in get user info.
 - fix couple of memory leaks.
+- add command line option to override check for daemon already running.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/daemon/automount.c b/daemon/automount.c
index 7ce9828..48ac30a 100644
--- a/daemon/automount.c
+++ b/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);
diff --git a/man/automount.8 b/man/automount.8
index 59ad50e..d9285bf 100644
--- a/man/automount.8
+++ b/man/automount.8
@@ -81,6 +81,9 @@ be disabled, returning the daemon to verbose logging.
 .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 processes that held them busy.
 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),

autofs-5.0.3-refactor-mount-request-vars.patch:

--- NEW FILE autofs-5.0.3-refactor-mount-request-vars.patch ---
autofs-5.0.3 - refactor mount request vars

From: Ian Kent <raven at themaw.net>

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 <raven at themaw.net>
---

 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


diff --git a/daemon/direct.c b/daemon/direct.c
index 072ef97..a3869a5 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -35,8 +35,6 @@
 #include <sys/mount.h>
 #include <sys/vfs.h>
 #include <sched.h>
-#include <pwd.h>
-#include <grp.h>
 
 #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
diff --git a/daemon/indirect.c b/daemon/indirect.c
index ccdd8bf..3922f3f 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -33,8 +33,6 @@
 #include <sys/time.h>
 #include <sys/mount.h>
 #include <sched.h>
-#include <pwd.h>
-#include <grp.h>
 
 #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;
-	}
+	set_tsd_user_vars(ap->logopt, mt.uid, mt.gid);
 
-	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);
-	}
-cont:
 	status = lookup_nss_mount(ap, NULL, mt.name, mt.len);
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 	if (status) {
diff --git a/include/automount.h b/include/automount.h
index 72e2457..da1bf8f 100644
--- a/include/automount.h
+++ b/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, const char *dir, const char *base);
 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 */
diff --git a/include/mounts.h b/include/mounts.h
new file mode 100644
index 0000000..7120351
--- /dev/null
+++ b/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 <raven at themaw.net> - 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
diff --git a/include/parse_subs.h b/include/parse_subs.h
index 10c6083..643ad68 100644
--- a/include/parse_subs.h
+++ b/include/parse_subs.h
@@ -27,8 +27,5 @@ int strmcmp(const char *, const char *, int);
 char *dequote(const char *, int, unsigned int);
 int span_space(const char *, unsigned int);
 char *sanitize_path(const char *, int, unsigned int, unsigned int);
-int umount_ent(struct autofs_point *, const char *);
-int mount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
-int umount_multi_triggers(struct autofs_point *, char *, struct mapent *, const char *);
 
 #endif
diff --git a/lib/mounts.c b/lib/mounts.c
index b987fbb..a4bf86c 100644
--- a/lib/mounts.c
+++ b/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 <raven at themaw.net> - All Rights Reserved
  *
@@ -23,12 +23,21 @@
 #include <fcntl.h>
 #include <sys/mount.h>
 #include <stdio.h>
+#include <dirent.h>
+#include <sys/vfs.h>
+#include <pwd.h>
+#include <grp.h>
 
 #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 *mnts, const char *path, unsigned int type)
 	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;
+}
+
diff --git a/lib/parse_subs.c b/lib/parse_subs.c
index 27cb0fc..3a04dd6 100644
--- a/lib/parse_subs.c
+++ b/lib/parse_subs.c
@@ -18,10 +18,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <unistd.h>
-#include <sys/vfs.h>
 #include "automount.h"
 
 /*
@@ -304,230 +301,3 @@ char *sanitize_path(const char *path, int origlen, unsigned int type, unsigned i
 	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;
-}
-

autofs-5.0.3-submount-shutdown-recovery-12-fix.patch:

--- NEW FILE autofs-5.0.3-submount-shutdown-recovery-12-fix.patch ---
autofs-5.0.3 - submount shutdown recovery fix

From: Ian Kent <raven at themaw.net>

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;

autofs-5.0.3-submount-shutdown-recovery-12.patch:

--- NEW FILE autofs-5.0.3-submount-shutdown-recovery-12.patch ---
autofs-5.0.3 - fix submount shutdown handling.

From: Ian Kent <raven at themaw.net>

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.
---

 CHANGELOG              |    1 
 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           |  180 +++++++------------------------------
 modules/mount_autofs.c |    2 
 12 files changed, 458 insertions(+), 435 deletions(-)


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

autofs-5.0.3-update-replicated-doco.patch:

--- NEW FILE autofs-5.0.3-update-replicated-doco.patch ---
autofs-5.0.3 - update replicated server selection documentation

From: Ian Kent <raven at themaw.net>

Update the replicated server selection README documentation to
reflect the selection rules now used.
---

 CHANGELOG                |    1 +
 README.replicated-server |   53 ++++++++++++++++++++++------------------------
 2 files changed, 26 insertions(+), 28 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index af3318a..be39e33 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -31,6 +31,7 @@
   umount during expire.
 - make mount of multi-mounts wuth a root offset atomic.
 - add replicated server selection debug logging.
+- update replicated server selection documentation.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/README.replicated-server b/README.replicated-server
index 333dea3..1d771d3 100644
--- a/README.replicated-server
+++ b/README.replicated-server
@@ -3,48 +3,45 @@ Supported forms for mount paths are:
 Normal single-host (these are unchanged)
 <path> host:/path/path
 
+Single host entries are not probed for a server response.
+
 Multiple replicated hosts, same path:
 <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
 <path> host1,host2:/blah host3:/some/other/path
 
-Works as expected
-
 Multiple replicated hosts, different (potentially) paths:
 <path> host1:/path/pathA host2:/path/pathB
 
-Same as above with RPC calls..
-
 Mutliple weighted, replicated hosts same path:
-
 <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:
 <path> 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:
-<path> 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
-
-Anything else, I ain't making no promises.
+For these formats a priority ordered list of hosts is created by using
+the following selection rules.
+
+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

autofs-5.0.3-use-dev-urandom.patch:

--- NEW FILE autofs-5.0.3-use-dev-urandom.patch ---
autofs-5.0.3 - use /dev/urandom instead of /dev/random

From: Ian Kent <raven at themaw.net>

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.
---

 CHANGELOG            |    1 +
 modules/replicated.c |    2 +-
 2 files changed, 2 insertions(+), 1 deletions(-)


diff --git a/CHANGELOG b/CHANGELOG
index be39e33..50c9a27 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -32,6 +32,7 @@
 - make mount of multi-mounts wuth a root offset atomic.
 - add replicated server selection debug logging.
 - update replicated server selection documentation.
+- use /dev/urandom instead of /dev/random.
  
 14/01/2008 autofs-5.0.3
 -----------------------
diff --git a/modules/replicated.c b/modules/replicated.c
index e41713e..362ab1b 100644
--- a/modules/replicated.c
+++ b/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;


Index: autofs.spec
===================================================================
RCS file: /cvs/pkgs/rpms/autofs/devel/autofs.spec,v
retrieving revision 1.249
retrieving revision 1.250
diff -u -r1.249 -r1.250
--- autofs.spec	14 Jul 2008 19:11:58 -0000	1.249
+++ autofs.spec	25 Aug 2008 04:47:37 -0000	1.250
@@ -4,7 +4,7 @@
 Summary: A tool for automatically mounting and unmounting filesystems
 Name: autofs
 Version: 5.0.3
-Release: 19
+Release: 21
 Epoch: 1
 License: GPLv2+
 Group: System Environment/Daemons
@@ -32,6 +32,27 @@
 Patch20: autofs-5.0.3-check-direct-path-len.patch
 Patch21: autofs-5.0.3-fix-get-user-info-check.patch
 Patch22: autofs-5.0.3-fix-couple-of-memory-leaks.patch
+Patch23: autofs-5.0.3-override-is-running-check.patch
+Patch24: autofs-5.0.3-dont-use-proc-for-is-running-check.patch
+Patch25: autofs-5.0.3-fix-included-browse-map-not-found.patch
+Patch26: autofs-5.0.3-fix-multi-source-messages.patch
+Patch27: autofs-5.0.3-clear-stale-on-map-read.patch
+Patch28: autofs-5.0.3-fix-proximity-other-timeout.patch
+Patch29: autofs-5.0.3-refactor-mount-request-vars.patch
+Patch30: autofs-5.0.3-make-handle_mounts-startup-cond-distinct.patch
+Patch31: autofs-5.0.3-submount-shutdown-recovery-12.patch
+Patch32: autofs-5.0.3-dont-block-on-expire.patch
+Patch33: autofs-5.0.3-add-umount_wait-parameter.patch
+Patch34: autofs-5.0.3-fix-multi-mount-race.patch
+Patch35: autofs-5.0.3-submount-shutdown-recovery-12-fix.patch
+Patch36: autofs-5.0.3-fix-nfs4-colon-escape.patch
+Patch37: autofs-5.0.3-check-replicated-list-after-probe.patch
+Patch38: autofs-5.0.3-add-replicated-debug-logging.patch
+Patch39: autofs-5.0.3-update-replicated-doco.patch
+Patch40: autofs-5.0.3-use-dev-urandom.patch
+Patch41: autofs-5.0.3-mtab-as-proc-mounts.patch
+Patch42: autofs-5.0.3-fix-ifc-buff-size.patch
+Patch43: autofs-5.0.3-fix-percent-hack.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
 Requires: kernel >= 2.6.17
@@ -147,6 +168,29 @@
 %{_libdir}/autofs/
 
 %changelog
+* Mon Aug 25 2008 Ian Kent <ikent at redhat.com> - 5.0.3-21
+- add upstream bug fix patches
+  - 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.
+
 * Mon Jul 14 2008 Tom "spot" Callaway <tcallawa at redhat.com> - 5.0.3-19
 - change conflicts to requires
 - fix license tag




More information about the fedora-extras-commits mailing list