Blob Blame History Raw
autofs-5.1.7 - eliminate cache_lookup_offset() usage

From: Ian Kent <raven@themaw.net>

The function cache_lookup_offset() will do a linear search when
looking for an offset. If the number of offsets is large this
can be a lot of overhead.

But it's possible to use the information already present where
this is called to to do a hashed lookup instead.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG           |    1 +
 lib/mounts.c        |   82 +++++++++++++++++++++++++++++++++------------------
 modules/parse_sun.c |   77 ++++++++++++++++++++++++++++++------------------
 3 files changed, 102 insertions(+), 58 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 0b577909..484bd866 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@
 - use sprintf() when constructing hosts mapent.
 - fix mnts_remove_amdmount() uses wrong list.
 - Fix option for master read wait.
+- eliminate cache_lookup_offset() usage.
 
 25/01/2021 autofs-5.1.7
 - make bind mounts propagation slave by default.
diff --git a/lib/mounts.c b/lib/mounts.c
index ccbd52e0..42e8ef07 100644
--- a/lib/mounts.c
+++ b/lib/mounts.c
@@ -2495,24 +2495,27 @@ int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
 	char *offset = path;
 	struct mapent *oe;
 	struct list_head *pos = NULL;
-	unsigned int fs_path_len;
+	unsigned int root_len = strlen(root);
 	int mounted;
 
-	fs_path_len = start + strlen(base);
-	if (fs_path_len > PATH_MAX)
-		return -1;
-
 	mounted = 0;
 	offset = cache_get_offset(base, offset, start, &me->multi_list, &pos);
 	while (offset) {
-		int plen = fs_path_len + strlen(offset);
+		char key[PATH_MAX + 1];
+		int key_len = root_len + strlen(offset);
 
-		if (plen > PATH_MAX) {
+		if (key_len > PATH_MAX) {
 			warn(ap->logopt, "path loo long");
 			goto cont;
 		}
 
-		oe = cache_lookup_offset(base, offset, start, &me->multi_list);
+		/* The root offset is always mounted seperately so the
+		 * offset path will always be root + offset.
+		 */
+		strcpy(key, root);
+		strcat(key, offset);
+
+		oe = cache_lookup_distinct(me->mc, key);
 		if (!oe || !oe->mapent)
 			goto cont;
 
@@ -2525,12 +2528,8 @@ int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
 		 */
 		if (ap->state == ST_READMAP && ap->flags & MOUNT_FLAG_REMOUNT) {
 			if (oe->ioctlfd != -1 ||
-			    is_mounted(oe->key, MNTS_REAL)) {
-				char oe_root[PATH_MAX + 1];
-				strcpy(oe_root, root);
-				strcat(oe_root, offset); 
-				mount_multi_triggers(ap, oe, oe_root, strlen(oe_root), base);
-			}
+			    is_mounted(oe->key, MNTS_REAL))
+				mount_multi_triggers(ap, oe, key, strlen(key), base);
 		}
 cont:
 		offset = cache_get_offset(base,
@@ -2584,6 +2583,8 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
 	const char o_root[] = "/";
 	const char *mm_base;
 	int left, start;
+	unsigned int root_len;
+	unsigned int mm_base_len;
 
 	left = 0;
 	start = strlen(root);
@@ -2597,11 +2598,28 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
 
 	pos = NULL;
 	offset = path;
+	root_len = start;
+	mm_base_len = strlen(mm_base);
 
 	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
+		char key[PATH_MAX + 1];
+		int key_len = root_len + strlen(offset);
 		char *oe_base;
 
-		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
+		if (mm_base_len > 1)
+			key_len += mm_base_len;
+
+		if (key_len > PATH_MAX) {
+			warn(ap->logopt, "path loo long");
+			continue;
+		}
+
+		strcpy(key, root);
+		if (mm_base_len > 1)
+			strcat(key, mm_base);
+		strcat(key, offset);
+
+		oe = cache_lookup_distinct(me->mc, key);
 		/* root offset is a special case */
 		if (!oe || (strlen(oe->key) - start) == 1)
 			continue;
@@ -2686,13 +2704,14 @@ int clean_stale_multi_triggers(struct autofs_point *ap,
 	char *root;
 	char mm_top[PATH_MAX + 1];
 	char path[PATH_MAX + 1];
-	char buf[MAX_ERR_BUF];
 	char *offset;
 	struct mapent *oe;
 	struct list_head *mm_root, *pos;
 	const char o_root[] = "/";
 	const char *mm_base;
 	int left, start;
+	unsigned int root_len;
+	unsigned int mm_base_len;
 	time_t age;
 
 	if (top)
@@ -2720,14 +2739,30 @@ int clean_stale_multi_triggers(struct autofs_point *ap,
 
 	pos = NULL;
 	offset = path;
+	root_len = start;
+	mm_base_len = strlen(mm_base);
 	age = me->multi->age;
 
 	while ((offset = cache_get_offset(mm_base, offset, start, mm_root, &pos))) {
+		char key[PATH_MAX + 1];
+		int key_len = root_len + strlen(offset);
 		char *oe_base;
-		char *key;
 		int ret;
 
-		oe = cache_lookup_offset(mm_base, offset, start, &me->multi_list);
+		if (mm_base_len > 1)
+			key_len += mm_base_len;
+
+		if (key_len > PATH_MAX) {
+			warn(ap->logopt, "path loo long");
+			continue;
+		}
+
+		strcpy(key, root);
+		if (mm_base_len > 1)
+			strcat(key, mm_base);
+		strcat(key, offset);
+
+		oe = cache_lookup_distinct(me->mc, key);
 		/* root offset is a special case */
 		if (!oe || (strlen(oe->key) - start) == 1)
 			continue;
@@ -2778,14 +2813,6 @@ int clean_stale_multi_triggers(struct autofs_point *ap,
 			}
 		}
 
-		key = strdup(oe->key);
-		if (!key) {
-	                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
-		        error(ap->logopt, "malloc: %s", estr);
-			left++;
-			continue;
-		}
-
 		debug(ap->logopt, "umount offset %s", oe->key);
 
 		if (umount_autofs_offset(ap, oe)) {
@@ -2800,7 +2827,6 @@ int clean_stale_multi_triggers(struct autofs_point *ap,
 				if (cache_delete_offset(oe->mc, key) == CHE_FAIL)
 					error(ap->logopt,
 					     "failed to delete offset key %s", key);
-				free(key);
 				continue;
 			}
 
@@ -2816,7 +2842,6 @@ int clean_stale_multi_triggers(struct autofs_point *ap,
 					left++;
 					/* But we did origianlly create this */
 					oe->flags |= MOUNT_FLAG_DIR_CREATED;
-					free(key);
 					continue;
 				}
 				/*
@@ -2834,7 +2859,6 @@ int clean_stale_multi_triggers(struct autofs_point *ap,
 				error(ap->logopt,
 				     "failed to delete offset key %s", key);
 		}
-		free(key);
 	}
 
 	return left;
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
index 4b137f99..819d6adc 100644
--- a/modules/parse_sun.c
+++ b/modules/parse_sun.c
@@ -1086,6 +1086,8 @@ static void cleanup_multi_triggers(struct autofs_point *ap,
 	struct list_head *mm_root, *pos;
 	const char o_root[] = "/";
 	const char *mm_base;
+	unsigned int root_len;
+	unsigned int mm_base_len;
 
 	mm_root = &me->multi->multi_list;
 
@@ -1095,16 +1097,31 @@ static void cleanup_multi_triggers(struct autofs_point *ap,
 		mm_base = base;
 
 	pos = NULL;
+	root_len = strlen(root);
+	mm_base_len = strlen(mm_base);
 
 	/* Make sure "none" of the offsets have an active mount. */
 	while ((poffset = cache_get_offset(mm_base, poffset, start, mm_root, &pos))) {
-		oe = cache_lookup_offset(mm_base, poffset, start, &me->multi_list);
-		/* root offset is a special case */
-		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
+		unsigned int path_len = root_len + strlen(poffset);
+
+		if (mm_base_len > 1)
+			path_len += mm_base_len;
+
+		if (path_len > PATH_MAX) {
+			warn(ap->logopt, "path loo long");
 			continue;
+		}
 
 		strcpy(path, root);
+		if (mm_base_len > 1)
+			strcat(path, mm_base);
 		strcat(path, poffset);
+
+		oe = cache_lookup_distinct(me->mc, path);
+		/* root offset is a special case */
+		if (!oe || !oe->mapent || (strlen(oe->key) - start) == 1)
+			continue;
+
 		if (umount(path)) {
 			error(ap->logopt, "error recovering from mount fail");
 			error(ap->logopt, "cannot umount offset %s", path);
@@ -1117,17 +1134,14 @@ static void cleanup_multi_triggers(struct autofs_point *ap,
 static int mount_subtree(struct autofs_point *ap, struct mapent *me,
 			 const char *name, char *loc, char *options, void *ctxt)
 {
-	struct mapent *mm;
 	struct mapent *ro;
 	char *mm_root, *mm_base, *mm_key;
-	const char *mnt_root;
-	unsigned int mm_root_len, mnt_root_len;
+	unsigned int mm_root_len;
 	int start, ret = 0, rv;
 
 	rv = 0;
 
-	mm = me->multi;
-	mm_key = mm->key;
+	mm_key = me->multi->key;
 
 	if (*mm_key == '/') {
 		mm_root = mm_key;
@@ -1141,20 +1155,26 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
 	}
 	mm_root_len = strlen(mm_root);
 
-	mnt_root = mm_root;
-	mnt_root_len = mm_root_len;
-
 	if (me == me->multi) {
+		char key[PATH_MAX + 1];
+
+		if (mm_root_len + 1 > PATH_MAX) {
+			warn(ap->logopt, "path loo long");
+			return 1;
+		}
+
 		/* name = NULL */
 		/* destination = mm_root */
 		mm_base = "/";
 
+		strcpy(key, mm_root);
+		strcat(key, mm_base);
+
 		/* Mount root offset if it exists */
-		ro = cache_lookup_offset(mm_base, mm_base, strlen(mm_root), &me->multi_list);
+		ro = cache_lookup_distinct(me->mc, key);
 		if (ro) {
-			char *myoptions, *ro_loc, *tmp;
+			char *myoptions, *ro_loc;
 			int namelen = name ? strlen(name) : 0;
-			const char *root;
 			int ro_len;
 
 			myoptions = NULL;
@@ -1172,13 +1192,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
 			if (ro_loc)
 				ro_len = strlen(ro_loc);
 
-			tmp = alloca(mnt_root_len + 2);
-			strcpy(tmp, mnt_root);
-			tmp[mnt_root_len] = '/';
-			tmp[mnt_root_len + 1] = '\0';
-			root = tmp;
-
-			rv = sun_mount(ap, root, name, namelen, ro_loc, ro_len, myoptions, ctxt);
+			rv = sun_mount(ap, key, name, namelen, ro_loc, ro_len, myoptions, ctxt);
 
 			free(myoptions);
 			if (ro_loc)
@@ -1186,11 +1200,11 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
 		}
 
 		if (ro && rv == 0) {
-			ret = mount_multi_triggers(ap, me, mnt_root, start, mm_base);
+			ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
 			if (ret == -1) {
 				error(ap->logopt, MODPREFIX
 					 "failed to mount offset triggers");
-				cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
+				cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
 				return 1;
 			}
 		} else if (rv <= 0) {
@@ -1206,24 +1220,29 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
 		int loclen = strlen(loc);
 		int namelen = strlen(name);
 
-		mnt_root = name;
-
 		/* name = mm_root + mm_base */
 		/* destination = mm_root + mm_base = name */
 		mm_base = &me->key[start];
 
-		rv = sun_mount(ap, mnt_root, name, namelen, loc, loclen, options, ctxt);
+		rv = sun_mount(ap, name, name, namelen, loc, loclen, options, ctxt);
 		if (rv == 0) {
-			ret = mount_multi_triggers(ap, me->multi, mnt_root, start, mm_base);
+			ret = mount_multi_triggers(ap, me->multi, name, start, mm_base);
 			if (ret == -1) {
 				error(ap->logopt, MODPREFIX
 					 "failed to mount offset triggers");
-				cleanup_multi_triggers(ap, me, mnt_root, start, mm_base);
+				cleanup_multi_triggers(ap, me, name, start, mm_base);
 				return 1;
 			}
 		} else if (rv < 0) {
-			char *mm_root_base = alloca(strlen(mm_root) + strlen(mm_base) + 1);
+			char mm_root_base[PATH_MAX + 1];
+			unsigned int mm_root_base_len = mm_root_len + strlen(mm_base) + 1;
 	
+			if (mm_root_base_len > PATH_MAX) {
+				warn(ap->logopt, MODPREFIX "path too long");
+				cache_delete_offset_list(me->mc, name);
+				return 1;
+			}
+
 			strcpy(mm_root_base, mm_root);
 			strcat(mm_root_base, mm_base);