Sophie

Sophie

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

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

autofs-5.0.4 - always read file maps

From: Ian Kent <raven@themaw.net>

autofs tries to not load an entire map into the internal cache unless it
has to. For maps that do get loaded into the cache it relies on checks to
work out if a map is up to date in order to trigger a map read. This is
fine for maps that can do direct key lookups but file maps need to do a
linear search through the file when locating an entry for a key. For large
maps this can be a huge overhead. This patch make autofs always load file
based maps at start and makes use of the map file mtime to discover if the
cache needs to be refreshed.
---

 daemon/lookup.c       |    9 ++++--
 modules/lookup_file.c |   70 ++++++++++++++++++++++----------------------------
 2 files changed, 38 insertions(+), 41 deletions(-)


--- autofs-5.0.1.orig/daemon/lookup.c
+++ autofs-5.0.1/daemon/lookup.c
@@ -284,10 +284,13 @@ static int do_read_map(struct autofs_poi
 	 * for the fail cases to function correctly and to cache the
 	 * lookup handle.
 	 *
-	 * We always need to whole map for direct mounts in order to
-	 * mount the triggers.
+	 * We always need to read the whole map for direct mounts in
+	 * order to mount the triggers. We also want to read the whole
+	 * map if it's a file map to avoid potentially lengthy linear
+	 * file scanning.
 	 */
-	if (!ap->ghost && ap->type != LKP_DIRECT)
+	if (strcmp(map->type, "file") &&
+	    !ap->ghost && ap->type != LKP_DIRECT)
 		return NSS_STATUS_SUCCESS;
 
 	if (!map->stale)
--- autofs-5.0.1.orig/modules/lookup_file.c
+++ autofs-5.0.1/modules/lookup_file.c
@@ -46,7 +46,6 @@ typedef enum { esc_none, esc_char, esc_v
 
 struct lookup_context {
 	const char *mapname;
-	time_t mtime;
 	struct parse_mod *parse;
 };
 
@@ -56,7 +55,6 @@ int lookup_init(const char *mapfmt, int 
 {
 	struct lookup_context *ctxt;
 	char buf[MAX_ERR_BUF];
-	struct stat st;
 
 	*context = NULL;
 
@@ -89,15 +87,6 @@ int lookup_init(const char *mapfmt, int 
 		return 1;
 	}
 
-	if (stat(ctxt->mapname, &st)) {
-		free(ctxt);
-		logmsg(MODPREFIX "file map %s, could not stat",
-		     argv[0]);
-		return 1;
-	}
-		
-	ctxt->mtime = st.st_mtime;
-
 	if (!mapfmt)
 		mapfmt = MAPFMT_DEFAULT;
 
@@ -397,7 +386,6 @@ int lookup_read_master(struct master *ma
 	int blen;
 	char *path;
 	char *ent;
-	struct stat st;
 	FILE *f;
 	int fd, cl_flags;
 	unsigned int path_len, ent_len;
@@ -515,13 +503,6 @@ int lookup_read_master(struct master *ma
 			break;
 	}
 
-	if (fstat(fd, &st)) {
-		crit(logopt, MODPREFIX "file map %s, could not stat",
-		       ctxt->mapname);
-		return NSS_STATUS_UNAVAIL;
-	}
-	ctxt->mtime = st.st_mtime;
-
 	fclose(f);
 
 	return NSS_STATUS_SUCCESS;
@@ -653,7 +634,6 @@ int lookup_read_map(struct autofs_point 
 	struct mapent_cache *mc;
 	char *key;
 	char *mapent;
-	struct stat st;
 	FILE *f;
 	int fd, cl_flags;
 	unsigned int k_len, m_len;
@@ -764,13 +744,6 @@ int lookup_read_map(struct autofs_point 
 			break;
 	}
 
-	if (fstat(fd, &st)) {
-		crit(ap->logopt,
-		     MODPREFIX "file map %s, could not stat",
-		     ctxt->mapname);
-		return NSS_STATUS_UNAVAIL;
-	}
-	ctxt->mtime = st.st_mtime;
 	source->age = age;
 
 	fclose(f);
@@ -983,9 +956,6 @@ static int check_map_indirect(struct aut
 	if (ret == CHE_FAIL)
 		return NSS_STATUS_NOTFOUND;
 
-	if (ret & CHE_UPDATED)
-		source->stale = 1;
-
 	pthread_cleanup_push(cache_lock_cleanup, mc);
 	cache_writelock(mc);
 	exists = cache_lookup_distinct(mc, key);
@@ -995,7 +965,6 @@ static int check_map_indirect(struct aut
 			free(exists->mapent);
 			exists->mapent = NULL;
 			exists->status = 0;
-			source->stale = 1;
 		}
 	}
 	pthread_cleanup_pop(1);
@@ -1017,14 +986,8 @@ static int check_map_indirect(struct aut
 		we = cache_lookup_distinct(mc, "*");
 		if (we) {
 			/* Wildcard entry existed and is now gone */
-			if (we->source == source && (wild & CHE_MISSING)) {
+			if (we->source == source && (wild & CHE_MISSING))
 				cache_delete(mc, "*");
-				source->stale = 1;
-			}
-		} else {
-			/* Wildcard not in map but now is */
-			if (wild & (CHE_OK | CHE_UPDATED))
-				source->stale = 1;
 		}
 		pthread_cleanup_pop(1);
 
@@ -1094,9 +1057,39 @@ int lookup_mount(struct autofs_point *ap
 	 * we never know about it.
 	 */
 	if (ap->type == LKP_INDIRECT && *key != '/') {
+		struct stat st;
 		char *lkp_key;
 
+		/*
+		 * We can skip the map lookup and cache update altogether
+		 * if we know the map hasn't been modified since it was
+		 * last read. If it has then we can mark the map stale
+		 * so a re-read is triggered following the lookup.
+		 */
+		if (stat(ctxt->mapname, &st)) {
+			error(ap->logopt, MODPREFIX
+			      "file map %s, could not stat", ctxt->mapname);
+			return NSS_STATUS_UNAVAIL;
+		}
+
 		cache_readlock(mc);
+		me = cache_lookup_first(mc);
+		if (me && st.st_mtime <= me->age) {
+			/*
+			 * If any map instances are present for this source
+			 * then either we have plus included entries or we
+			 * are looking through the list of nsswitch sources.
+			 * In either case we cannot avoid reading through the
+			 * map because we must preserve the key order over
+			 * multiple sources. But also, we can't know, at this
+			 * point, if a source instance has been changed since
+			 * the last time we checked it.
+			 */
+			if (!source->instance)
+				goto do_cache_lookup;
+		} else
+			source->stale = 1;
+
 		me = cache_lookup_distinct(mc, key);
 		if (me && me->multi)
 			lkp_key = strdup(me->multi->key);
@@ -1120,6 +1113,7 @@ int lookup_mount(struct autofs_point *ap
 	}
 
 	cache_readlock(mc);
+do_cache_lookup:
 	me = cache_lookup(mc, key);
 	/* Stale mapent => check for entry in alternate source or wildcard */
 	if (me && !me->mapent) {