Blame SOURCES/autofs-5.1.3-only-take-master-map-mutex-for-master-map-update.patch

603f99
autofs-5.1.3 - only take master map mutex for master map update
603f99
603f99
From: Ian Kent <raven@themaw.net>
603f99
603f99
When a map read is done it's neccessary to re-initialize the lookup
603f99
context which requires a write lock to be taken on the master map
603f99
entry source. Currently a map re-read also takes the master map lock
603f99
which will block new lookups.
603f99
603f99
If the lookup module thinks the map has been modified it will queue
603f99
a map read which will take these locks.
603f99
603f99
Now, when a bind mount (or symlink) is triggered by a lookup it's
603f99
necessary to trigger automounts that are included in the target path
603f99
for the dependent path to be valid.
603f99
603f99
When the target path triggers automounts in this way and refers to the
603f99
same master map entry, and a map re-read is scheduled and started and
603f99
manages to take the master map lock before the dependent lookup gets
603f99
past the master map lock check, the dependent path lookup will deadlock.
603f99
603f99
But the master map lock is meant to gaurd against master map entries
603f99
going away during lookups so isn't really needed for map reads as long
603f99
as the master map lock is held during the update of the mounted
603f99
automounts.
603f99
603f99
Signed-off-by: Ian Kent <raven@themaw.net>
603f99
---
603f99
 CHANGELOG      |    1 +
603f99
 daemon/state.c |    3 ---
603f99
 lib/master.c   |   45 +++++++++++++++++++++++++++++++++++++--------
603f99
 3 files changed, 38 insertions(+), 11 deletions(-)
603f99
603f99
--- autofs-5.0.7.orig/daemon/state.c
603f99
+++ autofs-5.0.7/daemon/state.c
603f99
@@ -484,12 +484,9 @@ static void *do_readmap(void *arg)
603f99
 
603f99
 	info(ap->logopt, "re-reading map for %s", ap->path);
603f99
 
603f99
-	pthread_cleanup_push(master_mutex_lock_cleanup, NULL);
603f99
-	master_mutex_lock();
603f99
 	status = lookup_nss_read_map(ap, NULL, now);
603f99
 	if (!status)
603f99
 		pthread_exit(NULL);
603f99
-	pthread_cleanup_pop(1);
603f99
 
603f99
 	if (ap->type == LKP_INDIRECT) {
603f99
 		struct ioctl_ops *ops = get_ioctl_ops();
603f99
--- autofs-5.0.7.orig/lib/master.c
603f99
+++ autofs-5.0.7/lib/master.c
603f99
@@ -1089,6 +1089,39 @@ next:
603f99
 	free(paths);
603f99
 }
603f99
 
603f99
+static void wait_for_lookups_and_lock(struct master *master)
603f99
+{
603f99
+	struct list_head *p, *head;
603f99
+	int status;
603f99
+
603f99
+again:
603f99
+	master_mutex_lock();
603f99
+
603f99
+	head = &master->mounts;
603f99
+	p = head->next;
603f99
+	while (p != head) {
603f99
+		struct master_mapent *this;
603f99
+
603f99
+		this = list_entry(p, struct master_mapent, list);
603f99
+
603f99
+		status = pthread_rwlock_trywrlock(&this->source_lock);
603f99
+		if (status) {
603f99
+			struct timespec t = { 0, 200000000 };
603f99
+			struct timespec r;
603f99
+
603f99
+			master_mutex_unlock();
603f99
+
603f99
+			while (nanosleep(&t, &r) == -1 && errno == EINTR)
603f99
+				memcpy(&t, &r, sizeof(struct timespec));
603f99
+
603f99
+			goto again;
603f99
+		}
603f99
+		master_source_unlock(this);
603f99
+
603f99
+		p = p->next;
603f99
+	}
603f99
+}
603f99
+
603f99
 int master_read_master(struct master *master, time_t age, int readall)
603f99
 {
603f99
 	unsigned int logopt = master->logopt;
603f99
@@ -1098,7 +1131,7 @@ int master_read_master(struct master *ma
603f99
 	 * We need to clear and re-populate the null map entry cache
603f99
 	 * before alowing anyone else to use it.
603f99
 	 */
603f99
-	master_mutex_lock();
603f99
+	wait_for_lookups_and_lock(master);
603f99
 	if (master->nc) {
603f99
 		cache_writelock(master->nc);
603f99
 		nc = master->nc;
603f99
@@ -1118,21 +1151,19 @@ int master_read_master(struct master *ma
603f99
 	lookup_nss_read_master(master, age);
603f99
 	cache_unlock(nc);
603f99
 	master_add_amd_mount_section_mounts(master, age);
603f99
-	master_mutex_unlock();
603f99
 
603f99
 	if (!master->read_fail)
603f99
 		master_mount_mounts(master, age, readall);
603f99
 	else {
603f99
 		master->read_fail = 0;
603f99
 		/* HUP signal sets readall == 1 only */
603f99
-		if (!readall)
603f99
+		if (!readall) {
603f99
+			master_mutex_unlock();
603f99
 			return 0;
603f99
-		else
603f99
+		} else
603f99
 			master_mount_mounts(master, age, readall);
603f99
 	}
603f99
 
603f99
-	master_mutex_lock();
603f99
-
603f99
 	if (list_empty(&master->mounts))
603f99
 		warn(logopt, "no mounts in table");
603f99
 
603f99
@@ -1422,7 +1453,6 @@ int master_mount_mounts(struct master *m
603f99
 	int cur_state;
603f99
 
603f99
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
603f99
-	master_mutex_lock();
603f99
 
603f99
 	head = &master->mounts;
603f99
 	p = head->next;
603f99
@@ -1510,7 +1540,6 @@ cont:
603f99
 		}
603f99
 	}
603f99
 
603f99
-	master_mutex_unlock();
603f99
 	pthread_setcancelstate(cur_state, NULL);
603f99
 
603f99
 	return 1;
603f99
--- autofs-5.0.7.orig/CHANGELOG
603f99
+++ autofs-5.0.7/CHANGELOG
603f99
@@ -257,6 +257,7 @@
603f99
 - fix some man page problems.
603f99
 - allow dot in OPTIONSTR value lexer pattern.
603f99
 - revert fix argc off by one in mount_autofs.c.
603f99
+- only take master map mutex for master map update.
603f99
 
603f99
 25/07/2012 autofs-5.0.7
603f99
 =======================