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);