Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 130701790bf2d95e902edf16031ff596 > files > 76

autofs-5.0.1-0.rc2.164.el5_8.src.rpm

autofs-5.0.1 - fix null cache race

From: Ian Kent <raven@themaw.net>

The null map entry cache scope is across the entire master map but
it is used by individual master map entries during master map re-read
and subsequest updates resulting form it. The current null cache locking
doesn't properly account for this.

To resolve this, when we re-read the master, map we need to block
access to the null cache until the master map has been read and the
null cache updated.
---

 daemon/automount.c  |    4 +++-
 include/automount.h |    1 +
 lib/cache.c         |   33 ++++++++++++++++++++++++++-------
 lib/master.c        |   28 ++++++++++++++++++++--------
 lib/master_parse.y  |    5 -----
 5 files changed, 50 insertions(+), 21 deletions(-)


--- autofs-5.0.1.orig/daemon/automount.c
+++ autofs-5.0.1/daemon/automount.c
@@ -1254,14 +1254,16 @@ static int do_hup_signal(struct master *
 	if (status)
 		fatal(status);
 
+	master_mutex_lock();
 	if (master->reading) {
 		status = pthread_mutex_unlock(&mrc.mutex);
 		if (status)
 			fatal(status);
+		master_mutex_unlock();
 		return 1;
 	}
-
 	master->reading = 1;
+	master_mutex_unlock();
 
 	status = pthread_create(&thid, &th_attr_detached, do_read_master, NULL);
 	if (status) {
--- autofs-5.0.1.orig/include/automount.h
+++ autofs-5.0.1/include/automount.h
@@ -192,6 +192,7 @@ void cache_multi_writelock(struct mapent
 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);
+void cache_clean_null_cache(struct mapent_cache *mc);
 void cache_release_null_cache(struct master *master);
 struct mapent *cache_enumerate(struct mapent_cache *mc, struct mapent *me);
 char *cache_get_offset(const char *prefix, char *offset, int start, struct list_head *head, struct list_head **pos);
--- autofs-5.0.1.orig/lib/cache.c
+++ autofs-5.0.1/lib/cache.c
@@ -230,15 +230,38 @@ struct mapent_cache *cache_init(struct a
 	return mc;
 }
 
+void cache_clean_null_cache(struct mapent_cache *mc)
+{
+	struct mapent *me, *next;
+	int i;
+
+	for (i = 0; i < mc->size; i++) {
+		me = mc->hash[i];
+		if (me == NULL)
+			continue;
+		next = me->next;
+		free(me->key);
+		if (me->mapent)
+			free(me->mapent);
+		free(me);
+
+		while (next != NULL) {
+			me = next;
+			next = me->next;
+			free(me->key);
+			free(me);
+		}
+	}
+
+	return;
+}
+
 struct mapent_cache *cache_init_null_cache(struct master *master)
 {
 	struct mapent_cache *mc;
 	unsigned int i;
 	int status;
 
-	if (master->nc)
-		cache_release_null_cache(master);
-
 	mc = malloc(sizeof(struct mapent_cache));
 	if (!mc)
 		return NULL;
@@ -266,8 +289,6 @@ struct mapent_cache *cache_init_null_cac
 	if (status)
 		fatal(status);
 
-	cache_writelock(mc);
-
 	for (i = 0; i < mc->size; i++) {
 		mc->hash[i] = NULL;
 		INIT_LIST_HEAD(&mc->ino_index[i]);
@@ -276,8 +297,6 @@ struct mapent_cache *cache_init_null_cac
 	mc->ap = NULL;
 	mc->map = NULL;
 
-	cache_unlock(mc);
-
 	return mc;
 }
 
--- autofs-5.0.1.orig/lib/master.c
+++ autofs-5.0.1/lib/master.c
@@ -814,17 +814,29 @@ int master_read_master(struct master *ma
 	unsigned int logopt = master->logopt;
 	struct mapent_cache *nc;
 
-	nc = cache_init_null_cache(master);
-	if (!nc) {
-		error(logopt,
-		      "failed to init null map cache for %s", master->name);
-		return 0;
+	/*
+	 * We need to clear and re-populate the null map entry cache
+	 * before alowing anyone else to use it.
+	 */
+	if (master->nc) {
+		cache_writelock(master->nc);
+		nc = master->nc;
+		cache_clean_null_cache(nc);
+	} else {
+		nc = cache_init_null_cache(master);
+		if (!nc) {
+			error(logopt,
+			      "failed to init null map cache for %s",
+			      master->name);
+			return 0;
+		}
+		cache_writelock(nc);
+		master->nc = nc;
 	}
-	master->nc = nc;
-
 	master_init_scan();
-
 	lookup_nss_read_master(master, age);
+	cache_unlock(nc);
+
 	master_mount_mounts(master, age, readall);
 
 	master_mutex_lock();
--- autofs-5.0.1.orig/lib/master_parse.y
+++ autofs-5.0.1/lib/master_parse.y
@@ -743,21 +743,16 @@ int master_parse_entry(const char *buffe
 
 	/* Add null map entries to the null map cache */
 	if (type && !strcmp(type, "null")) {
-		cache_writelock(nc);
 		cache_update(nc, NULL, path, NULL, lineno);
-		cache_unlock(nc);
 		local_free_vars();
 		return 1;
 	}
 
 	/* Ignore all subsequent matching nulled entries */
-	cache_readlock(nc);
 	if (cache_lookup_distinct(nc, path)) {
-		cache_unlock(nc);
 		local_free_vars();
 		return 1;
 	}
-	cache_unlock(nc);
 
 	if (debug || verbose) {
 		logopt = (debug ? LOGOPT_DEBUG : 0);