Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 130701790bf2d95e902edf16031ff596 > files > 1

autofs-5.0.1-0.rc2.164.el5_8.src.rpm

autofs-5.0.3 - use miscellaneous device node, if available, for active restart

From: Ian Kent <raven@themaw.net>

There is a problem with active restarts in autofs (that is to say
restarting autofs when there are busy mounts).

Currently autofs uses "umount -l" to clear active mounts at restart.
While using lazy umount works for most cases, anything that needs to
walk back up the mount tree to construct a path, such as getcwd(2) and
the proc file system /proc/<pid>/cwd, no longer works because the point
from which the path is constructed has been detached from the mount tree.

The actual problem with autofs is that it can't reconnect to existing
mounts. Immediately one things of just adding the ability to remount
autofs file systems would solve it, but alas, that can't work. This is
because autofs direct mounts and the implementation of "on demand mount
and expire" of nested mount trees have the file system mounted on top of
the mount trigger dentry.

To resolve this a miscellaneous device node for routing ioctl commands
to these mount points has been implemented in the autofs4 kernel module
and a library added to autofs. This provides the ability to open a file
descriptor for these over mounted autofs mount points.

This patch adds the functionaility needed to utilize these new features
and re-construct a mount tree from existing mounts and then re-connect
them. Clrearly, the maps used must correspond to the existing mounts
for this to work, so changing maps between stopping and starting
autofs again may lead to inconsistencies.
---

 daemon/automount.c      |   15 +-
 daemon/direct.c         |  148 +++++++++++++++---------
 daemon/indirect.c       |   63 ++++++----
 daemon/lookup.c         |   12 +-
 daemon/mount.c          |    7 +
 daemon/state.c          |    2 
 include/automount.h     |   28 +++-
 include/mounts.h        |   10 +
 lib/cache.c             |   28 +++-
 lib/master.c            |    7 -
 lib/master_parse.y      |    2 
 lib/mounts.c            |  288 ++++++++++++++++++++++++++++++++++++++++++++++++
 modules/lookup_hosts.c  |    2 
 modules/mount_afs.c     |    3 
 modules/mount_autofs.c  |   11 +
 modules/mount_bind.c    |    8 +
 modules/mount_changer.c |    5 
 modules/mount_ext2.c    |    5 
 modules/mount_generic.c |    5 
 modules/mount_nfs.c     |    8 +
 modules/parse_sun.c     |  104 +++++++++--------
 21 files changed, 589 insertions(+), 172 deletions(-)


--- autofs-5.0.1.orig/daemon/automount.c
+++ autofs-5.0.1/daemon/automount.c
@@ -386,12 +386,12 @@ static void check_rm_dirs(struct autofs_
 	if (!incl && ap->submount)
 		return;
 
-	if ((!ap->ghost) ||
+	if ((!(ap->flags & MOUNT_FLAG_GHOST)) ||
 	    (ap->state == ST_SHUTDOWN_PENDING ||
 	     ap->state == ST_SHUTDOWN_FORCE ||
 	     ap->state == ST_SHUTDOWN))
 		rm_unwanted(ap->logopt, path, incl, ap->dev);
-	else if (ap->ghost && (ap->type == LKP_INDIRECT))
+	else if ((ap->flags & MOUNT_FLAG_GHOST) && (ap->type == LKP_INDIRECT))
 		rm_unwanted(ap->logopt, path, 0, ap->dev);
 }
 
@@ -482,7 +482,7 @@ static int umount_subtree_mounts(struct 
 
 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
 		/* Lock the closest parent nesting point for umount */
-		cache_multi_lock(me->parent);
+		cache_multi_writelock(me->parent);
 		if (umount_multi_triggers(ap, me, root, base)) {
 			warn(ap->logopt,
 			     "some offset mounts still present under %s", path);
@@ -1431,7 +1431,8 @@ static void handle_mounts_cleanup(void *
 	submount = ap->submount;
 
 	strcpy(path, ap->path);
-	if (!submount && strcmp(ap->path, "/-") && ap->dir_created)
+	if (!submount && strcmp(ap->path, "/-") &&
+	    ap->flags & MOUNT_FLAG_DIR_CREATED)
 		clean = 1;
 
 	if (submount) {
@@ -1511,7 +1512,7 @@ void *handle_mounts(void *arg)
 
 	free(root);
 
-	if (ap->ghost && ap->type != LKP_DIRECT)
+	if (ap->flags & MOUNT_FLAG_GHOST && ap->type != LKP_DIRECT)
 		info(ap->logopt, "ghosting enabled");
 
 	suc->status = 0;
@@ -1990,7 +1991,9 @@ int main(int argc, char *argv[])
 
 	if (!query_kproto_ver() || get_kver_major() < 5) {
 		fprintf(stderr,
-			"%s: kernel protocol version 5.00 or above required.\n",
+			"%s: test mount forbidden or "
+			"incorrect kernel protocol version, "
+			"kernel protocol version 5.00 or above required.\n",
 			program);
 		exit(1);
 	}
--- autofs-5.0.1.orig/daemon/direct.c
+++ autofs-5.0.1/daemon/direct.c
@@ -20,6 +20,7 @@
  * ----------------------------------------------------------------------- */
 
 #include <dirent.h>
+#include <libgen.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
@@ -178,7 +179,7 @@ force_umount:
 	} else
 		info(ap->logopt, "umounted direct mount %s", me->key);
 
-	if (!rv && me->dir_created) {
+	if (!rv && me->flags & MOUNT_FLAG_DIR_CREATED) {
 		if  (rmdir(me->key) == -1) {
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 			warn(ap->logopt, "failed to remove dir %s: %s",
@@ -279,15 +280,10 @@ static int unlink_mount_tree(struct auto
 	return ret;
 }
 
-int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
+static int unlink_active_mounts(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
 {
 	struct ioctl_ops *ops = get_ioctl_ops();
-	struct mnt_params *mp;
-	time_t timeout = ap->exp_timeout;
-	struct stat st;
-	int status, ret, ioctlfd;
 	struct list_head list;
-	const char *map_name;
 
 	INIT_LIST_HEAD(&list);
 
@@ -316,18 +312,55 @@ int do_mount_autofs_direct(struct autofs
 
 			return 0;
 		}
+	}
 
-		if (!unlink_mount_tree(ap, &list)) {
-			debug(ap->logopt,
-			      "already mounted as other than autofs "
-			      "or failed to unlink entry in tree");
-			return -1;
-		}
+	if (!unlink_mount_tree(ap, &list)) {
+		debug(ap->logopt,
+		      "already mounted as other than autofs "
+		      "or failed to unlink entry in tree");
+		return 0;
 	}
 
-	if (me->ioctlfd != -1) {
-		error(ap->logopt, "active direct mount %s", me->key);
-		return -1;
+	return 1;
+}
+
+int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me)
+{
+	const char *str_direct = mount_type_str(t_direct);
+	struct ioctl_ops *ops = get_ioctl_ops();
+	struct mnt_params *mp;
+	time_t timeout = ap->exp_timeout;
+	struct stat st;
+	int status, ret, ioctlfd;
+	const char *map_name;
+
+	/* Calculate the timeouts */
+	ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
+
+	if (ops->version) {
+		ap->flags |= MOUNT_FLAG_REMOUNT;
+		ret = try_remount(ap, me, t_direct);
+		ap->flags &= ~MOUNT_FLAG_REMOUNT;
+		if (ret == 1)
+			return 0;
+		if (ret == 0)
+			return -1;
+	} else {
+		/*
+		 * A return of 0 indicates we're re-reading the map.
+		 * A return of 1 indicates we successfully unlinked
+		 * the mount tree if there was one. A return of -1
+		 * inducates we failed to unlink the mount tree so
+		 * we have to return a failure.
+		 */
+		ret = unlink_active_mounts(ap, mnts, me);
+		if (ret == -1 || ret == 0)
+			return ret;
+
+		if (me->ioctlfd != -1) {
+			error(ap->logopt, "active direct mount %s", me->key);
+			return -1;
+		}
 	}
 
 	status = pthread_once(&key_mnt_params_once, key_mnt_params_init);
@@ -353,7 +386,7 @@ int do_mount_autofs_direct(struct autofs
 	}
 
 	if (!mp->options) {
-		mp->options = make_options_string(ap->path, ap->kpipefd, "direct");
+		mp->options = make_options_string(ap->path, ap->kpipefd, str_direct);
 		if (!mp->options)
 			return 0;
 	}
@@ -367,10 +400,10 @@ int do_mount_autofs_direct(struct autofs
 		}
 		/* If we recieve an error, and it's EEXIST or EROFS we know
 		   the directory was not created. */
-		me->dir_created = 0;
+		me->flags &= ~MOUNT_FLAG_DIR_CREATED;
 	} else {
 		/* No errors so the directory was successfully created */
-		me->dir_created = 1;
+		me->flags |= MOUNT_FLAG_DIR_CREATED;
 	}
 
 	map_name = me->mc->map->argv[0];
@@ -394,24 +427,9 @@ int do_mount_autofs_direct(struct autofs
 		goto out_umount;
 	}
 
-	/* Calculate the timeouts */
-	ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
-
 	ops->timeout(ap->logopt, ioctlfd, &timeout);
-
-	if (ap->exp_timeout)
-		info(ap->logopt,
-		    "mounted direct mount on %s "
-		    "with timeout %u, freq %u seconds", me->key,
-		    (unsigned int) ap->exp_timeout,
-		    (unsigned int) ap->exp_runfreq);
-	else
-		info(ap->logopt,
-		     "mounted direct mount on %s with timeouts disabled",
-		     me->key);
-
+	notify_mount_result(ap, me->key, str_direct);
 	cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
-
 	ops->close(ap->logopt, ioctlfd);
 
 	debug(ap->logopt, "mounted trigger %s", me->key);
@@ -422,7 +440,7 @@ out_umount:
 	/* TODO: maybe force umount (-l) */
 	umount(me->key);
 out_err:
-	if (me->dir_created)
+	if (me->flags & MOUNT_FLAG_DIR_CREATED)
 		rmdir(me->key);
 
 	return -1;
@@ -454,8 +472,6 @@ int mount_autofs_direct(struct autofs_po
 	pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
 	master_source_readlock(ap->entry);
 	nc = ap->entry->master->nc;
-	cache_readlock(nc);
-	pthread_cleanup_push(cache_lock_cleanup, nc);
 	map = ap->entry->maps;
 	while (map) {
 		/*
@@ -468,8 +484,6 @@ int mount_autofs_direct(struct autofs_po
 		}
 
 		mc = map->mc;
-		pthread_cleanup_push(cache_lock_cleanup, mc);
-		cache_readlock(mc);
 		me = cache_enumerate(mc, NULL);
 		while (me) {
 			ne = cache_lookup_distinct(nc, me->key);
@@ -497,12 +511,10 @@ int mount_autofs_direct(struct autofs_po
 
 			me = cache_enumerate(mc, me);
 		}
-		pthread_cleanup_pop(1);
 		map = map->next;
 	}
 	pthread_cleanup_pop(1);
 	pthread_cleanup_pop(1);
-	pthread_cleanup_pop(1);
 
 	return 0;
 }
@@ -608,7 +620,7 @@ force_umount:
 	} else
 		info(ap->logopt, "umounted offset mount %s", me->key);
 
-	if (!rv && me->dir_created) {
+	if (!rv && me->flags & MOUNT_FLAG_DIR_CREATED) {
 		if  (rmdir(me->key) == -1) {
 			char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
 			warn(ap->logopt, "failed to remove dir %s: %s",
@@ -620,6 +632,7 @@ force_umount:
 
 int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset)
 {
+	const char *str_offset = mount_type_str(t_offset);
 	struct ioctl_ops *ops = get_ioctl_ops();
 	char buf[MAX_ERR_BUF];
 	struct mnt_params *mp;
@@ -629,16 +642,24 @@ int mount_autofs_offset(struct autofs_po
 	const char *type, *map_name = NULL;
 	char mountpoint[PATH_MAX];
 
-	if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) {
-		if (ap->state != ST_READMAP)
-			warn(ap->logopt,
-			      "trigger %s already mounted", me->key);
-		return MOUNT_OFFSET_OK;
-	}
-
-	if (me->ioctlfd != -1) {
-		error(ap->logopt, "active offset mount %s", me->key);
+	if (ops->version && ap->flags & MOUNT_FLAG_REMOUNT) {
+		ret = try_remount(ap, me, t_offset);
+		if (ret == 1)
+			return MOUNT_OFFSET_OK;
 		return MOUNT_OFFSET_FAIL;
+	} else {
+/*
+		if (is_mounted(_PROC_MOUNTS, me->key, MNTS_AUTOFS)) {
+			if (ap->state != ST_READMAP)
+				warn(ap->logopt,
+				     "trigger %s already mounted", me->key);
+			return MOUNT_OFFSET_OK;
+		}
+*/
+		if (me->ioctlfd != -1) {
+			error(ap->logopt, "active offset mount %s", me->key);
+			return MOUNT_OFFSET_FAIL;
+		}
 	}
 
 	status = pthread_once(&key_mnt_params_once, key_mnt_params_init);
@@ -664,7 +685,7 @@ int mount_autofs_offset(struct autofs_po
 	}
 
 	if (!mp->options) {
-		mp->options = make_options_string(ap->path, ap->kpipefd, "offset");
+		mp->options = make_options_string(ap->path, ap->kpipefd, str_offset);
 		if (!mp->options)
 			return MOUNT_OFFSET_OK;
 	}
@@ -689,7 +710,7 @@ int mount_autofs_offset(struct autofs_po
 			 * If we recieve an error, and it's EEXIST
 			 * we know the directory was not created.
 			 */
-			me->dir_created = 0;
+			me->flags &= ~MOUNT_FLAG_DIR_CREATED;
 		} else if (errno == EACCES) {
 			/*
 			 * We require the mount point directory to exist when
@@ -713,7 +734,7 @@ int mount_autofs_offset(struct autofs_po
 		}
 	} else {
 		/* No errors so the directory was successfully created */
-		me->dir_created = 1;
+		me->flags |= MOUNT_FLAG_DIR_CREATED;
 	}
 
 	debug(ap->logopt,
@@ -753,6 +774,10 @@ int mount_autofs_offset(struct autofs_po
 
 	ops->timeout(ap->logopt, ioctlfd, &timeout);
 	cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
+	if (ap->logopt & LOGOPT_DEBUG)
+		notify_mount_result(ap, mountpoint, str_offset);
+	else
+		notify_mount_result(ap, me->key, str_offset);
 	ops->close(ap->logopt, ioctlfd);
 
 	debug(ap->logopt, "mounted trigger %s at %s", me->key, mountpoint);
@@ -762,7 +787,7 @@ int mount_autofs_offset(struct autofs_po
 out_umount:
 	umount(mountpoint);
 out_err:
-	if (stat(mountpoint, &st) == 0 && me->dir_created)
+	if (stat(mountpoint, &st) == 0 && me->flags & MOUNT_FLAG_DIR_CREATED)
 		 rmdir_path(ap, mountpoint, st.st_dev);
 
 	return MOUNT_OFFSET_FAIL;
@@ -804,6 +829,7 @@ void *expire_proc_direct(void *arg)
 
 	left = 0;
 
+	pthread_cleanup_push(mnts_cleanup, mnts);
 	mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
 
 	/* Get a list of mounts select real ones and expire them if possible */
@@ -812,7 +838,6 @@ void *expire_proc_direct(void *arg)
 		ec.status = 0;
 		return NULL;
 	}
-	pthread_cleanup_push(mnts_cleanup, mnts);
 
 	list_for_each(p, &list) {
 		next = list_entry(p, struct mnt_list, list);
@@ -1070,6 +1095,7 @@ int handle_packet_expire_direct(struct a
 		crit(ap->logopt, "can't find map entry for (%lu,%lu)",
 		    (unsigned long) pkt->dev, (unsigned long) pkt->ino);
 		master_source_unlock(ap->entry);
+		master_mutex_unlock();
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -1303,6 +1329,8 @@ int handle_packet_missing_direct(struct 
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
+	master_mutex_lock();
+
 	/*
 	 * If our parent is a direct or offset mount that has been
 	 * covered by a mount and another lookup occurs after the
@@ -1354,6 +1382,7 @@ int handle_packet_missing_direct(struct 
 	if (ioctlfd == -1) {
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
+		master_mutex_unlock();
 		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 ?? */
@@ -1370,6 +1399,7 @@ int handle_packet_missing_direct(struct 
 		ops->close(ap->logopt, ioctlfd);
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
+		master_mutex_unlock();
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -1383,6 +1413,7 @@ int handle_packet_missing_direct(struct 
 		ops->close(ap->logopt, ioctlfd);
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
+		master_mutex_unlock();
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -1418,6 +1449,7 @@ int handle_packet_missing_direct(struct 
 		ops->close(ap->logopt, ioctlfd);
 		cache_unlock(mc);
 		master_source_unlock(ap->entry);
+		master_mutex_unlock();
 		mount_mutex_unlock(mt);
 		pending_cond_destroy(mt);
 		pending_mutex_destroy(mt);
@@ -1429,6 +1461,8 @@ int handle_packet_missing_direct(struct 
 	cache_unlock(mc);
 	master_source_unlock(ap->entry);
 
+	master_mutex_unlock();
+
 	pthread_cleanup_push(free_pending_args, mt);
 	pthread_cleanup_push(pending_mutex_destroy, mt);
 	pthread_cleanup_push(pending_cond_destroy, mt);
--- autofs-5.0.1.orig/daemon/indirect.c
+++ autofs-5.0.1/daemon/indirect.c
@@ -20,6 +20,7 @@
  * ----------------------------------------------------------------------- */
 
 #include <dirent.h>
+#include <libgen.h>
 #include <fcntl.h>
 #include <signal.h>
 #include <stdio.h>
@@ -32,6 +33,7 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/mount.h>
+#include <sys/vfs.h>
 #include <sched.h>
 
 #include "automount.h"
@@ -86,6 +88,7 @@ static int unlink_mount_tree(struct auto
 
 static int do_mount_autofs_indirect(struct autofs_point *ap, const char *root)
 {
+	const char *str_indirect = mount_type_str(t_indirect);
 	struct ioctl_ops *ops = get_ioctl_ops();
 	time_t timeout = ap->exp_timeout;
 	char *options = NULL;
@@ -94,19 +97,31 @@ static int do_mount_autofs_indirect(stru
 	struct mnt_list *mnts;
 	int ret;
 
-	mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 1);
-	if (mnts) {
-		ret = unlink_mount_tree(ap, mnts);
-		free_mnt_list(mnts);
-		if (!ret) {
-			error(ap->logopt,
-			      "already mounted as other than autofs "
-			      "or failed to unlink entry in tree");
-			goto out_err;
+	ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
+
+	if (ops->version) {
+		ap->flags |= MOUNT_FLAG_REMOUNT;
+		ret = try_remount(ap, NULL, t_indirect);
+		ap->flags &= ~MOUNT_FLAG_REMOUNT;
+		if (ret == 1)
+			return 0;
+		if (ret == 0)
+			return -1;
+	} else {
+		mnts = get_mnt_list(_PROC_MOUNTS, ap->path, 1);
+		if (mnts) {
+			ret = unlink_mount_tree(ap, mnts);
+			free_mnt_list(mnts);
+			if (!ret) {
+				error(ap->logopt,
+				      "already mounted as other than autofs "
+				      "or failed to unlink entry in tree");
+				goto out_err;
+			}
 		}
 	}
 
-	options = make_options_string(ap->path, ap->kpipefd, NULL);
+	options = make_options_string(ap->path, ap->kpipefd, str_indirect);
 	if (!options) {
 		error(ap->logopt, "options string error");
 		goto out_err;
@@ -122,10 +137,10 @@ static int do_mount_autofs_indirect(stru
 		}
 		/* If we recieve an error, and it's EEXIST or EROFS we know
 		   the directory was not created. */
-		ap->dir_created = 0;
+		ap->flags &= ~MOUNT_FLAG_DIR_CREATED;
 	} else {
 		/* No errors so the directory was successfully created */
-		ap->dir_created = 1;
+		ap->flags |= MOUNT_FLAG_DIR_CREATED;
 	}
 
 	type = ap->entry->maps->type;
@@ -166,24 +181,17 @@ static int do_mount_autofs_indirect(stru
 	ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
 
 	ops->timeout(ap->logopt, ap->ioctlfd, &timeout);
-
-	if (ap->exp_timeout)
-		info(ap->logopt,
-		    "mounted indirect mount for %s "
-		    "with timeout %u, freq %u seconds", ap->path,
-	 	    (unsigned int) ap->exp_timeout,
-		    (unsigned int) ap->exp_runfreq);
+	if (ap->logopt & LOGOPT_DEBUG)
+		notify_mount_result(ap, root, str_indirect);
 	else
-		info(ap->logopt,
-		    "mounted indirect mount for %s with timeouts disabled",
-		    ap->path);
+		notify_mount_result(ap, ap->path, str_indirect);
 
 	return 0;
 
 out_umount:
 	umount(root);
 out_rmdir:
-	if (ap->dir_created)
+	if (ap->flags & MOUNT_FLAG_DIR_CREATED)
 		rmdir(root);
 out_err:
 	if (options)
@@ -228,7 +236,7 @@ int mount_autofs_indirect(struct autofs_
 	}
 
 	if (map & LKP_NOTSUP)
-		ap->ghost = 0;
+		ap->flags &= ~MOUNT_FLAG_GHOST;
 
 	return 0;
 }
@@ -784,6 +792,8 @@ int handle_packet_missing_indirect(struc
 
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
 
+	master_mutex_lock();
+
 	debug(ap->logopt, "token %ld, name %s, request pid %u",
 		(unsigned long) pkt->wait_queue_token, pkt->name, pkt->pid);
 
@@ -791,6 +801,7 @@ int handle_packet_missing_indirect(struc
 	if (ap->shutdown || ap->state == ST_SHUTDOWN_FORCE) {
 		ops->send_fail(ap->logopt,
 			       ap->ioctlfd, pkt->wait_queue_token, -ENOENT);
+		master_mutex_unlock();
 		pthread_setcancelstate(state, NULL);
 		return 0;
 	}
@@ -801,6 +812,7 @@ int handle_packet_missing_indirect(struc
 		logerr("malloc: %s", estr);
 		ops->send_fail(ap->logopt,
 			       ap->ioctlfd, pkt->wait_queue_token, -ENOMEM);
+		master_mutex_unlock();
 		pthread_setcancelstate(state, NULL);
 		return 1;
 	}
@@ -832,6 +844,7 @@ int handle_packet_missing_indirect(struc
 		error(ap->logopt, "expire thread create failed");
 		ops->send_fail(ap->logopt,
 			       ap->ioctlfd, pkt->wait_queue_token, -status);
+		master_mutex_unlock();
 		mount_mutex_unlock(mt);
 		pending_cond_destroy(mt);
 		pending_mutex_destroy(mt);
@@ -840,6 +853,8 @@ int handle_packet_missing_indirect(struc
 		return 1;
 	}
 
+	master_mutex_unlock();
+
 	pthread_cleanup_push(free_pending_args, mt);
 	pthread_cleanup_push(pending_mutex_destroy, mt);
 	pthread_cleanup_push(pending_cond_destroy, mt);
--- autofs-5.0.1.orig/daemon/lookup.c
+++ autofs-5.0.1/daemon/lookup.c
@@ -290,7 +290,7 @@ static int do_read_map(struct autofs_poi
 	 * file scanning.
 	 */
 	if (strcmp(map->type, "file") &&
-	    !ap->ghost && ap->type != LKP_DIRECT)
+	    !(ap->flags & MOUNT_FLAG_GHOST) && ap->type != LKP_DIRECT)
 		return NSS_STATUS_SUCCESS;
 
 	if (!map->stale)
@@ -580,7 +580,7 @@ int lookup_ghost(struct autofs_point *ap
 	if (!strcmp(ap->path, "/-"))
 		return LKP_FAIL | LKP_DIRECT;
 
-	if (!ap->ghost)
+	if (!(ap->flags & MOUNT_FLAG_GHOST))
 		return LKP_INDIRECT;
 
 	pthread_cleanup_push(master_source_lock_cleanup, entry);
@@ -945,7 +945,8 @@ int lookup_nss_mount(struct autofs_point
 
 		map = map->next;
 	}
-	send_map_update_request(ap);
+	if (ap->state != ST_INIT)
+		send_map_update_request(ap);
 	pthread_cleanup_pop(1);
 
 	/*
@@ -1086,7 +1087,7 @@ int lookup_prune_cache(struct autofs_poi
 					status = cache_delete(mc, key);
 				if (status != CHE_FAIL) {
 					if (ap->type == LKP_INDIRECT) {
-						if (ap->ghost)
+						if (ap->flags & MOUNT_FLAG_GHOST)
 							rmdir_path(ap, path, ap->dev);
 					} else
 						rmdir_path(ap, path, this->dev);
@@ -1175,6 +1176,9 @@ struct mapent *lookup_source_mapent(stru
 		map = map->next;
 	}
 
+	if (me && me->mc != mc)
+		error(LOGOPT_ANY, "mismatching mc in cache", me->key);
+
 	return me;
 }
 
--- autofs-5.0.1.orig/daemon/mount.c
+++ autofs-5.0.1/daemon/mount.c
@@ -35,6 +35,7 @@ int do_mount(struct autofs_point *ap, co
 {
 	struct mount_mod *mod;
 	const char *modstr;
+	size_t root_len = root ? strlen(root) : 0;
 	char **ngp;
 	int rv;
 
@@ -61,10 +62,14 @@ int do_mount(struct autofs_point *ap, co
 		}
 	}
 
-	if (ap->type == LKP_DIRECT)
+	if (*name == '/')
 		debug(ap->logopt,
 		      "%s %s type %s options %s using module %s",
 		      what, name, fstype, options, modstr);
+	else if (root_len > 1 && root[root_len - 1] == '/')
+		debug(ap->logopt,
+		      "%s %s type %s options %s using module %s",
+		      what, root, fstype, options, modstr);
 	else
 		debug(ap->logopt,
 		      "%s %s/%s type %s options %s using module %s",
--- autofs-5.0.1.orig/daemon/state.c
+++ autofs-5.0.1/daemon/state.c
@@ -52,8 +52,6 @@ void st_mutex_unlock(void)
 		fatal(status);
 }
 
-int do_mount_autofs_direct(struct autofs_point *, struct mnt_list *, struct mapent *);
-
 void dump_state_queue(void)
 {
 	struct list_head *head = &state_queue;
--- autofs-5.0.1.orig/include/automount.h
+++ autofs-5.0.1/include/automount.h
@@ -30,6 +30,7 @@
 #include "rpc_subs.h"
 #include "mounts.h"
 #include "parse_subs.h"
+#include "mounts.h"
 #include "dev-ioctl-lib.h"
 
 #ifdef WITH_DMALLOC
@@ -143,7 +144,7 @@ struct mapent_cache {
 struct mapent {
 	struct mapent *next;
 	struct list_head ino_index;
-	pthread_mutex_t multi_mutex;
+	pthread_rwlock_t multi_rwlock;
 	struct list_head multi_list;
 	struct mapent_cache *mc;
 	struct map_source *source;
@@ -157,7 +158,7 @@ struct mapent {
 	/* Time of last mount fail */
 	unsigned int status;
 	/* For direct mounts per entry context is kept here */
-	int dir_created;
+	int flags;
 	/* File descriptor for ioctls */
 	int ioctlfd;
 	dev_t dev;
@@ -186,7 +187,8 @@ int cache_add_offset(struct mapent_cache
 int cache_set_parents(struct mapent *mm);
 int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age);
 int cache_delete(struct mapent_cache *mc, const char *key);
-void cache_multi_lock(struct mapent *me);
+void cache_multi_readlock(struct mapent *me);
+void cache_multi_writelock(struct mapent *me);
 void cache_multi_unlock(struct mapent *me);
 int cache_delete_offset_list(struct mapent_cache *mc, const char *key);
 void cache_release(struct map_source *map);
@@ -384,6 +386,18 @@ struct kernel_mod_version {
 	unsigned int minor;
 };
 
+/* Enable/disable gohsted directories */
+#define MOUNT_FLAG_GHOST		0x0001
+
+/* Directory created for this mount? */
+#define MOUNT_FLAG_DIR_CREATED		0x0002
+
+/* Use random policy when selecting a host from which to mount */
+#define MOUNT_FLAG_RANDOM_SELECT	0x0004
+
+/* Mount being re-mounted */
+#define MOUNT_FLAG_REMOUNT		0x0008
+
 struct autofs_point {
 	pthread_t thid;
 	char *path;			/* Mount point name */
@@ -397,15 +411,12 @@ struct autofs_point {
 	time_t exp_timeout;		/* Timeout for expiring mounts */
 	time_t exp_runfreq;		/* Frequency for polling for timeouts */
 	time_t negative_timeout;	/* timeout in secs for failed mounts */
-	unsigned ghost;			/* Enable/disable gohsted directories */
-	unsigned logopt;		/* Per map logging */
+	unsigned int flags;		/* autofs mount flags */
+	unsigned int logopt;		/* Per map logging */
 	pthread_t exp_thread;		/* Thread that is expiring */
 	pthread_t readmap_thread;	/* Thread that is reading maps */
 	enum states state;		/* Current state */
 	int state_pipe[2];		/* State change router pipe */
-	unsigned dir_created;		/* Directory created for this mount? */
-	unsigned random_selection;	/* Use random policy when selecting a
-					 * host from which to mount */
 	struct autofs_point *parent;	/* Owner of mounts list for submount */
 	pthread_mutex_t mounts_mutex;	/* Protect mount lists */
 	struct list_head mounts;	/* List of autofs mounts at current level */
@@ -428,6 +439,7 @@ 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, const char *root);
+int do_mount_autofs_direct(struct autofs_point *ap, struct mnt_list *mnts, struct mapent *me);
 int mount_autofs_direct(struct autofs_point *ap);
 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);
--- autofs-5.0.1.orig/include/mounts.h
+++ autofs-5.0.1/include/mounts.h
@@ -34,9 +34,10 @@
 #define MNTS_AUTOFS	0x0004
 
 #define REMOUNT_SUCCESS		0x0000
-#define REMOUNT_OPEN_FAIL	0x0001
-#define REMOUNT_STAT_FAIL	0x0002
-#define REMOUNT_READ_MAP	0x0004
+#define REMOUNT_FAIL		0x0001
+#define REMOUNT_OPEN_FAIL	0x0002
+#define REMOUNT_STAT_FAIL	0x0004
+#define REMOUNT_READ_MAP	0x0008
 
 extern const unsigned int t_indirect;
 extern const unsigned int t_direct;
@@ -92,6 +93,9 @@ int tree_get_mnt_sublist(struct mnt_list
 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);
+const char *mount_type_str(unsigned int);
+void notify_mount_result(struct autofs_point *, const char *, const char *);
+int try_remount(struct autofs_point *, struct mapent *, unsigned int);
 int umount_ent(struct autofs_point *, 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 *);
--- autofs-5.0.1.orig/lib/cache.c
+++ autofs-5.0.1/lib/cache.c
@@ -111,14 +111,29 @@ void cache_lock_cleanup(void *arg)
 	return;
 }
 
-void cache_multi_lock(struct mapent *me)
+void cache_multi_readlock(struct mapent *me)
 {
 	int status;
 
 	if (!me)
 		return;
 
-	status = pthread_mutex_lock(&me->multi_mutex);
+	status = pthread_rwlock_rdlock(&me->multi_rwlock);
+	if (status) {
+		logmsg("mapent cache multi mutex lock failed");
+		fatal(status);
+	}
+	return;
+}
+
+void cache_multi_writelock(struct mapent *me)
+{
+	int status;
+
+	if (!me)
+		return;
+
+	status = pthread_rwlock_wrlock(&me->multi_rwlock);
 	if (status) {
 		logmsg("mapent cache multi mutex lock failed");
 		fatal(status);
@@ -133,7 +148,7 @@ void cache_multi_unlock(struct mapent *m
 	if (!me)
 		return;
 
-	status = pthread_mutex_unlock(&me->multi_mutex);
+	status = pthread_rwlock_unlock(&me->multi_rwlock);
 	if (status) {
 		logmsg("mapent cache multi mutex unlock failed");
 		fatal(status);
@@ -560,8 +575,9 @@ int cache_add(struct mapent_cache *mc, s
 	me->ioctlfd = -1;
 	me->dev = (dev_t) -1;
 	me->ino = (ino_t) -1;
+	me->flags = 0;
 
-	status = pthread_mutex_init(&me->multi_mutex, NULL);
+	status = pthread_rwlock_init(&me->multi_rwlock, NULL);
 	if (status)
 		fatal(status);
 
@@ -769,7 +785,7 @@ int cache_delete(struct mapent_cache *mc
 				goto done;
 			}
 			pred->next = me->next;
-			status = pthread_mutex_destroy(&me->multi_mutex);
+			status = pthread_rwlock_destroy(&me->multi_rwlock);
 			if (status)
 				fatal(status);
 			ino_index_lock(mc);
@@ -793,7 +809,7 @@ int cache_delete(struct mapent_cache *mc
 			goto done;
 		}
 		mc->hash[hashval] = me->next;
-		status = pthread_mutex_destroy(&me->multi_mutex);
+		status = pthread_rwlock_destroy(&me->multi_rwlock);
 		if (status)
 			fatal(status);
 		ino_index_lock(mc);
--- autofs-5.0.1.orig/lib/master.c
+++ autofs-5.0.1/lib/master.c
@@ -99,14 +99,15 @@ int master_add_autofs_point(struct maste
 	else
 		ap->negative_timeout = global_negative_timeout;
 	ap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
-	ap->ghost = ghost;
+	ap->flags = 0;
+	if (ghost)
+		ap->flags = MOUNT_FLAG_GHOST;
 
 	if (ap->path[1] == '-')
 		ap->type = LKP_DIRECT;
 	else
 		ap->type = LKP_INDIRECT;
 
-	ap->dir_created = 0;
 	ap->logopt = logopt;
 
 	ap->parent = NULL;
@@ -479,7 +480,7 @@ void send_map_update_request(struct auto
 	struct map_source *map;
 	int status, need_update = 0;
 
-	if (!ap->ghost)
+	if (!(ap->flags & MOUNT_FLAG_GHOST))
 		return;
 
 	status = pthread_mutex_lock(&instance_mutex);
--- autofs-5.0.1.orig/lib/master_parse.y
+++ autofs-5.0.1/lib/master_parse.y
@@ -813,7 +813,7 @@ int master_parse_entry(const char *buffe
 				ops->timeout(ap->logopt, ap->ioctlfd, &tout);
 		}
 	}
-	entry->ap->random_selection = random_selection;
+	entry->ap->flags |= MOUNT_FLAG_RANDOM_SELECT;
 	if (negative_timeout)
 		entry->ap->negative_timeout = negative_timeout;
 
--- autofs-5.0.1.orig/lib/mounts.c
+++ autofs-5.0.1/lib/mounts.c
@@ -1072,6 +1072,294 @@ free_tsv:
 	return;
 }
 
+const char *mount_type_str(const unsigned int type)
+{
+	static const char *str_type[] = {
+		"indirect",
+		"direct",
+		"offset"
+	};
+	unsigned int pos, i;
+
+	for (pos = 0, i = type; pos < type_count; i >>= 1, pos++)
+		if (i & 0x1)
+			break;
+
+	return (pos == type_count ? NULL : str_type[pos]);
+}
+
+void notify_mount_result(struct autofs_point *ap,
+			 const char *path, const char *type)
+{
+	if (ap->exp_timeout)
+		info(ap->logopt,
+		    "mounted %s on %s with timeout %u, freq %u seconds",
+		    type, path,
+		    (unsigned int) ap->exp_timeout,
+		    (unsigned int) ap->exp_runfreq);
+	else
+		info(ap->logopt,
+		     "mounted %s on %s with timeouts disabled",
+		     type, path);
+
+	return;
+}
+
+static int do_remount_direct(struct autofs_point *ap, int fd, const char *path)
+{
+	struct ioctl_ops *ops = get_ioctl_ops();
+	int status = REMOUNT_SUCCESS;
+	uid_t uid;
+	gid_t gid;
+	int ret;
+
+	ops->requestor(ap->logopt, fd, path, &uid, &gid);
+	if (uid != -1 && gid != -1)
+		set_tsd_user_vars(ap->logopt, uid, gid);
+
+	ret = lookup_nss_mount(ap, NULL, path, strlen(path));
+	if (ret)
+		info(ap->logopt, "re-connected to %s", path);
+	else {
+		status = REMOUNT_FAIL;
+		info(ap->logopt, "failed to re-connect %s", path);
+	}
+
+	return status;
+}
+
+static int do_remount_indirect(struct autofs_point *ap, int fd, const char *path)
+{
+	struct ioctl_ops *ops = get_ioctl_ops();
+	int status = REMOUNT_SUCCESS;
+	struct dirent **de;
+	char buf[PATH_MAX + 1];
+	uid_t uid;
+	gid_t gid;
+	unsigned int mounted;
+	int n, size;
+
+	n = scandir(path, &de, 0, alphasort);
+	if (n < 0)
+		return -1;
+
+	size = sizeof(buf);
+
+	while (n--) {
+		int ret, len;
+
+		if (strcmp(de[n]->d_name, ".") == 0 ||
+		    strcmp(de[n]->d_name, "..") == 0) {
+			free(de[n]);
+			continue;
+		}
+
+		ret = cat_path(buf, size, path, de[n]->d_name);
+		if (!ret) {
+			do {
+				free(de[n]);
+			} while (n--);
+			free(de);
+			return -1;
+		}
+
+		ops->ismountpoint(ap->logopt, -1, buf, &mounted);
+		if (!mounted) {
+			struct dirent **de2;
+			int i, j;
+
+			i = j = scandir(buf, &de2, 0, alphasort);
+			while (i--)
+				free(de2[i]);
+			free(de2);
+			if (j <= 2) {
+				free(de[n]);
+				continue;
+			}
+		}
+
+		ops->requestor(ap->logopt, fd, buf, &uid, &gid);
+		if (uid != -1 && gid != -1)
+			set_tsd_user_vars(ap->logopt, uid, gid);
+
+		len = strlen(de[n]->d_name);
+
+		ret = lookup_nss_mount(ap, NULL, de[n]->d_name, len);
+		if (ret)
+			info(ap->logopt, "re-connected to %s", buf);
+		else {
+			status = REMOUNT_FAIL;
+			info(ap->logopt, "failed to re-connect %s", buf);
+		}
+		free(de[n]);
+	}
+	free(de);
+
+	return status;
+}
+
+static int remount_active_mount(struct autofs_point *ap,
+				struct mapent_cache *mc,
+				const char *path, dev_t devid,
+				const unsigned int type,
+				int *ioctlfd)
+{
+	struct ioctl_ops *ops = get_ioctl_ops();
+	time_t timeout = ap->exp_timeout;
+	const char *str_type = mount_type_str(type);
+	char buf[MAX_ERR_BUF];
+	unsigned int mounted;
+	struct stat st;
+	int fd;
+
+	*ioctlfd = -1;
+
+	/* Open failed, no mount present */
+	ops->open(ap->logopt, &fd, devid, path);
+	if (fd == -1)
+		return REMOUNT_OPEN_FAIL;
+
+	/* Re-reading the map, set timeout and return */
+	if (ap->state == ST_READMAP) {
+		ops->timeout(ap->logopt, fd, &timeout);
+		ops->close(ap->logopt, fd);
+		return REMOUNT_READ_MAP;
+	}
+
+	debug(ap->logopt, "trying to re-connect to mount %s", path);
+
+	/* Mounted so set pipefd and timeout etc. */
+	if (ops->catatonic(ap->logopt, fd) == -1) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(ap->logopt, "set catatonic failed: %s", estr);
+		debug(ap->logopt, "couldn't re-connect to mount %s", path);
+		ops->close(ap->logopt, fd);
+		return REMOUNT_OPEN_FAIL;
+	}
+	if (ops->setpipefd(ap->logopt, fd, ap->kpipefd) == -1) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(ap->logopt, "set pipefd failed: %s", estr);
+		debug(ap->logopt, "couldn't re-connect to mount %s", path);
+		ops->close(ap->logopt, fd);
+		return REMOUNT_OPEN_FAIL;
+	}
+	ops->timeout(ap->logopt, fd, &timeout);
+	if (fstat(fd, &st) == -1) {
+		error(ap->logopt,
+		      "failed to stat %s mount %s", str_type, path);
+		debug(ap->logopt, "couldn't re-connect to mount %s", path);
+		ops->close(ap->logopt, fd);
+		return REMOUNT_STAT_FAIL;
+	}
+	if (mc)
+		cache_set_ino_index(mc, path, st.st_dev, st.st_ino);
+	else
+		ap->dev = st.st_dev;
+	notify_mount_result(ap, path, str_type);
+
+	*ioctlfd = fd;
+
+	/* Any mounts on or below? */
+	if (ops->ismountpoint(ap->logopt, fd, path, &mounted) == -1) {
+		char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(ap->logopt, "ismountpoint %s failed: %s", path, estr);
+		debug(ap->logopt, "couldn't re-connect to mount %s", path);
+		ops->close(ap->logopt, fd);
+		return REMOUNT_FAIL;
+	}
+	if (!mounted) {
+		/*
+		 * If we're an indirect mount we pass back the fd.
+		 * But if were a direct or offset mount with no active
+		 * mount we don't retain an open file descriptor.
+		 */
+		if (type != t_indirect) {
+			ops->close(ap->logopt, fd);
+			*ioctlfd = -1;
+		}
+	} else {
+		int ret;
+		/*
+		 * What can I do if we can't remount the existing
+		 * mount(s) (possibly a partial failure), everything
+		 * following will be broken?
+		 */
+		if (type == t_indirect)
+			ret = do_remount_indirect(ap, fd, path);
+		else
+			ret = do_remount_direct(ap, fd, path);
+	}
+
+	debug(ap->logopt, "re-connected to mount %s", path);
+
+	return REMOUNT_SUCCESS;
+}
+
+int try_remount(struct autofs_point *ap, struct mapent *me, unsigned int type)
+{
+	struct ioctl_ops *ops = get_ioctl_ops();
+	struct mapent_cache *mc;
+	const char *path;
+	int ret, fd;
+	dev_t devid;
+
+	if (type == t_indirect) {
+		mc = NULL;
+		path = ap->path;
+	} else {
+		mc = me->mc;
+		path = me->key;
+	}
+
+	ret = ops->mount_device(ap->logopt, path, type, &devid);
+	if (ret == -1 || ret == 0)
+		return -1;
+
+	ret = remount_active_mount(ap, mc, path, devid, type, &fd);
+
+	/*
+	 * The directory must exist since we found a device
+	 * number for the mount but we can't know if we created
+	 * it or not. However, if this is an indirect mount with
+	 * the nobrowse option we need to remove the mount point
+	 * directory at umount anyway.
+	 */
+	if (type == t_indirect) {
+		if (ap->flags & MOUNT_FLAG_GHOST)
+			ap->flags &= ~MOUNT_FLAG_DIR_CREATED;
+		else
+			ap->flags |= MOUNT_FLAG_DIR_CREATED;
+	} else
+		me->flags &= ~MOUNT_FLAG_DIR_CREATED;
+
+	/*
+	 * Either we opened the mount or we're re-reading the map.
+	 * If we opened the mount and ioctlfd is not -1 we have
+	 * a descriptor for the indirect mount so we need to
+	 * record that in the mount point struct. Otherwise we're
+	 * re-reading the map.
+	*/
+	if (ret == REMOUNT_SUCCESS || ret == REMOUNT_READ_MAP) {
+		if (fd != -1) {
+			if (type == t_indirect)
+				ap->ioctlfd = fd;
+			else
+				me->ioctlfd = fd;
+			return 1;
+		}
+
+		/* Indirect mount requires a valid fd */
+		if (type != t_indirect)
+			return 1;
+	}
+
+	/*
+	 * Since we got the device number above a mount exists so
+	 * any other failure warrants a failure return here.
+	 */
+	return 0;
+}
+
 int umount_ent(struct autofs_point *ap, const char *path)
 {
 	int rv;
--- autofs-5.0.1.orig/modules/lookup_hosts.c
+++ autofs-5.0.1/modules/lookup_hosts.c
@@ -156,7 +156,7 @@ int lookup_mount(struct autofs_point *ap
 		 * We haven't read the list of hosts into the
 		 * cache so go straight to the lookup.
 		 */
-		if (!ap->ghost) {
+		if (!(ap->flags & MOUNT_FLAG_GHOST)) {
 			/*
 			 * If name contains a '/' we're searching for an
 			 * offset that doesn't exist in the export list
--- autofs-5.0.1.orig/modules/mount_afs.c
+++ autofs-5.0.1/modules/mount_afs.c
@@ -35,6 +35,9 @@ int mount_mount(struct autofs_point *ap,
 	size_t r_len = strlen(root);
 	size_t d_len = r_len + name_len + 2;
 
+	if (ap->flags & MOUNT_FLAG_REMOUNT)
+		return 0;
+
 	if (d_len > PATH_MAX)
 		return 1;
 
--- autofs-5.0.1.orig/modules/mount_autofs.c
+++ autofs-5.0.1/modules/mount_autofs.c
@@ -50,7 +50,7 @@ int mount_mount(struct autofs_point *ap,
 	pthread_t thid;
 	char *realpath, *mountpoint;
 	const char **argv;
-	int argc, status, ghost = ap->ghost;
+	int argc, status, ghost = ap->flags & MOUNT_FLAG_GHOST;
 	time_t timeout = ap->exp_timeout;
 	unsigned logopt = ap->logopt;
 	char *type, *format, *tmp, *tmp2;
@@ -76,8 +76,13 @@ int mount_mount(struct autofs_point *ap,
 	} else if (*name == '/') {
 		realpath = alloca(name_len + 1);
 		mountpoint = alloca(len + 1);
-		strcpy(mountpoint, root);
-		strcpy(realpath, name);
+		if (ap->flags & MOUNT_FLAG_REMOUNT) {
+			strcpy(mountpoint, name);
+			strcpy(realpath, name);
+		} else {
+			strcpy(mountpoint, root);
+			strcpy(realpath, name);
+		}
 	} else {
 		realpath = alloca(len + name_len + 2);
 		mountpoint = alloca(len + name_len + 2);
--- autofs-5.0.1.orig/modules/mount_bind.c
+++ autofs-5.0.1/modules/mount_bind.c
@@ -76,6 +76,9 @@ int mount_mount(struct autofs_point *ap,
 	int err;
 	int i, len;
 
+	if (ap->flags & MOUNT_FLAG_REMOUNT)
+		return 0;
+
 	/* Root offset of multi-mount */
 	len = strlen(root);
 	if (root[len - 1] == '/') {
@@ -127,7 +130,8 @@ int mount_mount(struct autofs_point *ap,
 			if (ap->type != LKP_INDIRECT)
 				return 1;
 
-			if ((!ap->ghost && name_len) && !existed)
+			if (!existed &&
+			   (!(ap->flags & MOUNT_FLAG_GHOST) && name_len))
 				rmdir_path(ap, fullpath, ap->dev);
 
 			return err;
@@ -170,7 +174,7 @@ int mount_mount(struct autofs_point *ap,
 			      MODPREFIX
 			      "failed to create local mount %s -> %s",
 			      fullpath, what);
-			if (ap->ghost && !status)
+			if (ap->flags & MOUNT_FLAG_GHOST && !status)
 				mkdir_path(fullpath, 0555);
 			else {
 				if (ap->type == LKP_INDIRECT)
--- autofs-5.0.1.orig/modules/mount_changer.c
+++ autofs-5.0.1/modules/mount_changer.c
@@ -51,6 +51,9 @@ int mount_mount(struct autofs_point *ap,
 	int err;
 	int len, status, existed = 1;
 
+	if (ap->flags & MOUNT_FLAG_REMOUNT)
+		return 0;
+
 	fstype = "iso9660";
 
 	/* Root offset of multi-mount */
@@ -122,7 +125,7 @@ int mount_mount(struct autofs_point *ap,
 		if (ap->type != LKP_INDIRECT)
 			return 1;
 
-		if ((!ap->ghost && name_len) || !existed)
+		if ((!(ap->flags & MOUNT_FLAG_GHOST) && name_len) || !existed)
 			rmdir_path(ap, fullpath, ap->dev);
 
 		return 1;
--- autofs-5.0.1.orig/modules/mount_ext2.c
+++ autofs-5.0.1/modules/mount_ext2.c
@@ -45,6 +45,9 @@ int mount_mount(struct autofs_point *ap,
 	const char *fsck_prog;
 	int len, status, existed = 1;
 
+	if (ap->flags & MOUNT_FLAG_REMOUNT)
+		return 0;
+
 	/* Root offset of multi-mount */
 	len = strlen(root);
 	if (root[len - 1] == '/') {
@@ -132,7 +135,7 @@ int mount_mount(struct autofs_point *ap,
 		if (ap->type != LKP_INDIRECT)
 			return 1;
 
-		if ((!ap->ghost && name_len) || !existed)
+		if ((!(ap->flags & MOUNT_FLAG_GHOST) && name_len) || !existed)
 			rmdir_path(ap, fullpath, ap->dev);
 
 		return 1;
--- autofs-5.0.1.orig/modules/mount_generic.c
+++ autofs-5.0.1/modules/mount_generic.c
@@ -44,6 +44,9 @@ int mount_mount(struct autofs_point *ap,
 	int err;
 	int len, status, existed = 1;
 
+	if (ap->flags & MOUNT_FLAG_REMOUNT)
+		return 0;
+
 	/* Root offset of multi-mount */
 	len = strlen(root);
 	if (root[len - 1] == '/') {
@@ -92,7 +95,7 @@ int mount_mount(struct autofs_point *ap,
 		if (ap->type != LKP_INDIRECT)
 			return 1;
 
-		if ((!ap->ghost && name_len) || !existed)
+		if ((!(ap->flags & MOUNT_FLAG_GHOST) && name_len) || !existed)
 			rmdir_path(ap, fullpath, ap->dev);
 
 		return 1;
--- autofs-5.0.1.orig/modules/mount_nfs.c
+++ autofs-5.0.1/modules/mount_nfs.c
@@ -64,10 +64,14 @@ int mount_mount(struct autofs_point *ap,
 	struct host *this, *hosts = NULL;
 	unsigned int vers;
 	char *nfsoptions = NULL;
+	unsigned int random_selection = ap->flags & MOUNT_FLAG_RANDOM_SELECT;
 	int len, status, err, existed = 1;
 	int nosymlink = 0;
 	int ro = 0;            /* Set if mount bind should be read-only */
 
+	if (ap->flags & MOUNT_FLAG_REMOUNT)
+		return 0;
+
 	debug(ap->logopt,
 	      MODPREFIX "root=%s name=%s what=%s, fstype=%s, options=%s",
 	      root, name, what, fstype, options);
@@ -136,7 +140,7 @@ int mount_mount(struct autofs_point *ap,
 		info(ap->logopt, MODPREFIX "no hosts available");
 		return 1;
 	}
-	prune_host_list(ap->logopt, &hosts, vers, nfsoptions, ap->random_selection);
+	prune_host_list(ap->logopt, &hosts, vers, nfsoptions, random_selection);
 
 	if (!hosts) {
 		info(ap->logopt, MODPREFIX "no hosts available");
@@ -260,7 +264,7 @@ forced_fail:
 	if (ap->type != LKP_INDIRECT)
 		return 1;
 
-	if ((!ap->ghost && name_len) || !existed)
+	if ((!(ap->flags & MOUNT_FLAG_GHOST) && name_len) || !existed)
 		rmdir_path(ap, fullpath, ap->dev);
 
 	return 1;
--- autofs-5.0.1.orig/modules/parse_sun.c
+++ autofs-5.0.1/modules/parse_sun.c
@@ -1108,9 +1108,9 @@ static int mount_subtree(struct autofs_p
 	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;
+	char *mnt_tmp_root, *mm_root, *mm_base, *mm_key;
+	const char *mnt_root, *target;
+	unsigned int mm_root_len, mnt_root_len;
 	int start, ret = 0, rv;
 	unsigned int move;
 
@@ -1143,11 +1143,19 @@ static int mount_subtree(struct autofs_p
 		strcat(mm_root, "/");
 		strcat(mm_root, mm_key);
 	}
+	mm_root_len = strlen(mm_root);
 
-	mm_tmp_root = mkdtemp(t_dir);
-	if (!mm_tmp_root)
-		return 1;
-	mm_tmp_root_len = strlen(mm_tmp_root);
+	mnt_tmp_root = NULL;
+	if (ap->flags & MOUNT_FLAG_REMOUNT) {
+		mnt_root = mm_root;
+		mnt_root_len = mm_root_len;
+	} else {
+		mnt_root = mkdtemp(t_dir);
+		if (!mnt_root)
+			return 1;
+		mnt_root_len = strlen(mnt_root);
+		mnt_tmp_root = (char *) mnt_root;
+	}
 
 	if (me == me->multi) {
 		/* name = NULL */
@@ -1169,20 +1177,20 @@ static int mount_subtree(struct autofs_p
 				warn(ap->logopt,
 				      MODPREFIX "failed to parse root offset");
 				cache_delete_offset_list(me->mc, name);
-				rmdir(mm_tmp_root);
-				return 1;
+				goto error_out;
 			}
 			ro_len = strlen(ro_loc);
 
-			move = MOUNT_MOVE_OTHER;
-			if (check_fstype_autofs_option(myoptions))
-				move = MOUNT_MOVE_AUTOFS;
+			if (!(ap->flags & MOUNT_FLAG_REMOUNT)) {
+				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';
+			tmp = alloca(mnt_root_len + 1);
+			strcpy(tmp, mnt_root);
+			tmp[mnt_root_len] = '/';
+			tmp[mnt_root_len + 1] = '\0';
 			root = tmp;
 
 			rv = sun_mount(ap, root, name, namelen, ro_loc, ro_len, myoptions, ctxt);
@@ -1192,14 +1200,13 @@ static int mount_subtree(struct autofs_p
 		}
 
 		if (ro && rv == 0) {
-			ret = mount_multi_triggers(ap, me, mm_tmp_root, start, mm_base);
+			ret = mount_multi_triggers(ap, me, mnt_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;
+				cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
+				cleanup_multi_root(ap, mnt_root, mm_root, move);
+				goto error_out;
 			}
 		} else if (rv <= 0) {
 			move = MOUNT_MOVE_NONE;
@@ -1207,34 +1214,34 @@ static int mount_subtree(struct autofs_p
 			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;
+				cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
+				goto error_out;
 			}
 		}
 	} else {
 		int loclen = strlen(loc);
 		int namelen = strlen(name);
 
-		move = MOUNT_MOVE_OTHER;
-		if (check_fstype_autofs_option(options))
-			move = MOUNT_MOVE_AUTOFS;
+		if (!(ap->flags & MOUNT_FLAG_REMOUNT)) {
+			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);
+		rv = sun_mount(ap, mnt_root, name, namelen, loc, loclen, options, ctxt);
 		if (rv == 0) {
-			ret = mount_multi_triggers(ap, me->multi, mm_tmp_root, start, mm_base);
+			ret = mount_multi_triggers(ap, me->multi, mnt_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;
+				cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
+				cleanup_multi_root(ap, mnt_root, mm_root, move);
+				goto error_out;
 			}
 		} else if (rv < 0) {
 			char *mm_root_base = alloca(strlen(mm_root) + strlen(mm_base) + 1);
@@ -1248,21 +1255,20 @@ static int mount_subtree(struct autofs_p
 			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;
+				cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
+				goto error_out;
 			}
 		}
 	}
 
-	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;
+	if (!move_mount(ap, mnt_root, target, move)) {
+		cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
+		cleanup_multi_root(ap, mnt_root, mm_root, move);
+		goto error_out;
 	}
 
-	rmdir(mm_tmp_root);
+	if (mnt_tmp_root)
+		rmdir(mnt_tmp_root);
 
 	/* Mount for base of tree failed */
 	if (rv > 0)
@@ -1277,6 +1283,12 @@ done:
 		rv = 0;
 
 	return rv;
+
+error_out:
+	if (mnt_tmp_root)
+		rmdir(mnt_tmp_root);
+
+	return 1;
 }
 
 /*
@@ -1472,7 +1484,7 @@ int parse_mount(struct autofs_point *ap,
 			 * us to fail on the check for duplicate offsets in
 			 * we don't know when submounts go away.
 			 */
-			cache_multi_lock(me);
+			cache_multi_writelock(me);
 			cache_delete_offset_list(mc, name);
 			cache_multi_unlock(me);
 		}
@@ -1495,7 +1507,7 @@ int parse_mount(struct autofs_point *ap,
 		}
 
 		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
-		cache_multi_lock(me);
+		cache_multi_writelock(me);
 		/* It's a multi-mount; deal with it */
 		do {
 			char *path, *myoptions, *loc;
@@ -1690,7 +1702,7 @@ mount_it:
 		      options, loclen, loc);
 
 		cache_readlock(mc);
-		cache_multi_lock(me);
+		cache_multi_writelock(me);
 
 		rv = mount_subtree(ap, me, name, loc, options, ctxt);