Ian Kent cc4062
autofs-5.0.5 - fix null cache race
Ian Kent cc4062
Ian Kent cc4062
From: Ian Kent <raven@themaw.net>
Ian Kent cc4062
Ian Kent cc4062
The null map entry cache scope is across the entire master map but
Ian Kent cc4062
it is used by individual master map entries during master map re-read
Ian Kent cc4062
and subsequest updates resulting form it. The current null cache locking
Ian Kent cc4062
doesn't properly account for this.
Ian Kent cc4062
Ian Kent cc4062
To resolve this, when we re-read the master, map we need to block
Ian Kent cc4062
access to the null cache until the master map has been read and the
Ian Kent cc4062
null cache updated.
Ian Kent cc4062
---
Ian Kent cc4062
Ian Kent cc4062
 CHANGELOG           |    1 +
Ian Kent cc4062
 daemon/automount.c  |    4 +++-
Ian Kent cc4062
 include/automount.h |    1 +
Ian Kent cc4062
 lib/cache.c         |   33 ++++++++++++++++++++++++++-------
Ian Kent cc4062
 lib/master.c        |   27 ++++++++++++++++++++-------
Ian Kent cc4062
 lib/master_parse.y  |    5 -----
Ian Kent cc4062
 6 files changed, 51 insertions(+), 20 deletions(-)
Ian Kent cc4062
Ian Kent cc4062
Ian Kent cc4062
--- autofs-5.0.5.orig/CHANGELOG
Ian Kent cc4062
+++ autofs-5.0.5/CHANGELOG
Ian Kent cc4062
@@ -37,6 +37,7 @@
Ian Kent cc4062
 - fix wildcard map entry match.
Ian Kent cc4062
 - fix parse_sun() module init.
Ian Kent cc4062
 - dont check null cache on expire.
Ian Kent cc4062
+- fix null cache race.
Ian Kent cc4062
 
Ian Kent cc4062
 03/09/2009 autofs-5.0.5
Ian Kent cc4062
 -----------------------
Ian Kent cc4062
--- autofs-5.0.5.orig/daemon/automount.c
Ian Kent cc4062
+++ autofs-5.0.5/daemon/automount.c
Ian Kent cc4062
@@ -1273,14 +1273,16 @@ static int do_hup_signal(struct master *
Ian Kent cc4062
 	if (status)
Ian Kent cc4062
 		fatal(status);
Ian Kent cc4062
 
Ian Kent cc4062
+	master_mutex_lock();
Ian Kent cc4062
 	if (master->reading) {
Ian Kent cc4062
 		status = pthread_mutex_unlock(&mrc.mutex);
Ian Kent cc4062
 		if (status)
Ian Kent cc4062
 			fatal(status);
Ian Kent cc4062
+		master_mutex_unlock();
Ian Kent cc4062
 		return 1;
Ian Kent cc4062
 	}
Ian Kent cc4062
-
Ian Kent cc4062
 	master->reading = 1;
Ian Kent cc4062
+	master_mutex_unlock();
Ian Kent cc4062
 
Ian Kent cc4062
 	status = pthread_create(&thid, &th_attr_detached, do_read_master, NULL);
Ian Kent cc4062
 	if (status) {
Ian Kent cc4062
--- autofs-5.0.5.orig/include/automount.h
Ian Kent cc4062
+++ autofs-5.0.5/include/automount.h
Ian Kent cc4062
@@ -194,6 +194,7 @@ void cache_multi_writelock(struct mapent
Ian Kent cc4062
 void cache_multi_unlock(struct mapent *me);
Ian Kent cc4062
 int cache_delete_offset_list(struct mapent_cache *mc, const char *key);
Ian Kent cc4062
 void cache_release(struct map_source *map);
Ian Kent cc4062
+void cache_clean_null_cache(struct mapent_cache *mc);
Ian Kent cc4062
 void cache_release_null_cache(struct master *master);
Ian Kent cc4062
 struct mapent *cache_enumerate(struct mapent_cache *mc, struct mapent *me);
Ian Kent cc4062
 char *cache_get_offset(const char *prefix, char *offset, int start, struct list_head *head, struct list_head **pos);
Ian Kent cc4062
--- autofs-5.0.5.orig/lib/cache.c
Ian Kent cc4062
+++ autofs-5.0.5/lib/cache.c
Ian Kent cc4062
@@ -228,15 +228,38 @@ struct mapent_cache *cache_init(struct a
Ian Kent cc4062
 	return mc;
Ian Kent cc4062
 }
Ian Kent cc4062
 
Ian Kent cc4062
+void cache_clean_null_cache(struct mapent_cache *mc)
Ian Kent cc4062
+{
Ian Kent cc4062
+	struct mapent *me, *next;
Ian Kent cc4062
+	int i;
Ian Kent cc4062
+
Ian Kent cc4062
+	for (i = 0; i < mc->size; i++) {
Ian Kent cc4062
+		me = mc->hash[i];
Ian Kent cc4062
+		if (me == NULL)
Ian Kent cc4062
+			continue;
Ian Kent cc4062
+		next = me->next;
Ian Kent cc4062
+		free(me->key);
Ian Kent cc4062
+		if (me->mapent)
Ian Kent cc4062
+			free(me->mapent);
Ian Kent cc4062
+		free(me);
Ian Kent cc4062
+
Ian Kent cc4062
+		while (next != NULL) {
Ian Kent cc4062
+			me = next;
Ian Kent cc4062
+			next = me->next;
Ian Kent cc4062
+			free(me->key);
Ian Kent cc4062
+			free(me);
Ian Kent cc4062
+		}
Ian Kent cc4062
+	}
Ian Kent cc4062
+
Ian Kent cc4062
+	return;
Ian Kent cc4062
+}
Ian Kent cc4062
+
Ian Kent cc4062
 struct mapent_cache *cache_init_null_cache(struct master *master)
Ian Kent cc4062
 {
Ian Kent cc4062
 	struct mapent_cache *mc;
Ian Kent cc4062
 	unsigned int i;
Ian Kent cc4062
 	int status;
Ian Kent cc4062
 
Ian Kent cc4062
-	if (master->nc)
Ian Kent cc4062
-		cache_release_null_cache(master);
Ian Kent cc4062
-
Ian Kent cc4062
 	mc = malloc(sizeof(struct mapent_cache));
Ian Kent cc4062
 	if (!mc)
Ian Kent cc4062
 		return NULL;
Ian Kent cc4062
@@ -264,8 +287,6 @@ struct mapent_cache *cache_init_null_cac
Ian Kent cc4062
 	if (status)
Ian Kent cc4062
 		fatal(status);
Ian Kent cc4062
 
Ian Kent cc4062
-	cache_writelock(mc);
Ian Kent cc4062
-
Ian Kent cc4062
 	for (i = 0; i < mc->size; i++) {
Ian Kent cc4062
 		mc->hash[i] = NULL;
Ian Kent cc4062
 		INIT_LIST_HEAD(&mc->ino_index[i]);
Ian Kent cc4062
@@ -274,8 +295,6 @@ struct mapent_cache *cache_init_null_cac
Ian Kent cc4062
 	mc->ap = NULL;
Ian Kent cc4062
 	mc->map = NULL;
Ian Kent cc4062
 
Ian Kent cc4062
-	cache_unlock(mc);
Ian Kent cc4062
-
Ian Kent cc4062
 	return mc;
Ian Kent cc4062
 }
Ian Kent cc4062
 
Ian Kent cc4062
--- autofs-5.0.5.orig/lib/master.c
Ian Kent cc4062
+++ autofs-5.0.5/lib/master.c
Ian Kent cc4062
@@ -811,15 +811,28 @@ int master_read_master(struct master *ma
Ian Kent cc4062
 	unsigned int logopt = master->logopt;
Ian Kent cc4062
 	struct mapent_cache *nc;
Ian Kent cc4062
 
Ian Kent cc4062
-	nc = cache_init_null_cache(master);
Ian Kent cc4062
-	if (!nc) {
Ian Kent cc4062
-		error(logopt,
Ian Kent cc4062
-		      "failed to init null map cache for %s", master->name);
Ian Kent cc4062
-		return 0;
Ian Kent cc4062
+	/*
Ian Kent cc4062
+	 * We need to clear and re-populate the null map entry cache
Ian Kent cc4062
+	 * before alowing anyone else to use it.
Ian Kent cc4062
+	 */
Ian Kent cc4062
+	if (master->nc) {
Ian Kent cc4062
+		cache_writelock(master->nc);
Ian Kent cc4062
+		nc = master->nc;
Ian Kent cc4062
+		cache_clean_null_cache(nc);
Ian Kent cc4062
+	} else {
Ian Kent cc4062
+		nc = cache_init_null_cache(master);
Ian Kent cc4062
+		if (!nc) {
Ian Kent cc4062
+			error(logopt,
Ian Kent cc4062
+			      "failed to init null map cache for %s",
Ian Kent cc4062
+			      master->name);
Ian Kent cc4062
+			return 0;
Ian Kent cc4062
+		}
Ian Kent cc4062
+		cache_writelock(nc);
Ian Kent cc4062
+		master->nc = nc;
Ian Kent cc4062
 	}
Ian Kent cc4062
-	master->nc = nc;
Ian Kent cc4062
-
Ian Kent cc4062
 	master_init_scan();
Ian Kent cc4062
+	lookup_nss_read_master(master, age);
Ian Kent cc4062
+	cache_unlock(nc);
Ian Kent cc4062
 
Ian Kent cc4062
 	lookup_nss_read_master(master, age);
Ian Kent cc4062
 	if (!master->read_fail)
Ian Kent cc4062
--- autofs-5.0.5.orig/lib/master_parse.y
Ian Kent cc4062
+++ autofs-5.0.5/lib/master_parse.y
Ian Kent cc4062
@@ -741,21 +741,16 @@ int master_parse_entry(const char *buffe
Ian Kent cc4062
 
Ian Kent cc4062
 	/* Add null map entries to the null map cache */
Ian Kent cc4062
 	if (type && !strcmp(type, "null")) {
Ian Kent cc4062
-		cache_writelock(nc);
Ian Kent cc4062
 		cache_update(nc, NULL, path, NULL, lineno);
Ian Kent cc4062
-		cache_unlock(nc);
Ian Kent cc4062
 		local_free_vars();
Ian Kent cc4062
 		return 1;
Ian Kent cc4062
 	}
Ian Kent cc4062
 
Ian Kent cc4062
 	/* Ignore all subsequent matching nulled entries */
Ian Kent cc4062
-	cache_readlock(nc);
Ian Kent cc4062
 	if (cache_lookup_distinct(nc, path)) {
Ian Kent cc4062
-		cache_unlock(nc);
Ian Kent cc4062
 		local_free_vars();
Ian Kent cc4062
 		return 1;
Ian Kent cc4062
 	}
Ian Kent cc4062
-	cache_unlock(nc);
Ian Kent cc4062
 
Ian Kent cc4062
 	if (debug || verbose) {
Ian Kent cc4062
 		logopt = (debug ? LOGOPT_DEBUG : 0);