autofs-5.1.7 - eliminate cache_lookup_offset() usage From: Ian Kent 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 --- 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);