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

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