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

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