diff --git a/CHANGELOG b/CHANGELOG
index 3e801e2..866ae0a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -19,6 +19,8 @@
   patches.
 - tidy up directory cleanup and add validation check to rmdir_path.
 - remove SIGCHLD handler.
+- alter expire locking of multi-mounts to lock sub-tree instead of
+  entire tree.
 
 13/7/2006 autofs-5.0.1 rc1
 --------------------------
diff --git a/autofs.spec b/autofs.spec
index 7532b80..cc1ee93 100644
--- a/autofs.spec
+++ b/autofs.spec
@@ -59,7 +59,7 @@ inkludera nätfilsystem, CD-ROM, floppydi
 echo %{version}-%{release} > .version
 
 %build
-CFLAGS="$RPM_OPT_FLAGS -Wall" ./configure --libdir=%{_libdir} --enable-ignore-busy
+CFLAGS="$RPM_OPT_FLAGS -Wall" ./configure --libdir=%{_libdir} --disable-mount-locking --enable-ignore-busy
 CFLAGS="$RPM_OPT_FLAGS -Wall" make initdir=/etc/rc.d/init.d DONTSTRIP=1
 
 %install
diff --git a/daemon/automount.c b/daemon/automount.c
index 5217347..5fba783 100644
--- a/daemon/automount.c
+++ b/daemon/automount.c
@@ -370,6 +370,7 @@ static void update_map_cache(struct auto
    it also tries to umount path itself */
 int umount_multi(struct autofs_point *ap, const char *path, int incl)
 {
+	struct mapent_cache *mc;
 	struct mapent *me;
 	struct statfs fs;
 	int is_autofs_fs;
@@ -400,16 +401,20 @@ int umount_multi(struct autofs_point *ap
 		}
 	}
 
+	cache_multi_lock(me->parent);
+
+	mc = me->source->mc;
+
 	left = 0;
 
-	if (me && me->multi) {
+	if (me->multi) {
 		struct autofs_point *oap = ap;
 		char *root, *base;
 
 		if (ap->submount)
 			oap = ap->parent;
 
-		 if (me == me->multi && !strchr(me->key, '/')) {
+		if (me == me->multi && !strchr(me->key, '/')) {
 			/* Indirect multi-mount root */
 			root = alloca(strlen(ap->path) + strlen(me->key) + 2);
 			strcpy(root, ap->path);
@@ -427,10 +432,12 @@ int umount_multi(struct autofs_point *ap
 			left++;
 		}
 	}
-	cache_unlock(me->source->mc);
 
-	if (left || is_autofs_fs)
+	if (left || is_autofs_fs) {
+		cache_multi_unlock(me->parent);
+		cache_unlock(mc);
 		return left;
+	}
 
 	/*
 	 * If this is the root of a multi-mount we've had to umount
@@ -451,6 +458,9 @@ int umount_multi(struct autofs_point *ap
 		check_rm_dirs(ap, path, incl);
 	}
 
+	cache_multi_unlock(me->parent);
+	cache_unlock(mc);
+
 	return left;
 }
 
diff --git a/daemon/direct.c b/daemon/direct.c
index e6c1f35..5a528fc 100644
--- a/daemon/direct.c
+++ b/daemon/direct.c
@@ -725,29 +725,10 @@ out_err:
 
 static int expire_direct(int ioctlfd, const char *path, unsigned int when, unsigned int logopt)
 {
-	char *estr, buf[MAX_ERR_BUF];
 	int ret, retries = EXPIRE_RETRIES;
 
 	while (retries--) {
 		struct timespec tm = {0, 100000000};
-		int busy = 0;
-
-		ret = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &busy);
-		if (ret == -1) {
-			/* Mount has gone away */
-			if (errno == EBADF || errno == EINVAL)
-				return 1;
-
-			estr = strerror_r(errno, buf, MAX_ERR_BUF);
-			error(logopt, "ioctl failed: %s", estr);
-			return 0;
-		}
-
-		/* No need to go further */
-		if (busy)
-			return 0;
-
-		sched_yield();
 
 		/* Ggenerate expire message for the mount. */
 		ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when);
@@ -756,7 +737,7 @@ static int expire_direct(int ioctlfd, co
 			if (errno == EBADF || errno == EINVAL)
 				return 1;
 
-			/* Need to wait for the kernel ? */
+			/* Other than need to wait for the kernel ? */
 			if (errno != EAGAIN)
 				return 0;
 		}
diff --git a/daemon/indirect.c b/daemon/indirect.c
index 970215c..766ec08 100644
--- a/daemon/indirect.c
+++ b/daemon/indirect.c
@@ -366,29 +366,10 @@ force_umount:
 
 static int expire_indirect(int ioctlfd, const char *path, unsigned int when, unsigned int count, unsigned int logopt)
 {
-	char *estr, buf[MAX_ERR_BUF];
 	int ret, retries = count;
 
 	while (retries--) {
 		struct timespec tm = {0, 100000000};
-		int busy = 0;
-
-		ret = ioctl(ioctlfd, AUTOFS_IOC_ASKUMOUNT, &busy);
-		if (ret == -1) {
-			/* Mount has gone away */
-			if (errno == EBADF || errno == EINVAL)
-				return 1;
-
-			estr = strerror_r(errno, buf, MAX_ERR_BUF);
-			error(logopt, "ioctl failed: %s", estr);
-			return 0;
-		}
-
-		/* No need to go further */
-		if (busy)
-			return 0;
-
-		sched_yield();
 
 		/* Ggenerate expire message for the mount. */
 		ret = ioctl(ioctlfd, AUTOFS_IOC_EXPIRE_DIRECT, &when);
@@ -397,7 +378,7 @@ static int expire_indirect(int ioctlfd, 
 			if (errno == EBADF || errno == EINVAL)
 				return 1;
 
-			/* Need to wait for the kernel ? */
+			/* Other than need to wait for the kernel ? */
 			if (errno != EAGAIN)
 				return 0;
 		}
@@ -480,11 +461,10 @@ void *expire_proc_indirect(void *arg)
 
 		if (*me->key == '/') {
 			ioctlfd = me->ioctlfd;
-			cache_unlock(me->source->mc);
 		} else {
 			ioctlfd = ap->ioctlfd;
-			cache_unlock(me->source->mc);
 		}
+		cache_unlock(me->source->mc);
 
 		debug(ap->logopt, "expire %s", next->path);
 
@@ -502,7 +482,7 @@ void *expire_proc_indirect(void *arg)
 	 * have some offset mounts with no '/' offset so we need to
 	 * umount them here.
 	 */
-	limit = count_mounts(ap, ap->path);
+	limit = count_mounts(ap, ap->path) * 2;
 	ret = expire_indirect(ap->ioctlfd, ap->path, now, limit, ap->logopt);
 	if (!ret) {
 		debug(ap->logopt,
@@ -525,28 +505,22 @@ void *expire_proc_indirect(void *arg)
 	}
 	free_mnt_list(mnts);
 
-	if (submnts) {
+	if (submnts)
 		debug(ap->logopt,
 		      "%d submounts remaining in %s", submnts, ap->path);
-		ea->status = 1;
-		pthread_exit(NULL);
-	}
 
 	/* 
 	 * EXPIRE_MULTI is synchronous, so we can be sure (famous last
 	 * words) the umounts are done by the time we reach here
 	 */
-	if (count) {
+	if (count)
 		debug(ap->logopt, "%d remaining in %s", count, ap->path);
-		ea->status = 1;
-		pthread_exit(NULL);
-	}
 
 	/* If we are trying to shutdown make sure we can umount */
 	if (!ioctl(ap->ioctlfd, AUTOFS_IOC_ASKUMOUNT, &ret)) {
 		if (!ret) {
 			warn(ap->logopt, "mount still busy %s", ap->path);
-			ea->status = 1;
+			ea->status++;
 		}
 	}
 
diff --git a/include/automount.h b/include/automount.h
index 54a7180..90a9c7a 100644
--- a/include/automount.h
+++ b/include/automount.h
@@ -123,12 +123,11 @@ #define CHE_DUPLICATE	0x0020
 
 #define HASHSIZE		77
 #define NEGATIVE_TIMEOUT	10
-#define UMOUNT_RETRIES		25
-#define EXPIRE_RETRIES		15
+#define UMOUNT_RETRIES		50
+#define EXPIRE_RETRIES		25
 
 struct mapent_cache {
 	pthread_rwlock_t rwlock;
-	pthread_mutex_t multi_mutex;
 	unsigned int size;
 	struct list_head *ino_index;
 	struct mapent **hash;
@@ -137,11 +136,14 @@ struct mapent_cache {
 struct mapent {
 	struct mapent *next;
 	struct list_head ino_index;
+	pthread_mutex_t multi_mutex;
 	struct list_head multi_list;
 	/* Map source of the cache entry */
 	struct map_source *source;
-	/* Need to know owner if we're a multi mount */
+	/* Need to know owner if we're a multi-mount */
 	struct mapent *multi;
+	/* Parent nesting point within multi-mount */
+	struct mapent *parent;
 	char *key;
 	char *mapent;
 	time_t age;
@@ -173,11 +175,12 @@ struct mapent *cache_partial_match(struc
 int cache_add(struct mapent_cache *mc, struct map_source *source,
 			const char *key, const char *mapent, time_t age);
 int cache_add_offset(struct mapent_cache *mc, const char *mkey, const char *key, const char *mapent, time_t age);
+int cache_set_parents(struct mapent *mm);
 int cache_update(struct mapent_cache *mc, struct map_source *source,
 			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_cache *mc);
-void cache_multi_unlock(struct mapent_cache *mc);
+void cache_multi_lock(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);
 struct mapent *cache_enumerate(struct mapent_cache *mc, struct mapent *me);
diff --git a/lib/cache.c b/lib/cache.c
index a047320..432270b 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -98,11 +98,14 @@ void cache_lock_cleanup(void *arg)
 	cache_unlock(mc);
 }
 
-void cache_multi_lock(struct mapent_cache *mc)
+void cache_multi_lock(struct mapent *me)
 {
 	int status;
 
-	status = pthread_mutex_lock(&mc->multi_mutex);
+	if (!me)
+		return;
+
+	status = pthread_mutex_lock(&me->multi_mutex);
 	if (status) {
 		error(LOGOPT_ANY, "mapent cache multi mutex lock failed");
 		fatal(status);
@@ -110,17 +113,21 @@ void cache_multi_lock(struct mapent_cach
 	return;
 }
 
-void cache_multi_unlock(struct mapent_cache *mc)
+void cache_multi_unlock(struct mapent *me)
 {
 	int status;
 
-	status = pthread_mutex_unlock(&mc->multi_mutex);
+	if (!me)
+		return;
+
+	status = pthread_mutex_unlock(&me->multi_mutex);
 	if (status) {
 		error(LOGOPT_ANY, "mapent cache multi mutex unlock failed");
 		fatal(status);
 	}
 	return;
 }
+
 struct mapent_cache *cache_init(struct map_source *map)
 {
 	struct mapent_cache *mc;
@@ -153,10 +160,6 @@ struct mapent_cache *cache_init(struct m
 	if (status)
 		fatal(status);
 
-	status = pthread_mutex_init(&mc->multi_mutex, NULL);
-	if (status)
-		fatal(status);
-
 	cache_writelock(mc);
 
 	for (i = 0; i < mc->size; i++) {
@@ -411,6 +414,7 @@ int cache_add(struct mapent_cache *mc, s
 	struct mapent *me, *existing = NULL;
 	char *pkey, *pent;
 	unsigned int hashval = hash(key);
+	int status;
 
 	me = (struct mapent *) malloc(sizeof(struct mapent));
 	if (!me)
@@ -440,10 +444,15 @@ int cache_add(struct mapent_cache *mc, s
 	INIT_LIST_HEAD(&me->ino_index);
 	INIT_LIST_HEAD(&me->multi_list);
 	me->multi = NULL;
+	me->parent = NULL;
 	me->ioctlfd = -1;
 	me->dev = (dev_t) -1;
 	me->ino = (ino_t) -1;
 
+	status = pthread_mutex_init(&me->multi_mutex, NULL);
+	if (status)
+		fatal(status);
+
 	/* 
 	 * We need to add to the end if values exist in order to
 	 * preserve the order in which the map was read on lookup.
@@ -526,6 +535,56 @@ done:
 	return ret; 
 }
 
+static struct mapent *get_parent(const char *key, struct list_head *head, struct list_head **pos)
+{
+	struct list_head *next;
+	struct mapent *this, *last;
+	int eq;
+
+	last = NULL;
+	next = *pos ? (*pos)->next : head->next;
+
+	list_for_each(next, head) {
+		this = list_entry(next, struct mapent, multi_list);
+
+		if (!strcmp(this->key, key))
+			break;
+
+		eq = strncmp(this->key, key, strlen(this->key));
+		if (eq == 0) {
+			*pos = next;
+			last = this;
+			continue;
+		}
+	}
+
+	return last;
+}
+
+int cache_set_parents(struct mapent *mm)
+{
+	struct list_head *multi_head, *p, *pos;
+	struct mapent *this;
+
+	if (!mm->multi)
+		return 0;
+
+	pos = NULL;
+	multi_head = &mm->multi->multi_list;
+
+	list_for_each(p, multi_head) {
+		struct mapent *parent;
+		this = list_entry(p, struct mapent, multi_list);
+		parent = get_parent(this->key, multi_head, &pos);
+		if (parent)
+			this->parent = parent;
+		else
+			this->parent = mm->multi;
+	}
+
+	return 1;
+}
+
 /* cache must be write locked by caller */
 int cache_update(struct mapent_cache *mc, struct map_source *source,
 		 const char *key, const char *mapent, time_t age)
@@ -568,7 +627,7 @@ int cache_delete(struct mapent_cache *mc
 {
 	struct mapent *me = NULL, *pred;
 	unsigned int hashval = hash(key);
-	int ret = CHE_OK;
+	int status, ret = CHE_OK;
 
 	me = mc->hash[hashval];
 	if (!me) {
@@ -585,6 +644,9 @@ int cache_delete(struct mapent_cache *mc
 				goto done;
 			}
 			pred->next = me->next;
+			status = pthread_mutex_destroy(&me->multi_mutex);
+			if (status)
+				fatal(status);
 			if (!list_empty(&me->ino_index))
 				list_del(&me->ino_index);
 			free(me->key);
@@ -605,6 +667,9 @@ int cache_delete(struct mapent_cache *mc
 			goto done;
 		}
 		mc->hash[hashval] = me->next;
+		status = pthread_mutex_destroy(&me->multi_mutex);
+		if (status)
+			fatal(status);
 		if (!list_empty(&me->ino_index))
 			list_del(&me->ino_index);
 		free(me->key);
@@ -713,10 +778,6 @@ void cache_release(struct map_source *ma
 	if (status)
 		fatal(status);
 
-	status = pthread_mutex_destroy(&mc->multi_mutex);
-	if (status)
-		fatal(status);
-
 	free(mc->hash);
 	free(mc->ino_index);
 	free(mc);
diff --git a/lib/parse_subs.c b/lib/parse_subs.c
index 6fb9895..a24e6da 100644
--- a/lib/parse_subs.c
+++ b/lib/parse_subs.c
@@ -472,9 +472,7 @@ cont:
 		}
 
 		/* We're done - clean out the offsets */
-		cache_multi_lock(mc);
 		status = cache_delete_offset_list(mc, me->key);
-		cache_multi_unlock(mc);
 		if (status != CHE_OK)
 			warn(ap->logopt, "couldn't delete offset list");
 	}
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index 25d2eda..7dc8339 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -645,12 +645,7 @@ add_offset_entry(struct autofs_point *ap
 	} else
 		strcpy(m_mapent, loc);
 
-	cache_readlock(mc);
-	cache_multi_lock(mc);
 	ret = cache_add_offset(mc, name, m_key, m_mapent, age);
-	cache_multi_unlock(mc);
-	cache_unlock(mc);
-
 	if (ret == CHE_OK)
 		debug(ap->logopt, MODPREFIX
 		      "added multi-mount offset %s -> %s", path, m_mapent);
@@ -956,22 +951,25 @@ int parse_mount(struct autofs_point *ap,
 				return 1;
 			}
 		}
+		cache_unlock(mc);
 
+		cache_readlock(mc);
 		me = cache_lookup_distinct(mc, name);
 		if (me) {
 			/* So we know we're the multi-mount root */
 			if (!me->multi)
 				me->multi = me;
 		}
-		cache_unlock(mc);
 
 		if (!me) {
 			error(ap->logopt,
 			      MODPREFIX "can't find multi root %s", name);
 			free(options);
+			cache_unlock(mc);
 			return 1;
 		}
 
+		cache_multi_lock(me);
 		/* It's a multi-mount; deal with it */
 		do {
 			char *path, *myoptions, *loc;
@@ -991,10 +989,8 @@ int parse_mount(struct autofs_point *ap,
 
 			if (!path) {
 				warn(ap->logopt, MODPREFIX "null path or out of memory");
-				cache_readlock(mc);
-				cache_multi_lock(mc);
 				cache_delete_offset_list(mc, name);
-				cache_multi_unlock(mc);
+				cache_multi_unlock(me);
 				cache_unlock(mc);
 				free(options);
 				return 1;
@@ -1005,10 +1001,8 @@ int parse_mount(struct autofs_point *ap,
 
 			l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
 			if (!l) {
-				cache_readlock(mc);
-				cache_multi_lock(mc);
 				cache_delete_offset_list(mc, name);
-				cache_multi_unlock(mc);
+				cache_multi_unlock(me);
 				cache_unlock(mc);
 				free(path);
 				free(options);
@@ -1027,10 +1021,8 @@ int parse_mount(struct autofs_point *ap,
 
 			if (status != CHE_OK) {
 				warn(ap->logopt, MODPREFIX "error adding multi-mount");
-				cache_readlock(mc);
-				cache_multi_lock(mc);
 				cache_delete_offset_list(mc, name);
-				cache_multi_unlock(mc);
+				cache_multi_unlock(me);
 				cache_unlock(mc);
 				free(path);
 				free(options);
@@ -1044,19 +1036,11 @@ int parse_mount(struct autofs_point *ap,
 			free(myoptions);
 		} while (*p == '/');
 
-		cache_readlock(mc);
-		me = cache_lookup_distinct(mc, name);
-		if (!me) {
-			error(ap->logopt,
-			      MODPREFIX
-			      "failed to find cache entry for %s", name);
-			cache_multi_lock(mc);
-			cache_delete_offset_list(mc, name);
-			cache_multi_unlock(mc);
-			cache_unlock(mc);
-			free(options);
-			return 1;
-		}
+		/*
+		 * We've got the ordered list of multi-mount entries so go
+		 * through and set the parent entry of each
+		 */
+		cache_set_parents(me);
 
 		/* Mount root offset if it exists */
 		ro = cache_lookup_offset("/", "/", strlen(m_root), &me->multi_list);
@@ -1068,9 +1052,8 @@ int parse_mount(struct autofs_point *ap,
 			if (!rv) {
 				warn(ap->logopt,
 				      MODPREFIX "failed to mount root offset");
-				cache_multi_lock(mc);
 				cache_delete_offset_list(mc, name);
-				cache_multi_unlock(mc);
+				cache_multi_unlock(me);
 				cache_unlock(mc);
 				free(options);
 				return 1;
@@ -1086,9 +1069,8 @@ int parse_mount(struct autofs_point *ap,
 				warn(ap->logopt,
 				      MODPREFIX
 				      "mount multi-mount root %s failed", name);
-				cache_multi_lock(mc);
 				cache_delete_offset_list(mc, name);
-				cache_multi_unlock(mc);
+				cache_multi_unlock(me);
 				cache_unlock(mc);
 				free(options);
 				return rv;
@@ -1098,9 +1080,12 @@ int parse_mount(struct autofs_point *ap,
 		if (!mount_multi_triggers(ap, m_root, me, "/")) {
 			warn(ap->logopt,
 			      MODPREFIX "failed to mount offset triggers");
+			cache_multi_unlock(me);
+			cache_unlock(mc);
 			free(options);
 			return 1;
 		}
+		cache_multi_unlock(me);
 		cache_unlock(mc);
 
 		free(options);
@@ -1217,11 +1202,13 @@ int parse_mount(struct autofs_point *ap,
 
 		me = lookup_source_mapent(oap, name, LKP_DISTINCT);
 		if (me) {
+			struct mapent *mm;
 			char *m_key;
 			int start;
 			char *base, *m_root;
 
 			mc = me->source->mc;
+			mm = me->multi;
 
 			if (!me->multi) {
 				cache_unlock(mc);
@@ -1253,13 +1240,13 @@ int parse_mount(struct autofs_point *ap,
 
 			base = &me->key[start];
 
-			cache_multi_lock(mc);
+			cache_multi_lock(mm);
 			if (!mount_multi_triggers(oap, m_root, me->multi, base)) {
 				error(ap->logopt,
 				      MODPREFIX "failed to mount offset triggers");
 				rv = 1;
 			}
-			cache_multi_unlock(mc);
+			cache_multi_unlock(mm);
 			cache_unlock(mc);
 		}
 	}
