autofs-5.0.5 - 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.
---
CHANGELOG | 1 +
daemon/automount.c | 4 +++-
include/automount.h | 1 +
lib/cache.c | 33 ++++++++++++++++++++++++++-------
lib/master.c | 27 ++++++++++++++++++++-------
lib/master_parse.y | 5 -----
6 files changed, 51 insertions(+), 20 deletions(-)
--- autofs-5.0.5.orig/CHANGELOG
+++ autofs-5.0.5/CHANGELOG
@@ -37,6 +37,7 @@
- fix wildcard map entry match.
- fix parse_sun() module init.
- dont check null cache on expire.
+- fix null cache race.
03/09/2009 autofs-5.0.5
-----------------------
--- autofs-5.0.5.orig/daemon/automount.c
+++ autofs-5.0.5/daemon/automount.c
@@ -1273,14 +1273,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.5.orig/include/automount.h
+++ autofs-5.0.5/include/automount.h
@@ -194,6 +194,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.5.orig/lib/cache.c
+++ autofs-5.0.5/lib/cache.c
@@ -228,15 +228,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;
@@ -264,8 +287,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]);
@@ -274,8 +295,6 @@ struct mapent_cache *cache_init_null_cac
mc->ap = NULL;
mc->map = NULL;
- cache_unlock(mc);
-
return mc;
}
--- autofs-5.0.5.orig/lib/master.c
+++ autofs-5.0.5/lib/master.c
@@ -811,15 +811,28 @@ 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);
lookup_nss_read_master(master, age);
if (!master->read_fail)
--- autofs-5.0.5.orig/lib/master_parse.y
+++ autofs-5.0.5/lib/master_parse.y
@@ -741,21 +741,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);