Sophie

Sophie

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

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

autofs-5.0.4 - fix negative cache non-existent key

From: Ian Kent <raven@themaw.net>

autofs was not recording map entries that don't exist for negative
caching. This was causing unwanted network map lookups.
---

 daemon/lookup.c          |   48 +++++++++++++++++++++++++++++++++++++++++++++--
 modules/lookup_file.c    |   20 ++++++++++++-------
 modules/lookup_hosts.c   |   23 ++++++++++++++++++----
 modules/lookup_ldap.c    |   20 ++++++++++++-------
 modules/lookup_nisplus.c |   19 ++++++++++++------
 modules/lookup_program.c |   35 ++++++++++++++++++++++++++--------
 modules/lookup_yp.c      |   19 ++++++++++++------
 7 files changed, 144 insertions(+), 40 deletions(-)


--- autofs-5.0.1.orig/daemon/lookup.c
+++ autofs-5.0.1/daemon/lookup.c
@@ -805,6 +805,45 @@ static enum nsswitch_status lookup_map_n
 	return result;
 }
 
+static void update_negative_cache(struct autofs_point *ap, struct map_source *source, char *name)
+{
+	struct master_mapent *entry = ap->entry;
+	struct map_source *map;
+	struct mapent *me;
+
+	/* Have we recorded the lookup fail for negative caching? */
+	me = lookup_source_mapent(ap, name, LKP_DISTINCT);
+	if (me)
+		/*
+		 *  Already exists in the cache, the mount fail updates
+		 *  will update negative timeout status.
+		 */
+		cache_unlock(me->mc);
+	else {
+		/* Notify only once after fail */
+		error(ap->logopt, "key \"%s\" not found in map.", name);
+
+		/* Doesn't exist in any source, just add it somewhere */
+		if (source)
+			map = source;
+		else
+			map = entry->maps;
+		if (map) {
+			time_t now = time(NULL);
+			int rv = CHE_FAIL;
+
+			cache_writelock(map->mc);
+			rv = cache_update(map->mc, map, name, NULL, now);
+			if (rv != CHE_FAIL) {
+				me = cache_lookup_distinct(map->mc, name);
+				me->status = now + ap->negative_timeout;
+			}
+			cache_unlock(map->mc);
+		}
+	}
+	return;
+}
+
 int lookup_nss_mount(struct autofs_point *ap, struct map_source *source, const char *name, int name_len)
 {
 	struct master_mapent *entry = ap->entry;
@@ -909,8 +948,13 @@ int lookup_nss_mount(struct autofs_point
 	send_map_update_request(ap);
 	pthread_cleanup_pop(1);
 
-	if (result == NSS_STATUS_NOTFOUND)
-		error(ap->logopt, "key \"%s\" not found in map.", name);
+	/*
+	 * The last source lookup will return NSS_STATUS_NOTFOUND if the
+	 * map exits and the key has not been found but the map may also
+	 * not exist in which case the key is also not found.
+	 */
+	if (result == NSS_STATUS_NOTFOUND || result == NSS_STATUS_UNAVAIL)
+		update_negative_cache(ap, source, name);
 
 	return !result;
 }
--- autofs-5.0.1.orig/modules/lookup_file.c
+++ autofs-5.0.1/modules/lookup_file.c
@@ -1073,14 +1073,20 @@ int lookup_mount(struct autofs_point *ap
 	if (key_len > KEY_MAX_LEN)
 		return NSS_STATUS_NOTFOUND;
 
-	/* Check if we recorded a mount fail for this key */
-	cache_readlock(mc);
-	me = cache_lookup_distinct(mc, key);
-	if (me && me->status >= time(NULL)) {
-		cache_unlock(mc);
-		return NSS_STATUS_UNAVAIL;
+	/* Check if we recorded a mount fail for this key anywhere */
+	me = lookup_source_mapent(ap, key, LKP_DISTINCT);
+	if (me) {
+		if (me->status >= time(NULL)) {
+			cache_unlock(me->mc);
+			return NSS_STATUS_NOTFOUND;
+		}
+
+		/* Negative timeout expired for non-existent entry. */
+		if (!me->mapent)
+			cache_delete(me->mc, key);
+
+		cache_unlock(me->mc);
 	}
-	cache_unlock(mc);
 
 	/*
 	 * We can't check the direct mount map as if it's not in
--- autofs-5.0.1.orig/modules/lookup_hosts.c
+++ autofs-5.0.1/modules/lookup_hosts.c
@@ -130,12 +130,27 @@ int lookup_mount(struct autofs_point *ap
 
 	mc = source->mc;
 
+	/* Check if we recorded a mount fail for this key anywhere */
+	me = lookup_source_mapent(ap, name, LKP_DISTINCT);
+	if (me) {
+		struct mapent_cache *fmc = me->mc;
+
+		if (me->status >= time(NULL)) {
+			cache_unlock(fmc);
+			return NSS_STATUS_NOTFOUND;
+		}
+
+		if (!me->mapent) {
+			cache_delete(fmc, name);
+			me = NULL;
+		}
+
+		cache_unlock(fmc);
+	}
+
 	cache_readlock(mc);
 	me = cache_lookup_distinct(mc, name);
-	if (me && me->status >= time(NULL)) {
-		cache_unlock(mc);
-		return NSS_STATUS_NOTFOUND;
-	} else if (!me) {
+	if (!me) {
 		cache_unlock(mc);
 		/*
 		 * We haven't read the list of hosts into the
--- autofs-5.0.1.orig/modules/lookup_ldap.c
+++ autofs-5.0.1/modules/lookup_ldap.c
@@ -2502,14 +2502,20 @@ int lookup_mount(struct autofs_point *ap
 	if (key_len > KEY_MAX_LEN)
 		return NSS_STATUS_NOTFOUND;
 
-	/* Check if we recorded a mount fail for this key */
-	cache_readlock(mc);
-	me = cache_lookup_distinct(mc, key);
-	if (me && me->status >= time(NULL)) {
-		cache_unlock(mc);
-		return NSS_STATUS_NOTFOUND;
+	/* Check if we recorded a mount fail for this key anywhere */
+	me = lookup_source_mapent(ap, key, LKP_DISTINCT);
+	if (me) {
+		if (me->status >= time(NULL)) {
+			cache_unlock(me->mc);
+			return NSS_STATUS_NOTFOUND;
+		}
+
+		/* Negative timeout expired for non-existent entry. */
+		if (!me->mapent)
+			cache_delete(me->mc, key);
+
+		cache_unlock(me->mc);
 	}
-	cache_unlock(mc);
 
         /*
 	 * We can't check the direct mount map as if it's not in
--- autofs-5.0.1.orig/modules/lookup_nisplus.c
+++ autofs-5.0.1/modules/lookup_nisplus.c
@@ -493,13 +493,20 @@ int lookup_mount(struct autofs_point *ap
 	if (key_len > KEY_MAX_LEN)
 		return NSS_STATUS_NOTFOUND;
 
-	cache_readlock(mc);
-	me = cache_lookup_distinct(mc, key);
-	if (me && me->status >= time(NULL)) {
-		cache_unlock(mc);
-		return NSS_STATUS_NOTFOUND;
+	/* Check if we recorded a mount fail for this key anywhere */
+	me = lookup_source_mapent(ap, key, LKP_DISTINCT);
+	if (me) {
+		if (me->status >= time(NULL)) {
+			cache_unlock(me->mc);
+			return NSS_STATUS_NOTFOUND;
+		}
+
+		/* Negative timeout expired for non-existent entry. */
+		if (!me->mapent)
+			cache_delete(me->mc, key);
+
+		cache_unlock(me->mc);
 	}
-	cache_unlock(mc);
 
 	/*
 	 * We can't check the direct mount map as if it's not in
--- autofs-5.0.1.orig/modules/lookup_program.c
+++ autofs-5.0.1/modules/lookup_program.c
@@ -131,13 +131,25 @@ int lookup_mount(struct autofs_point *ap
 
 	mc = source->mc;
 
+	/* Check if we recorded a mount fail for this key anywhere */
+	me = lookup_source_mapent(ap, name, LKP_DISTINCT);
+	if (me) {
+		if (me->status >= time(NULL)) {
+			cache_unlock(me->mc);
+			return NSS_STATUS_NOTFOUND;
+		}
+
+		/* Negative timeout expired for non-existent entry. */
+		if (!me->mapent)
+			cache_delete(me->mc, name);
+
+		cache_unlock(me->mc);
+	}
+
 	/* Catch installed direct offset triggers */
-	cache_readlock(mc);
+	cache_writelock(mc);
 	me = cache_lookup_distinct(mc, name);
-	if (me && me->status >= time(NULL)) {
-		cache_unlock(mc);
-		return NSS_STATUS_NOTFOUND;
-	} else if (!me) {
+	if (!me) {
 		cache_unlock(mc);
 		/*
 		 * If there's a '/' in the name and the offset is not in
@@ -149,8 +161,6 @@ int lookup_mount(struct autofs_point *ap
 			return NSS_STATUS_NOTFOUND;
 		}
 	} else {
-		cache_unlock(mc);
-
 		/* Otherwise we found a valid offset so try mount it */
 		debug(ap->logopt, MODPREFIX "%s -> %s", name, me->mapent);
 
@@ -163,19 +173,28 @@ int lookup_mount(struct autofs_point *ap
 		 */
 		if (strchr(name, '/') ||
 		    me->age + ap->negative_timeout > time(NULL)) {
+			char *ent = NULL;
+
+			if (me->mapent) {
+				ent = alloca(strlen(me->mapent) + 1);
+				strcpy(ent, me->mapent);
+			}
+			cache_unlock(mc);
 			master_source_current_wait(ap->entry);
 			ap->entry->current = source;
 			ret = ctxt->parse->parse_mount(ap, name,
-				 name_len, me->mapent, ctxt->parse->context);
+				 name_len, ent, ctxt->parse->context);
 			goto out_free;
 		} else {
 			if (me->multi) {
+				cache_unlock(mc);
 				warn(ap->logopt, MODPREFIX
 				     "unexpected lookup for active multi-mount"
 				     " key %s, returning fail", name);
 				return NSS_STATUS_UNAVAIL;
 			}
 			cache_delete(mc, name);
+			cache_unlock(mc);
 		}
 	}
 
--- autofs-5.0.1.orig/modules/lookup_yp.c
+++ autofs-5.0.1/modules/lookup_yp.c
@@ -602,13 +602,20 @@ int lookup_mount(struct autofs_point *ap
 	if (key_len > KEY_MAX_LEN)
 		return NSS_STATUS_NOTFOUND;
 
-	cache_readlock(mc);
-	me = cache_lookup_distinct(mc, key);
-	if (me && me->status >= time(NULL)) {
-		cache_unlock(mc);
-		return NSS_STATUS_NOTFOUND;
+	/* Check if we recorded a mount fail for this key anywhere */
+	me = lookup_source_mapent(ap, key, LKP_DISTINCT);
+	if (me) {
+		if (me->status >= time(NULL)) {
+			cache_unlock(me->mc);
+			return NSS_STATUS_NOTFOUND;
+		}
+
+		/* Negative timeout expired for non-existent entry. */
+		if (!me->mapent)
+			cache_delete(me->mc, key);
+
+		cache_unlock(me->mc);
 	}
-	cache_unlock(mc);
 
 	 /*
 	  * We can't check the direct mount map as if it's not in