--- /dev/null
+autofs-5.1.7 - Fix option for master read wait
+
+From: Goldwyn Rodrigues <rgoldwyn@suse.de>
+
+The master-wait program option expects a value, and if provided
+automount crashes with the following trace:
+
+#0 __GI_____strtoul_l_internal (nptr=0x0, endptr=0x7fffffffe120, base=0, group=<optimized out>,
+ loc=0x7ffff77a63a0 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
+#1 0x0000555555562c52 in getnumopt ()
+#2 0x0000555555564ec0 in main ()
+
+This is because the options string is not correct and does not expect
+an argument for master-wait (M), which sets optarg to NULL.
+
+Fixes: e68f07f ("autofs-5.1.2 - add master read wait option")
+Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/automount.c | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index fe49740e..0b577909 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -4,6 +4,7 @@
+ - dont use realloc in host exports list processing.
+ - use sprintf() when constructing hosts mapent.
+ - fix mnts_remove_amdmount() uses wrong list.
++- Fix option for master read wait.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index e476f6b2..7fa92877 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -2274,7 +2274,7 @@ int main(int argc, char *argv[])
+ time_t timeout;
+ time_t age = monotonic_time(NULL);
+ struct rlimit rlim;
+- const char *options = "+hp:t:vmdD:SfVrO:l:n:CFUM";
++ const char *options = "+hp:t:vmdD:SfVrO:l:n:CFUM:";
+ static const struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"pid-file", 1, 0, 'p'},
--- /dev/null
+autofs-5.1.7 - add a len field to struct autofs_point
+
+From: Ian Kent <raven@themaw.net>
+
+Add a path length field to struct autofs_point since the path length
+is needed at various times avoiding additional strlen() calls.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/lookup.c | 2 +-
+ daemon/master.c | 1 +
+ include/automount.h | 1 +
+ lib/mounts.c | 6 +++---
+ modules/parse_amd.c | 4 ++--
+ modules/parse_sun.c | 4 ++--
+ 7 files changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 60924b3f..0dae6761 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -30,6 +30,7 @@
+ - rename tree implementation functions.
+ - add some multi-mount macros.
+ - remove unused functions cache_dump_multi() and cache_dump_cache().
++- add a len field to struct autofs_point.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index 8c9a82b5..5116b927 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -843,7 +843,7 @@ static int lookup_amd_instance(struct autofs_point *ap,
+ return NSS_STATUS_UNKNOWN;
+ }
+
+- m_key = malloc(strlen(ap->path) + strlen(MM_ROOT(me)->key) + 2);
++ m_key = malloc(ap->len + strlen(MM_ROOT(me)->key) + 2);
+ if (!m_key) {
+ error(ap->logopt,
+ "failed to allocate storage for search key");
+diff --git a/daemon/master.c b/daemon/master.c
+index da527a61..022fb9dd 100644
+--- a/daemon/master.c
++++ b/daemon/master.c
+@@ -86,6 +86,7 @@ int master_add_autofs_point(struct master_mapent *entry, unsigned logopt,
+ free(ap);
+ return 0;
+ }
++ ap->len = strlen(ap->path);
+ ap->pref = NULL;
+
+ ap->entry = entry;
+diff --git a/include/automount.h b/include/automount.h
+index e917515b..34485859 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -548,6 +548,7 @@ struct kernel_mod_version {
+ struct autofs_point {
+ pthread_t thid;
+ char *path; /* Mount point name */
++ size_t len; /* Length of mount point name */
+ mode_t mode; /* Mount point mode */
+ char *pref; /* amd prefix */
+ int pipefd; /* File descriptor for pipe */
+diff --git a/lib/mounts.c b/lib/mounts.c
+index f6f20fc0..b478ecb4 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1158,7 +1158,7 @@ struct mnt_list *mnts_add_mount(struct autofs_point *ap,
+ if (!mp)
+ goto fail;
+ } else {
+- int len = strlen(ap->path) + strlen(name) + 2;
++ int len = ap->len + strlen(name) + 2;
+
+ mp = malloc(len);
+ if (!mp)
+@@ -2495,9 +2495,9 @@ static int rmdir_path_offset(struct autofs_point *ap, struct mapent *oe)
+ dir = strdup(oe->key);
+
+ if (ap->flags & MOUNT_FLAG_GHOST)
+- split = strlen(ap->path) + strlen(MM_ROOT(oe)->key) + 1;
++ split = ap->len + strlen(MM_ROOT(oe)->key) + 1;
+ else
+- split = strlen(ap->path);
++ split = ap->len;
+
+ dir[split] = '\0';
+ path = &dir[split + 1];
+diff --git a/modules/parse_amd.c b/modules/parse_amd.c
+index d3e8a450..5a9079d6 100644
+--- a/modules/parse_amd.c
++++ b/modules/parse_amd.c
+@@ -147,7 +147,7 @@ static struct substvar *add_lookup_vars(struct autofs_point *ap,
+ struct mapent *me;
+ int len;
+
+- len = strlen(ap->path) + 1 + key_len + 1;
++ len = ap->len + 1 + key_len + 1;
+ if (len > PATH_MAX) {
+ error(ap->logopt, MODPREFIX
+ "error: lookup key is greater than PATH_MAX");
+@@ -1319,7 +1319,7 @@ static int do_host_mount(struct autofs_point *ap, const char *name,
+ char *target;
+ size_t len;
+
+- len = strlen(ap->path) + strlen(entry->rhost) + 2;
++ len = ap->len + strlen(entry->rhost) + 2;
+ target = malloc(len);
+ if (!target) {
+ warn(ap->logopt, MODPREFIX
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index b11c6693..b1f64ca0 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1154,7 +1154,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ mm_root = mm_key;
+ start = strlen(mm_key);
+ } else {
+- start = strlen(ap->path) + strlen(mm_key) + 1;
++ start = ap->len + strlen(mm_key) + 1;
+ mm_root = alloca(start + 3);
+ strcpy(mm_root, ap->path);
+ strcat(mm_root, "/");
+@@ -1477,7 +1477,7 @@ dont_expand:
+ }
+ strcpy(m_root, name);
+ } else {
+- m_root_len = strlen(ap->path) + name_len + 1;
++ m_root_len = ap->len + name_len + 1;
+ m_root = alloca(m_root_len + 1);
+ if (!m_root) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
--- /dev/null
+autofs-5.1.7 - add ext_mount_hash_mutex lock helpers
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: check_return: Calling "pthread_mutex_lock" without checking
+ return value.
+
+Well, I use helpers to do this in many places so can't really disagree.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 26 ++++++++++++++++++++------
+ 2 files changed, 21 insertions(+), 6 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index b1b28888..ff44ac25 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -65,6 +65,7 @@
+ - fix double free in parse_mapent().
+ - refactor lookup_prune_one_cache() a bit.
+ - cater for empty mounts list in mnts_get_expire_list().
++- add ext_mount_hash_mutex lock helpers.
+
+ 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 3996eb5e..c24d1a88 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -788,6 +788,20 @@ char *make_mnt_name_string(char *path)
+ return mnt_name;
+ }
+
++static void ext_mount_hash_mutex_lock(void)
++{
++ int status = pthread_mutex_lock(&ext_mount_hash_mutex);
++ if (status)
++ fatal(status);
++}
++
++static void ext_mount_hash_mutex_unlock(void)
++{
++ int status = pthread_mutex_unlock(&ext_mount_hash_mutex);
++ if (status)
++ fatal(status);
++}
++
+ static struct ext_mount *ext_mount_lookup(const char *mp)
+ {
+ uint32_t hval = hash(mp, HASH_SIZE(ext_mounts_hash));
+@@ -806,7 +820,7 @@ int ext_mount_add(const char *path, const char *umount)
+ struct ext_mount *em;
+ int ret = 0;
+
+- pthread_mutex_lock(&ext_mount_hash_mutex);
++ ext_mount_hash_mutex_lock();
+
+ em = ext_mount_lookup(path);
+ if (em) {
+@@ -840,7 +854,7 @@ int ext_mount_add(const char *path, const char *umount)
+
+ ret = 1;
+ done:
+- pthread_mutex_unlock(&ext_mount_hash_mutex);
++ ext_mount_hash_mutex_unlock();
+ return ret;
+ }
+
+@@ -849,7 +863,7 @@ int ext_mount_remove(const char *path)
+ struct ext_mount *em;
+ int ret = 0;
+
+- pthread_mutex_lock(&ext_mount_hash_mutex);
++ ext_mount_hash_mutex_lock();
+
+ em = ext_mount_lookup(path);
+ if (!em)
+@@ -867,7 +881,7 @@ int ext_mount_remove(const char *path)
+ ret = 1;
+ }
+ done:
+- pthread_mutex_unlock(&ext_mount_hash_mutex);
++ ext_mount_hash_mutex_unlock();
+ return ret;
+ }
+
+@@ -876,13 +890,13 @@ int ext_mount_inuse(const char *path)
+ struct ext_mount *em;
+ int ret = 0;
+
+- pthread_mutex_lock(&ext_mount_hash_mutex);
++ ext_mount_hash_mutex_lock();
+ em = ext_mount_lookup(path);
+ if (!em)
+ goto done;
+ ret = em->ref;
+ done:
+- pthread_mutex_unlock(&ext_mount_hash_mutex);
++ ext_mount_hash_mutex_unlock();
+ return ret;
+ }
+
--- /dev/null
+autofs-5.1.7 - add length check in umount_subtree_mounts()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: fixed_size_dest: You might overrun the 4097-character
+ fixed-size string "key" by copying "me->key" without
+ checking the length.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/automount.c | 5 +++++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 224f58d6..9e385ba9 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -55,6 +55,7 @@
+ - fix possible memory leak in master_parse().
+ - fix possible memory leak in mnts_add_amdmount().
+ - fix double unlock in parse_mount().
++- add length check in umount_subtree_mounts().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 48472d5f..70506d83 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -562,6 +562,11 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+ left++;
+ }
+
++ if (me->len > PATH_MAX) {
++ crit(ap->logopt, "me->key too long for buffer");
++ return 1;
++ }
++
+ strcpy(key, me->key);
+
+ cache_unlock(mc);
--- /dev/null
+autofs-5.1.7 - add mapent tree implementation
+
+From: Ian Kent <raven@themaw.net>
+
+Add a struct mapent basic tree implementation.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/automount.h | 4 ++++
+ include/mounts.h | 8 ++++++++
+ lib/cache.c | 9 ++++++++-
+ lib/mounts.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 71 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 74571570..8841f72f 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -32,6 +32,7 @@
+ - remove unused functions cache_dump_multi() and cache_dump_cache().
+ - add a len field to struct autofs_point.
+ - make tree implementation data independent.
++- add mapent tree implementation.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/automount.h b/include/automount.h
+index 34485859..ebc2007f 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -166,10 +166,14 @@ struct mapent {
+ struct mapent_cache *mc;
+ struct map_source *source;
+ /* Need to know owner if we're a multi-mount */
++ struct tree_node *mm_root;
++ struct tree_node *mm_parent;
++ struct tree_node node;
+ struct mapent *multi;
+ /* Parent nesting point within multi-mount */
+ struct mapent *parent;
+ char *key;
++ size_t len;
+ char *mapent;
+ struct stack *stack;
+ time_t age;
+diff --git a/include/mounts.h b/include/mounts.h
+index 71d29566..fd7c6183 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -66,6 +66,13 @@ struct tree_node {
+ #define MNT_LIST(n) (container_of(n, struct mnt_list, node))
+ #define MNT_LIST_NODE(ptr) ((struct tree_node *) &((struct mnt_list *) ptr)->node)
+
++#define MAPENT(n) (container_of(n, struct mapent, node))
++#define MAPENT_NODE(p) ((struct tree_node *) &((struct mapent *) p)->node)
++#define MAPENT_ROOT(p) ((struct tree_node *) ((struct mapent *) p)->mm_root)
++#define MAPENT_PARENT(p) ((struct tree_node *) ((struct mapent *) p)->mm_parent)
++#define MAPENT_SET_ROOT(p, r) { (((struct mapent *) p)->mm_root = (struct tree_node *) r); }
++#define MAPENT_SET_PARENT(p, n) { (((struct mapent *) p)->mm_parent = (struct tree_node *) n); }
++
+ typedef struct tree_node *(*tree_new_t) (void *ptr);
+ typedef int (*tree_cmp_t) (struct tree_node *n, void *ptr);
+ typedef void (*tree_free_t) (struct tree_node *n);
+@@ -161,6 +168,7 @@ unsigned int mnts_has_mounted_mounts(struct autofs_point *ap);
+ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap);
+ void mnts_put_expire_list(struct list_head *mnts);
+ void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned int flags);
++struct tree_node *tree_mapent_root(struct mapent *me);
+ int unlink_mount_tree(struct autofs_point *ap, const char *mp);
+ void free_mnt_list(struct mnt_list *list);
+ int is_mounted(const char *mp, unsigned int type);
+diff --git a/lib/cache.c b/lib/cache.c
+index 629c4d0a..6dfaeff5 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -546,17 +546,21 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
+ struct mapent *me, *existing = NULL;
+ char *pkey, *pent;
+ u_int32_t hashval = hash(key, mc->size);
++ size_t len;
+
+ me = (struct mapent *) malloc(sizeof(struct mapent));
+ if (!me)
+ return CHE_FAIL;
+
+- pkey = malloc(strlen(key) + 1);
++ len = strlen(key);
++
++ pkey = malloc(len + 1);
+ if (!pkey) {
+ free(me);
+ return CHE_FAIL;
+ }
+ me->key = strcpy(pkey, key);
++ me->len = len;
+
+ if (mapent) {
+ pent = malloc(strlen(mapent) + 1);
+@@ -575,6 +579,9 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
+ me->status = 0;
+ me->mc = mc;
+ me->source = ms;
++ me->mm_root = NULL;
++ me->mm_parent = NULL;
++ INIT_TREE_NODE(&me->node);
+ INIT_LIST_HEAD(&me->ino_index);
+ INIT_LIST_HEAD(&me->multi_list);
+ me->multi = NULL;
+diff --git a/lib/mounts.c b/lib/mounts.c
+index a6d1c5a7..40ebf9cf 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -79,6 +79,17 @@ static struct tree_ops mnt_ops = {
+ };
+ static struct tree_ops *tree_mnt_ops = &mnt_ops;
+
++static struct tree_node *tree_mapent_new(void *ptr);
++static int tree_mapent_cmp(struct tree_node *n, void *ptr);
++static void tree_mapent_free(struct tree_node *n);
++
++static struct tree_ops mapent_ops = {
++ .new = tree_mapent_new,
++ .cmp = tree_mapent_cmp,
++ .free = tree_mapent_free,
++};
++static struct tree_ops *tree_mapent_ops = &mapent_ops;
++
+ unsigned int linux_version_code(void)
+ {
+ struct utsname my_utsname;
+@@ -1431,6 +1442,45 @@ void mnts_put_expire_list(struct list_head *mnts)
+ mnts_hash_mutex_unlock();
+ }
+
++struct tree_node *tree_mapent_root(struct mapent *me)
++{
++ return tree_root(tree_mapent_ops, me);
++}
++
++static struct tree_node *tree_mapent_new(void *ptr)
++{
++ struct tree_node *n = MAPENT_NODE(ptr);
++
++ n->ops = tree_mapent_ops;
++ n->left = NULL;
++ n->right = NULL;
++
++ return n;
++}
++
++static int tree_mapent_cmp(struct tree_node *n, void *ptr)
++{
++ struct mapent *n_me = MAPENT(n);
++ size_t n_me_len = n_me->len;
++ struct mapent *me = ptr;
++ size_t me_len = me->len;
++
++ if (strncmp(me->key, n_me->key, n_me_len) == 0) {
++ if (me_len < n_me_len)
++ return -1;
++ else if (me_len > n_me_len)
++ return 1;
++ }
++ return strcmp(me->key, n_me->key);
++}
++
++static void tree_mapent_free(struct tree_node *n)
++{
++ n->ops = NULL;
++ n->left = NULL;
++ n->right = NULL;
++}
++
+ /* From glibc decode_name() */
+ /* Since the values in a line are separated by spaces, a name cannot
+ * contain a space. Therefore some programs encode spaces in names
--- /dev/null
+autofs-5.1.7 - add missing desciption of null map option
+
+From: Ian Kent <raven@themaw.net>
+
+The description of how the -null master map option behaves is
+mising from auto.master(5).
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ man/auto.master.5.in | 19 +++++++++++++++++++
+ 2 files changed, 20 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index b29d2ed8..f5f0da76 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -76,6 +76,7 @@
+ - eliminate redundant cache lookup in tree_mapent_add_node().
+ - fix hosts map offset order.
+ - fix direct mount deadlock.
++- add missing description of null map option.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/man/auto.master.5.in b/man/auto.master.5.in
+index 72fbfd23..16717015 100644
+--- a/man/auto.master.5.in
++++ b/man/auto.master.5.in
+@@ -265,6 +265,25 @@ accessing /net/myserver will mount exports from myserver on directories below
+ NOTE: mounts done from a hosts map will be mounted with the "nosuid,nodev" options
+ unless overridden by explicitly specifying the "suid", "dev" options in the
+ master map entry.
++.SH BUILTIN MAP \-null
++If "\-null" is given as the map it is used to tell automount(8) to ignore a subsequent
++master map entry with the given path.
++.P
++It can only be used for paths that appear in the master map (or in direct mount maps).
++.P
++An indirect mount map top level mount point path can be nulled. If so no mounts from
++the nulled mount are performed (essentially it isn't mounted).
++.P
++Direct mount map path entries can be nulled. Since they must be present at startup
++they are (notionally) part of the master map.
++.P
++A nulled master map entry path will ignore a single subsequent matching entry. Any
++matching entry following that will be treated as it normally would be. An example
++use of this is allowing local master map entries to override remote ones.
++.P
++NOTE: If a duplicate master map entry path is seen (excluding paths of null entries)
++it will be ignored and noted in the log, that is the first encountered master map
++entry is used unless there is a corresponding null entry.
+ .SH LDAP MAPS
+ If the map type \fBldap\fP is specified the mapname is of the form
+ \fB[//servername/]dn\fP, where the optional \fBservername\fP is
--- /dev/null
+autofs-5.1.7 - add missing free in handle_mounts()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: error[doubleFree]: Memory pointed to by 'root' is freed twice
+
+No it's not, but root isn't freed before the fatal call which crashes
+automount so add a free() before the fatal() call.
+
+It appears Coverity doesn't recognise pthread_exit() as an exit condition.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/automount.c | 2 ++
+ 2 files changed, 3 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 9c3ede45..62a918a9 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -50,6 +50,7 @@
+ - check for offset with no mount location.
+ - remove mounts_mutex.
+ - remove unused variable from get_exports().
++- add missing free in handle_mounts().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 28c4d1ee..48472d5f 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -1922,6 +1922,8 @@ void *handle_mounts(void *arg)
+ status = pthread_mutex_lock(&suc->mutex);
+ if (status) {
+ logerr("failed to lock startup condition mutex!");
++ if (root)
++ free(root);
+ fatal(status);
+ }
+
--- /dev/null
+autofs-5.1.7 - add mount and umount offsets functions
+
+From: Ian Kent <raven@themaw.net>
+
+Add tree_mapent_mount_offsets() and tree_mapent_umount_offsets() to
+the mapent tree handling implementation.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1
+ include/mounts.h | 2
+ lib/mounts.c | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 263 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 0bd6f181..892f7581 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -39,6 +39,7 @@
+ - fix mount_fullpath().
+ - add tree_mapent_cleanup_offsets().
+ - add set_offset_tree_catatonic().
++- add mount and umount offsets functions.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/mounts.h b/include/mounts.h
+index 5441ee0e..e56f80ba 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -172,6 +172,8 @@ struct tree_node *tree_mapent_root(struct mapent *me);
+ int tree_mapent_add_node(struct mapent_cache *mc, const char *base, const char *key);
+ int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key);
+ void tree_mapent_cleanup_offsets(struct mapent *oe);
++int tree_mapent_mount_offsets(struct mapent *oe, int nonstrict);
++int tree_mapent_umount_offsets(struct mapent *oe, int nonstrict);
+ int unlink_mount_tree(struct autofs_point *ap, const char *mp);
+ void free_mnt_list(struct mnt_list *list);
+ int is_mounted(const char *mp, unsigned int type);
+diff --git a/lib/mounts.c b/lib/mounts.c
+index f075a27e..f7c29475 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1692,6 +1692,266 @@ void tree_mapent_cleanup_offsets(struct mapent *oe)
+ }
+ }
+
++static int tree_mapent_rmdir_path_offset(struct autofs_point *ap, struct mapent *oe)
++{
++ struct mapent *mm_root = MAPENT(MAPENT_ROOT(oe));
++ char *dir, *path;
++ unsigned int split;
++ int ret;
++
++ if (ap->type == LKP_DIRECT)
++ return rmdir_path(ap, oe->key, mm_root->dev);
++
++ dir = strdup(oe->key);
++
++ if (ap->flags & MOUNT_FLAG_GHOST)
++ split = ap->len + mm_root->len + 1;
++ else
++ split = ap->len;
++
++ dir[split] = '\0';
++ path = &dir[split + 1];
++
++ if (chdir(dir) == -1) {
++ error(ap->logopt, "failed to chdir to %s", dir);
++ free(dir);
++ return -1;
++ }
++
++ ret = rmdir_path(ap, path, ap->dev);
++
++ free(dir);
++
++ if (chdir("/") == -1)
++ error(ap->logopt, "failed to chdir to /");
++
++ return ret;
++}
++
++static int tree_mapent_mount_offset(struct mapent *oe, void *ptr)
++{
++ struct traverse_subtree_context *ctxt = ptr;
++ struct autofs_point *ap = ctxt->ap;
++ int ret;
++
++ debug(ap->logopt, "mount offset %s", oe->key);
++
++ ret = mount_autofs_offset(ap, oe);
++ if (ret < MOUNT_OFFSET_OK) {
++ if (ret != MOUNT_OFFSET_IGNORE) {
++ warn(ap->logopt, "failed to mount offset");
++ return 0;
++ } else {
++ debug(ap->logopt,
++ "ignoring \"nohide\" trigger %s", oe->key);
++ /*
++ * Ok, so we shouldn't modify the mapent but
++ * mount requests are blocked at a point above
++ * this and expire only uses the mapent key or
++ * holds the cache write lock.
++ */
++ free(oe->mapent);
++ oe->mapent = NULL;
++ }
++ }
++
++ return 1;
++}
++
++static int tree_mapent_umount_offset(struct mapent *oe, void *ptr)
++{
++ struct traverse_subtree_context *ctxt = ptr;
++ struct autofs_point *ap = ctxt->ap;
++ int ret = 1;
++
++ /*
++ * Check for and umount subtree offsets resulting from
++ * nonstrict mount fail.
++ */
++ ret = tree_mapent_umount_offsets(oe, ctxt->strict);
++ if (!ret)
++ return 0;
++
++ /*
++ * If an offset that has an active mount has been removed
++ * from the multi-mount we don't want to attempt to trigger
++ * mounts for it. Obviously this is because it has been
++ * removed, but less obvious is the potential strange
++ * behaviour that can result if we do try and mount it
++ * again after it's been expired. For example, if an NFS
++ * file system is no longer exported and is later umounted
++ * it can be mounted again without any error message but
++ * shows as an empty directory. That's going to confuse
++ * people for sure.
++ *
++ * If the mount cannot be umounted (the process is now
++ * using a stale mount) the offset needs to be invalidated
++ * so no further mounts will be attempted but the offset
++ * cache entry must remain so expires can continue to
++ * attempt to umount it. If the mount can be umounted and
++ * the offset is removed, at least for NFS we will get
++ * ESTALE errors when attempting list the directory.
++ */
++ if (oe->ioctlfd != -1 ||
++ is_mounted(oe->key, MNTS_REAL)) {
++ if (umount_ent(ap, oe->key) &&
++ is_mounted(oe->key, MNTS_REAL)) {
++ debug(ap->logopt,
++ "offset %s has active mount, invalidate",
++ oe->key);
++ /*
++ * Ok, so we shouldn't modify the mapent but
++ * mount requests are blocked at a point above
++ * this and expire only uses the mapent key or
++ * holds the cache write lock.
++ */
++ if (oe->mapent) {
++ free(oe->mapent);
++ oe->mapent = NULL;
++ }
++ return 0;
++ }
++ }
++
++ /* Don't bother if there's noting to umount. */
++ if (!is_mounted(oe->key, MNTS_AUTOFS))
++ goto done;
++
++ debug(ap->logopt, "umount offset %s", oe->key);
++
++ if (umount_autofs_offset(ap, oe)) {
++ warn(ap->logopt, "failed to umount offset");
++ ret = 0;
++ } else {
++ struct stat st;
++ int ret;
++
++ if (!(oe->flags & MOUNT_FLAG_DIR_CREATED))
++ goto done;
++
++ /*
++ * An error due to partial directory removal is
++ * ok so only try and remount the offset if the
++ * actual mount point still exists.
++ */
++ ret = tree_mapent_rmdir_path_offset(ap, oe);
++ if (ret == -1 && !stat(oe->key, &st)) {
++ ret = tree_mapent_mount_offset(oe, ctxt);
++ /* But we did origianlly create this */
++ oe->flags |= MOUNT_FLAG_DIR_CREATED;
++ }
++ }
++done:
++ return ret;
++}
++
++static int tree_mapent_mount_offsets_work(struct tree_node *n, void *ptr)
++{
++ struct traverse_subtree_context *ctxt = ptr;
++ struct mapent *oe = MAPENT(n);
++ struct mapent *mm_root = MAPENT(MAPENT_ROOT(oe));
++ struct autofs_point *ap = ctxt->ap;
++ int ret;
++
++ if (!oe->mapent)
++ return 1;
++
++ /* Stale offset, no longer present in the mapent */
++ if (oe->age != mm_root->age) {
++ /* Best effort */
++ tree_mapent_umount_offset(oe, ctxt);
++ return 1;
++ }
++
++ ret = tree_mapent_mount_offset(oe, ctxt);
++
++ /*
++ * If re-constructing a multi-mount it's necessary to walk
++ * into nested mounts, unlike the usual "mount only what's
++ * needed as you go" behavior.
++ */
++ if (ap->state == ST_READMAP && ap->flags & MOUNT_FLAG_REMOUNT) {
++ if (oe->ioctlfd != -1 ||
++ is_mounted(oe->key, MNTS_REAL))
++ /* Best effort */
++ tree_mapent_mount_offsets(oe, !ctxt->strict);
++ }
++
++ return ret;
++}
++
++int tree_mapent_mount_offsets(struct mapent *oe, int nonstrict)
++{
++ struct tree_node *base = MAPENT_NODE(oe);
++ struct traverse_subtree_context ctxt = {
++ .ap = oe->mc->ap,
++ .base = base,
++ .strict = !nonstrict,
++ };
++
++ return tree_mapent_traverse_subtree(base,
++ tree_mapent_mount_offsets_work, &ctxt);
++}
++
++static int tree_mapent_umount_offsets_work(struct tree_node *n, void *ptr)
++{
++ struct mapent *oe = MAPENT(n);
++
++ return tree_mapent_umount_offset(oe, ptr);
++}
++
++int tree_mapent_umount_offsets(struct mapent *oe, int nonstrict)
++{
++ struct tree_node *base = MAPENT_NODE(oe);
++ struct autofs_point *ap = oe->mc->ap;
++ struct traverse_subtree_context ctxt = {
++ .ap = ap,
++ .base = base,
++ .strict = !nonstrict,
++ };
++ int ret;
++
++ ret = tree_mapent_traverse_subtree(base,
++ tree_mapent_umount_offsets_work, &ctxt);
++ if (ret && tree_mapent_is_root(oe)) {
++ char mp[PATH_MAX + 1];
++
++ /*
++ * The map entry cache stores mapent keys. For indirect
++ * mount maps they are single direcory components so when
++ * one of these keys is the root of a multi-mount the mount
++ * path must be constructed.
++ */
++ if (!mount_fullpath(mp, PATH_MAX, ap->path, oe->key)) {
++ error(ap->logopt, "mount path is too long");
++ return 0;
++ }
++
++ /*
++ * Special case.
++ * If we can't umount the root container then we can't
++ * delete the offsets from the cache and we need to put
++ * the offset triggers back.
++ */
++ if (is_mounted(mp, MNTS_REAL)) {
++ info(ap->logopt, "unmounting dir = %s", mp);
++ if (umount_ent(ap, mp) &&
++ is_mounted(mp, MNTS_REAL)) {
++ if (!tree_mapent_mount_offsets(oe, 1))
++ warn(ap->logopt,
++ "failed to remount offset triggers");
++ return 0;
++ }
++ }
++
++ /* check for mounted mount entry and remove it if found */
++ mnts_remove_mount(mp, MNTS_MOUNTED);
++
++ }
++
++ return ret;
++}
++
+ /* From glibc decode_name() */
+ /* Since the values in a line are separated by spaces, a name cannot
+ * contain a space. Therefore some programs encode spaces in names
--- /dev/null
+autofs-5.1.7 - add set_offset_tree_catatonic()
+
+From: Ian Kent <raven@themaw.net>
+
+Add tree mapent support function set_offset_tree_catatonic().
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 15 +++++++++++++++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 89d4cfa0..0bd6f181 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -38,6 +38,7 @@
+ - add tree_mapent_traverse_subtree().
+ - fix mount_fullpath().
+ - add tree_mapent_cleanup_offsets().
++- add set_offset_tree_catatonic().
+
+ 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 ba573b9a..f075a27e 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2578,6 +2578,21 @@ static int set_mount_catatonic(struct autofs_point *ap, struct mapent *me, int i
+ return 0;
+ }
+
++static int set_offset_tree_catatonic_work(struct tree_node *n, void *ptr)
++{
++ struct mapent *me = MAPENT(n);
++ struct autofs_point *ap = me->mc->ap;
++
++ set_mount_catatonic(ap, me, me->ioctlfd);
++
++ return 1;
++}
++
++static void set_offset_tree_catatonic(struct autofs_point *ap, struct mapent *me)
++{
++ tree_traverse_inorder(MAPENT_ROOT(me), set_offset_tree_catatonic_work, NULL);
++}
++
+ static void set_multi_mount_tree_catatonic(struct autofs_point *ap, struct mapent *me)
+ {
+ if (!list_empty(&me->multi_list)) {
--- /dev/null
+autofs-5.1.7 - add some multi-mount macros
+
+From: Ian Kent <raven@themaw.net>
+
+Add convienience macros IS_MM() to check is a mapent is part of a
+multi-mount, IS_MM_ROOT() to check if a mapent is the root of a
+multi-mount tree and MM_ROOT() to return the multi-mount root mapent.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/automount.c | 14 +++++++-------
+ daemon/direct.c | 6 +++---
+ daemon/lookup.c | 10 +++++-----
+ include/automount.h | 5 +++++
+ lib/cache.c | 30 +++++++++++++++---------------
+ lib/mounts.c | 14 +++++++-------
+ modules/lookup_file.c | 4 ++--
+ modules/lookup_hosts.c | 4 ++--
+ modules/lookup_ldap.c | 4 ++--
+ modules/lookup_nisplus.c | 4 ++--
+ modules/lookup_program.c | 4 ++--
+ modules/lookup_sss.c | 4 ++--
+ modules/lookup_yp.c | 4 ++--
+ modules/parse_sun.c | 12 ++++++------
+ 15 files changed, 63 insertions(+), 57 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 1bf20699..3ba748d7 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -28,6 +28,7 @@
+ - rename path to m_offset in update_offset_entry().
+ - don't pass root to do_mount_autofs_offset().
+ - rename tree implementation functions.
++- add some multi-mount macros.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 62530b6b..f4608fc9 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -545,27 +545,27 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+
+ if (me) {
+ mc = me->mc;
+- is_mm_root = (me->multi == me);
++ is_mm_root = IS_MM_ROOT(me);
+ }
+
+ left = 0;
+
+- if (me && me->multi) {
++ if (me && IS_MM(me)) {
+ char root[PATH_MAX + 1];
+ char key[PATH_MAX + 1];
+ struct mapent *tmp;
+ int status;
+ char *base;
+
+- if (!strchr(me->multi->key, '/'))
++ if (!strchr(MM_ROOT(me)->key, '/'))
+ /* Indirect multi-mount root */
+ /* sprintf okay - if it's mounted, it's
+ * PATH_MAX or less bytes */
+- sprintf(root, "%s/%s", ap->path, me->multi->key);
++ sprintf(root, "%s/%s", ap->path, MM_ROOT(me)->key);
+ else
+- strcpy(root, me->multi->key);
++ strcpy(root, MM_ROOT(me)->key);
+
+- if (is_mm_root)
++ if (IS_MM_ROOT(me))
+ base = NULL;
+ else
+ base = me->key + strlen(root);
+@@ -588,7 +588,7 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+ return 0;
+ }
+
+- if (!left && is_mm_root) {
++ if (!left && IS_MM_ROOT(me)) {
+ status = cache_delete_offset_list(mc, me->key);
+ if (status != CHE_OK) {
+ warn(ap->logopt, "couldn't delete offset list");
+diff --git a/daemon/direct.c b/daemon/direct.c
+index 5c1146a7..3f4f5704 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -686,7 +686,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+ * a mount that has been automatically mounted by
+ * the kernel NFS client.
+ */
+- if (me->multi != me &&
++ if (!IS_MM_ROOT(me) &&
+ is_mounted(me->key, MNTS_REAL))
+ return MOUNT_OFFSET_IGNORE;
+
+@@ -1220,11 +1220,11 @@ static void *do_mount_direct(void *arg)
+ * for direct mount multi-mounts with no real mount at
+ * their base so they will be expired.
+ */
+- if (close_fd && me == me->multi)
++ if (close_fd && IS_MM_ROOT(me))
+ close_fd = 0;
+ if (!close_fd)
+ me->ioctlfd = mt.ioctlfd;
+- if (me->multi && me->multi != me)
++ if (IS_MM(me) && !IS_MM_ROOT(me))
+ flags |= MNTS_OFFSET;
+ }
+ ops->send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index 2fea0c0b..8c9a82b5 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -748,7 +748,7 @@ int lookup_ghost(struct autofs_point *ap, const char *root)
+ goto next;
+
+ /* It's a busy multi-mount - leave till next time */
+- if (list_empty(&me->multi_list))
++ if (IS_MM(me))
+ error(ap->logopt,
+ "invalid key %s", me->key);
+ goto next;
+@@ -838,12 +838,12 @@ static int lookup_amd_instance(struct autofs_point *ap,
+ char *m_key;
+
+ me = cache_lookup_distinct(map->mc, name);
+- if (!me || !me->multi) {
++ if (!me || !IS_MM(me)) {
+ error(ap->logopt, "expected multi mount entry not found");
+ return NSS_STATUS_UNKNOWN;
+ }
+
+- m_key = malloc(strlen(ap->path) + strlen(me->multi->key) + 2);
++ m_key = malloc(strlen(ap->path) + strlen(MM_ROOT(me)->key) + 2);
+ if (!m_key) {
+ error(ap->logopt,
+ "failed to allocate storage for search key");
+@@ -852,7 +852,7 @@ static int lookup_amd_instance(struct autofs_point *ap,
+
+ strcpy(m_key, ap->path);
+ strcat(m_key, "/");
+- strcat(m_key, me->multi->key);
++ strcat(m_key, MM_ROOT(me)->key);
+
+ mnt = mnts_find_amdmount(m_key);
+ free(m_key);
+@@ -1355,7 +1355,7 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti
+ * created on demand and managed by expire and don't
+ * prune the multi-map owner map entry.
+ */
+- if (*me->key == '/' || me->multi == me) {
++ if (*me->key == '/' || IS_MM_ROOT(me)) {
+ me = cache_enumerate(mc, me);
+ continue;
+ }
+diff --git a/include/automount.h b/include/automount.h
+index fa6f5d63..e917515b 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -183,6 +183,11 @@ struct mapent {
+ ino_t ino;
+ };
+
++#define IS_MM(me) (me->multi)
++#define IS_MM_ROOT(me) (me->multi == me)
++#define MM_ROOT(me) (me->multi)
++#define MM_PARENT(me) (me->parent)
++
+ void cache_lock_cleanup(void *arg);
+ void cache_readlock(struct mapent_cache *mc);
+ void cache_writelock(struct mapent_cache *mc);
+diff --git a/lib/cache.c b/lib/cache.c
+index a90bbb1d..1d9f5cc7 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -374,7 +374,7 @@ struct mapent *cache_lookup_first(struct mapent_cache *mc)
+
+ while (me) {
+ /* Multi mount entries are not primary */
+- if (me->multi && me->multi != me) {
++ if (IS_MM(me) && !IS_MM_ROOT(me)) {
+ me = me->next;
+ continue;
+ }
+@@ -397,7 +397,7 @@ struct mapent *cache_lookup_next(struct mapent_cache *mc, struct mapent *me)
+ this = me->next;
+ while (this) {
+ /* Multi mount entries are not primary */
+- if (this->multi && this->multi != this) {
++ if (IS_MM(this) && !IS_MM_ROOT(this)) {
+ this = this->next;
+ continue;
+ }
+@@ -413,7 +413,7 @@ struct mapent *cache_lookup_next(struct mapent_cache *mc, struct mapent *me)
+
+ while (this) {
+ /* Multi mount entries are not primary */
+- if (this->multi && this->multi != this) {
++ if (IS_MM(this) && !IS_MM_ROOT(this)) {
+ this = this->next;
+ continue;
+ }
+@@ -435,7 +435,7 @@ struct mapent *cache_lookup_key_next(struct mapent *me)
+ next = me->next;
+ while (next) {
+ /* Multi mount entries are not primary */
+- if (me->multi && me->multi != me)
++ if (IS_MM(me) && !IS_MM_ROOT(me))
+ continue;
+ if (!strcmp(me->key, next->key))
+ return next;
+@@ -706,7 +706,7 @@ int cache_update_offset(struct mapent_cache *mc, const char *mkey, const char *k
+ me = cache_lookup_distinct(mc, key);
+ if (me) {
+ cache_add_ordered_offset(me, &owner->multi_list);
+- me->multi = owner;
++ MM_ROOT(me) = owner;
+ goto done;
+ }
+ ret = CHE_FAIL;
+@@ -814,14 +814,14 @@ int cache_set_offset_parent(struct mapent_cache *mc, const char *offset)
+ this = cache_lookup_distinct(mc, offset);
+ if (!this)
+ return 0;
+- if (!this->multi)
++ if (!IS_MM(this))
+ return 0;
+
+ parent = get_offset_parent(mc, offset);
+ if (parent)
+ this->parent = parent;
+ else
+- this->parent = this->multi;
++ this->parent = MM_ROOT(this);
+
+ return 1;
+ }
+@@ -879,7 +879,7 @@ int cache_delete_offset(struct mapent_cache *mc, const char *key)
+ return CHE_FAIL;
+
+ if (strcmp(key, me->key) == 0) {
+- if (me->multi && me->multi == me)
++ if (IS_MM(me) && IS_MM_ROOT(me))
+ return CHE_FAIL;
+ mc->hash[hashval] = me->next;
+ goto delete;
+@@ -889,7 +889,7 @@ int cache_delete_offset(struct mapent_cache *mc, const char *key)
+ pred = me;
+ me = me->next;
+ if (strcmp(key, me->key) == 0) {
+- if (me->multi && me->multi == me)
++ if (IS_MM(me) && IS_MM_ROOT(me))
+ return CHE_FAIL;
+ pred->next = me->next;
+ goto delete;
+@@ -927,7 +927,7 @@ int cache_delete(struct mapent_cache *mc, const char *key)
+ me = me->next;
+ if (strcmp(key, me->key) == 0) {
+ struct stack *s = me->stack;
+- if (me->multi && !list_empty(&me->multi_list)) {
++ if (IS_MM(me)) {
+ ret = CHE_FAIL;
+ goto done;
+ }
+@@ -956,7 +956,7 @@ int cache_delete(struct mapent_cache *mc, const char *key)
+
+ if (strcmp(key, me->key) == 0) {
+ struct stack *s = me->stack;
+- if (me->multi && !list_empty(&me->multi_list)) {
++ if (IS_MM(me)) {
+ ret = CHE_FAIL;
+ goto done;
+ }
+@@ -995,7 +995,7 @@ int cache_delete_offset_list(struct mapent_cache *mc, const char *key)
+ return CHE_FAIL;
+
+ /* Not offset list owner */
+- if (me->multi != me)
++ if (!IS_MM_ROOT(me))
+ return CHE_FAIL;
+
+ head = &me->multi_list;
+@@ -1016,13 +1016,13 @@ int cache_delete_offset_list(struct mapent_cache *mc, const char *key)
+ this = list_entry(next, struct mapent, multi_list);
+ next = next->next;
+ list_del_init(&this->multi_list);
+- this->multi = NULL;
++ MM_ROOT(this) = NULL;
+ debug(logopt, "deleting offset key %s", this->key);
+ status = cache_delete(mc, this->key);
+ if (status == CHE_FAIL) {
+ warn(logopt,
+ "failed to delete offset %s", this->key);
+- this->multi = me;
++ MM_ROOT(this) = me;
+ /* TODO: add list back in */
+ remain++;
+ }
+@@ -1030,7 +1030,7 @@ int cache_delete_offset_list(struct mapent_cache *mc, const char *key)
+
+ if (!remain) {
+ list_del_init(&me->multi_list);
+- me->multi = NULL;
++ MM_ROOT(me) = NULL;
+ }
+
+ if (remain)
+diff --git a/lib/mounts.c b/lib/mounts.c
+index f5b905a6..f6f20fc0 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2163,7 +2163,7 @@ int try_remount(struct autofs_point *ap, struct mapent *me, unsigned int type)
+ } else {
+ me->flags &= ~MOUNT_FLAG_DIR_CREATED;
+ if (type == t_offset) {
+- if (!is_mounted(me->parent->key, MNTS_REAL))
++ if (!is_mounted(MM_PARENT(me)->key, MNTS_REAL))
+ me->flags |= MOUNT_FLAG_DIR_CREATED;
+ }
+ }
+@@ -2310,7 +2310,7 @@ void set_indirect_mount_tree_catatonic(struct autofs_point *ap)
+ goto next;
+
+ /* Only need to set offset mounts catatonic */
+- if (me->multi && me->multi == me)
++ if (IS_MM(me) && IS_MM_ROOT(me))
+ set_multi_mount_tree_catatonic(ap, me);
+ next:
+ me = cache_enumerate(mc, me);
+@@ -2330,7 +2330,7 @@ next:
+ void set_direct_mount_tree_catatonic(struct autofs_point *ap, struct mapent *me)
+ {
+ /* Set offset mounts catatonic for this mapent */
+- if (me->multi && me->multi == me)
++ if (IS_MM(me) && IS_MM_ROOT(me))
+ set_multi_mount_tree_catatonic(ap, me);
+ set_mount_catatonic(ap, me, me->ioctlfd);
+ }
+@@ -2490,12 +2490,12 @@ static int rmdir_path_offset(struct autofs_point *ap, struct mapent *oe)
+ int ret;
+
+ if (ap->type == LKP_DIRECT)
+- return rmdir_path(ap, oe->key, oe->multi->dev);
++ return rmdir_path(ap, oe->key, MM_ROOT(oe)->dev);
+
+ dir = strdup(oe->key);
+
+ if (ap->flags & MOUNT_FLAG_GHOST)
+- split = strlen(ap->path) + strlen(oe->multi->key) + 1;
++ split = strlen(ap->path) + strlen(MM_ROOT(oe)->key) + 1;
+ else
+ split = strlen(ap->path);
+
+@@ -2690,7 +2690,7 @@ int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
+ oe = cache_lookup_distinct(me->mc, key);
+ if (!oe || !oe->mapent)
+ goto cont;
+- if (oe->age != me->multi->age) {
++ if (oe->age != MM_ROOT(me)->age) {
+ /* Best effort */
+ do_umount_offset(ap, oe, root, start);
+ goto cont;
+@@ -2724,7 +2724,7 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
+
+ left = do_umount_multi_triggers(ap, me, root, start, base);
+
+- if (!left && me->multi == me) {
++ if (!left && IS_MM_ROOT(me)) {
+ /*
+ * Special case.
+ * If we can't umount the root container then we can't
+diff --git a/modules/lookup_file.c b/modules/lookup_file.c
+index f46a04f0..6afc5587 100644
+--- a/modules/lookup_file.c
++++ b/modules/lookup_file.c
+@@ -1199,8 +1199,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, key);
+- if (me && me->multi)
+- lkp_key = strdup(me->multi->key);
++ if (me && IS_MM(me))
++ lkp_key = strdup(MM_ROOT(me)->key);
+ else if (!ap->pref)
+ lkp_key = strdup(key);
+ else {
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index c1ebb7f6..7e101ddb 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -177,7 +177,7 @@ static void update_hosts_mounts(struct autofs_point *ap,
+ me = cache_lookup_first(mc);
+ while (me) {
+ /* Hosts map entry not yet expanded or already expired */
+- if (!me->multi)
++ if (!IS_MM(me))
+ goto next;
+
+ debug(ap->logopt, MODPREFIX "get list of exports for %s", me->key);
+@@ -200,7 +200,7 @@ next:
+ * Hosts map entry not yet expanded, already expired
+ * or not the base of the tree
+ */
+- if (!me->multi || me->multi != me)
++ if (!IS_MM(me) || !IS_MM_ROOT(me))
+ goto cont;
+
+ debug(ap->logopt, MODPREFIX
+diff --git a/modules/lookup_ldap.c b/modules/lookup_ldap.c
+index 3624dd86..3e43fc01 100644
+--- a/modules/lookup_ldap.c
++++ b/modules/lookup_ldap.c
+@@ -3700,8 +3700,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ if (ap->type == LKP_INDIRECT && *key != '/') {
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, key);
+- if (me && me->multi)
+- lkp_key = strdup(me->multi->key);
++ if (me && IS_MM(me))
++ lkp_key = strdup(MM_ROOT(me)->key);
+ else if (!ap->pref)
+ lkp_key = strdup(key);
+ else {
+diff --git a/modules/lookup_nisplus.c b/modules/lookup_nisplus.c
+index cbd03cdb..6e9a85d1 100644
+--- a/modules/lookup_nisplus.c
++++ b/modules/lookup_nisplus.c
+@@ -722,8 +722,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ if (ap->type == LKP_INDIRECT && *key != '/') {
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, key);
+- if (me && me->multi)
+- lkp_key = strdup(me->multi->key);
++ if (me && IS_MM(me))
++ lkp_key = strdup(MM_ROOT(me)->key);
+ else if (!ap->pref)
+ lkp_key = strdup(key);
+ else {
+diff --git a/modules/lookup_program.c b/modules/lookup_program.c
+index ca209488..70f27545 100644
+--- a/modules/lookup_program.c
++++ b/modules/lookup_program.c
+@@ -646,7 +646,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ name_len, ent, ctxt->parse->context);
+ goto out_free;
+ } else {
+- if (me->multi && me->multi != me) {
++ if (IS_MM(me) && !IS_MM_ROOT(me)) {
+ cache_unlock(mc);
+ warn(ap->logopt, MODPREFIX
+ "unexpected lookup for active multi-mount"
+@@ -657,7 +657,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ cache_writelock(mc);
+ me = cache_lookup_distinct(mc, name);
+ if (me) {
+- if (me->multi)
++ if (IS_MM(me))
+ cache_delete_offset_list(mc, name);
+ cache_delete(mc, name);
+ }
+diff --git a/modules/lookup_sss.c b/modules/lookup_sss.c
+index ccd605af..ad834626 100644
+--- a/modules/lookup_sss.c
++++ b/modules/lookup_sss.c
+@@ -1055,8 +1055,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, key);
+- if (me && me->multi)
+- lkp_key = strdup(me->multi->key);
++ if (me && IS_MM(me))
++ lkp_key = strdup(MM_ROOT(me)->key);
+ else
+ lkp_key = strdup(key);
+ cache_unlock(mc);
+diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
+index 38f75497..8bccb72f 100644
+--- a/modules/lookup_yp.c
++++ b/modules/lookup_yp.c
+@@ -826,8 +826,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ if (ap->type == LKP_INDIRECT && *key != '/') {
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, key);
+- if (me && me->multi)
+- lkp_key = strdup(me->multi->key);
++ if (me && IS_MM(me))
++ lkp_key = strdup(MM_ROOT(me)->key);
+ else if (!ap->pref)
+ lkp_key = strdup(key);
+ else {
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 34d4441e..b11c6693 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1148,7 +1148,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+
+ rv = 0;
+
+- mm_key = me->multi->key;
++ mm_key = MM_ROOT(me)->key;
+
+ if (*mm_key == '/') {
+ mm_root = mm_key;
+@@ -1162,7 +1162,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ }
+ mm_root_len = strlen(mm_root);
+
+- if (me == me->multi) {
++ if (IS_MM_ROOT(me)) {
+ char key[PATH_MAX + 1];
+
+ if (mm_root_len + 1 > PATH_MAX) {
+@@ -1179,7 +1179,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+
+ /* Mount root offset if it exists */
+ ro = cache_lookup_distinct(me->mc, key);
+- if (ro && ro->age == me->multi->age) {
++ if (ro && ro->age == MM_ROOT(me)->age) {
+ char *myoptions, *ro_loc;
+ int namelen = name ? strlen(name) : 0;
+ int ro_len;
+@@ -1350,7 +1350,7 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ if (*name == '/') {
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, name);
+- if (me && me->multi && me->multi != me) {
++ if (me && IS_MM(me) && !IS_MM_ROOT(me)) {
+ cache_unlock(mc);
+ mapent_len = strlen(mapent) + 1;
+ pmapent = malloc(mapent_len + 1);
+@@ -1505,7 +1505,7 @@ dont_expand:
+ }
+
+ /* So we know we're the multi-mount root */
+- if (!me->multi)
++ if (!IS_MM(me))
+ me->multi = me;
+ else {
+ /*
+@@ -1630,7 +1630,7 @@ dont_expand:
+ */
+ cache_readlock(mc);
+ if (*name == '/' &&
+- (me = cache_lookup_distinct(mc, name)) && me->multi) {
++ (me = cache_lookup_distinct(mc, name)) && IS_MM(me)) {
+ cache_unlock(mc);
+ loc = strdup(p);
+ if (!loc) {
--- /dev/null
+autofs-5.1.7 - add tree_mapent_add_node()
+
+From: Ian Kent <raven@themaw.net>
+
+Add function tree_mapent_add_node() to the mapent tree handling
+implementation.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/automount.h | 1 +
+ include/mounts.h | 1 +
+ lib/cache.c | 5 ++---
+ lib/mounts.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 52 insertions(+), 3 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 8841f72f..85730eda 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -33,6 +33,7 @@
+ - add a len field to struct autofs_point.
+ - make tree implementation data independent.
+ - add mapent tree implementation.
++- add tree_mapent_add_node().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/automount.h b/include/automount.h
+index ebc2007f..f6023e27 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -216,6 +216,7 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
+ int cache_update_offset(struct mapent_cache *mc, const char *mkey, const char *key, const char *mapent, time_t age);
+ int cache_lookup_negative(struct mapent *me, const char *key);
+ void cache_update_negative(struct mapent_cache *mc, struct map_source *ms, const char *key, time_t timeout);
++struct mapent *cache_get_offset_parent(struct mapent_cache *mc, const char *key);
+ int cache_set_offset_parent(struct mapent_cache *mc, const char *offset);
+ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age);
+ int cache_delete(struct mapent_cache *mc, const char *key);
+diff --git a/include/mounts.h b/include/mounts.h
+index fd7c6183..a0e60e24 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -169,6 +169,7 @@ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap);
+ void mnts_put_expire_list(struct list_head *mnts);
+ void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned int flags);
+ struct tree_node *tree_mapent_root(struct mapent *me);
++int tree_mapent_add_node(struct mapent_cache *mc, const char *base, const char *key);
+ int unlink_mount_tree(struct autofs_point *ap, const char *mp);
+ void free_mnt_list(struct mnt_list *list);
+ int is_mounted(const char *mp, unsigned int type);
+diff --git a/lib/cache.c b/lib/cache.c
+index 6dfaeff5..7c409a56 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -749,8 +749,7 @@ void cache_update_negative(struct mapent_cache *mc,
+ }
+
+
+-static struct mapent *get_offset_parent(struct mapent_cache *mc,
+- const char *key)
++struct mapent *cache_get_offset_parent(struct mapent_cache *mc, const char *key)
+ {
+ struct mapent *me;
+ char *parent, *tail;
+@@ -796,7 +795,7 @@ int cache_set_offset_parent(struct mapent_cache *mc, const char *offset)
+ if (!IS_MM(this))
+ return 0;
+
+- parent = get_offset_parent(mc, offset);
++ parent = cache_get_offset_parent(mc, offset);
+ if (parent)
+ this->parent = parent;
+ else
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 40ebf9cf..a0bf3d52 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1481,6 +1481,53 @@ static void tree_mapent_free(struct tree_node *n)
+ n->right = NULL;
+ }
+
++int tree_mapent_add_node(struct mapent_cache *mc,
++ const char *root, const char *key)
++{
++ unsigned int logopt = mc->ap->logopt;
++ struct tree_node *tree, *n;
++ struct mapent *base;
++ struct mapent *parent;
++ struct mapent *me;
++
++ base = cache_lookup_distinct(mc, root);
++ if (!base) {
++ error(logopt,
++ "failed to find multi-mount root for key %s", key);
++ return 0;
++ }
++
++ if (MAPENT_ROOT(base) != MAPENT_NODE(base)) {
++ error(logopt,
++ "failed to find multi-mount root of offset tree",
++ key);
++ return 0;
++ }
++ tree = MAPENT_ROOT(base);
++
++ me = cache_lookup_distinct(mc, key);
++ if (!me) {
++ error(logopt,
++ "failed to find key %s of multi-mount", key);
++ return 0;
++ }
++
++ n = tree_add_node(tree, me);
++ if (!n)
++ return 0;
++
++ MAPENT_SET_ROOT(me, tree)
++
++ /* Set the subtree parent */
++ parent = cache_get_offset_parent(mc, key);
++ if (!parent)
++ MAPENT_SET_PARENT(me, tree)
++ else
++ MAPENT_SET_PARENT(me, MAPENT_NODE(parent))
++
++ return 1;
++}
++
+ /* From glibc decode_name() */
+ /* Since the values in a line are separated by spaces, a name cannot
+ * contain a space. Therefore some programs encode spaces in names
--- /dev/null
+autofs-5.1.7 - add tree_mapent_cleanup_offsets()
+
+From: Ian Kent <raven@themaw.net>
+
+Add function tree_mapent_cleanup_offsets() to the mapent tree handling
+implementation.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/mounts.h | 1 +
+ lib/mounts.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 47 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index e2fd532c..89d4cfa0 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -37,6 +37,7 @@
+ - add tree_mapent_delete_offsets().
+ - add tree_mapent_traverse_subtree().
+ - fix mount_fullpath().
++- add tree_mapent_cleanup_offsets().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/mounts.h b/include/mounts.h
+index b5a1193b..5441ee0e 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -171,6 +171,7 @@ void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned
+ struct tree_node *tree_mapent_root(struct mapent *me);
+ int tree_mapent_add_node(struct mapent_cache *mc, const char *base, const char *key);
+ int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key);
++void tree_mapent_cleanup_offsets(struct mapent *oe);
+ int unlink_mount_tree(struct autofs_point *ap, const char *mp);
+ void free_mnt_list(struct mnt_list *list);
+ int is_mounted(const char *mp, unsigned int type);
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 497c28c9..ba573b9a 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1647,6 +1647,51 @@ int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key)
+ return 1;
+ }
+
++static void tree_mapent_umount_mount(struct autofs_point *ap, const char *mp)
++{
++ if (is_mounted(mp, MNTS_ALL)) {
++ if (umount(mp)) {
++ error(ap->logopt, "error recovering from mount fail");
++ error(ap->logopt, "cannot umount %s", mp);
++ }
++ }
++}
++
++static int tree_mapent_cleanup_offsets_work(struct tree_node *n, void *ptr)
++{
++ struct mapent *oe = MAPENT(n);
++ struct traverse_subtree_context *ctxt = ptr;
++
++ tree_mapent_umount_mount(ctxt->ap, oe->key);
++
++ return 1;
++}
++
++void tree_mapent_cleanup_offsets(struct mapent *oe)
++{
++ struct tree_node *base = MAPENT_NODE(oe);
++ struct traverse_subtree_context ctxt = {
++ .ap = oe->mc->ap,
++ .base = base,
++ .strict = 0,
++ };
++ struct autofs_point *ap = oe->mc->ap;
++
++ tree_mapent_traverse_subtree(base, tree_mapent_cleanup_offsets_work, &ctxt);
++
++ /* Cleanup base mount after offsets have been cleaned up */
++ if (*oe->key == '/')
++ tree_mapent_umount_mount(ap, oe->key);
++ else {
++ char mp[PATH_MAX + 1];
++
++ if (!mount_fullpath(mp, PATH_MAX, ap->path, oe->key))
++ error(ap->logopt, "mount path is too long");
++ else
++ tree_mapent_umount_mount(ap, mp);
++ }
++}
++
+ /* From glibc decode_name() */
+ /* Since the values in a line are separated by spaces, a name cannot
+ * contain a space. Therefore some programs encode spaces in names
--- /dev/null
+autofs-5.1.7 - add tree_mapent_delete_offsets()
+
+From: Ian Kent <raven@themaw.net>
+
+Add function tree_mapent_delete_offsets() to the mapent tree handling
+implementation.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/mounts.h | 1 +
+ lib/mounts.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 72 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 85730eda..488b4996 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -34,6 +34,7 @@
+ - make tree implementation data independent.
+ - add mapent tree implementation.
+ - add tree_mapent_add_node().
++- add tree_mapent_delete_offsets().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/mounts.h b/include/mounts.h
+index a0e60e24..b5a1193b 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -170,6 +170,7 @@ void mnts_put_expire_list(struct list_head *mnts);
+ void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned int flags);
+ struct tree_node *tree_mapent_root(struct mapent *me);
+ int tree_mapent_add_node(struct mapent_cache *mc, const char *base, const char *key);
++int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key);
+ int unlink_mount_tree(struct autofs_point *ap, const char *mp);
+ void free_mnt_list(struct mnt_list *list);
+ int is_mounted(const char *mp, unsigned int type);
+diff --git a/lib/mounts.c b/lib/mounts.c
+index a0bf3d52..eb700c79 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1528,6 +1528,76 @@ int tree_mapent_add_node(struct mapent_cache *mc,
+ return 1;
+ }
+
++static int tree_mapent_delete_offset_tree(struct tree_node *root)
++{
++ struct mapent *me = MAPENT(root);
++ unsigned int logopt = me->mc->ap->logopt;
++ int ret = CHE_OK;
++
++ if (root->left) {
++ ret = tree_mapent_delete_offset_tree(root->left);
++ if (!ret)
++ return 0;
++ root->left = NULL;
++ }
++ if (root->right) {
++ ret = tree_mapent_delete_offset_tree(root->right);
++ if (!ret)
++ return 0;
++ root->right = NULL;
++ }
++
++ /* Keep the owner of the multi-mount offset tree and clear
++ * the root and parent when done.
++ */
++ if (MAPENT_ROOT(me) != MAPENT_NODE(me)) {
++ struct tree_node *root = MAPENT_ROOT(me);
++
++ debug(logopt, "deleting offset key %s", me->key);
++
++ /* cache_delete won't delete an active offset */
++ MAPENT_SET_ROOT(me, NULL);
++ ret = cache_delete(me->mc, me->key);
++ if (ret != CHE_OK) {
++ MAPENT_SET_ROOT(me, root);
++ warn(logopt, "failed to delete offset %s", me->key);
++ }
++ } else {
++ MAPENT_SET_ROOT(me, NULL);
++ MAPENT_SET_PARENT(me, NULL);
++ }
++
++ return ret == CHE_OK ? 1 : 0;
++}
++
++int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key)
++{
++ unsigned int logopt = mc->ap->logopt;
++ struct mapent *me;
++
++ me = cache_lookup_distinct(mc, key);
++ if (!me) {
++ error(logopt,
++ "failed to find multi-mount root for key %s", key);
++ return 0;
++ }
++
++ /* Not offset list owner */
++ if (MAPENT_ROOT(me) != MAPENT_NODE(me)) {
++ error(logopt,
++ "mapent for key %s is not multi-mount owner", key);
++ return 0;
++ }
++
++ if (!tree_mapent_delete_offset_tree(MAPENT_ROOT(me))) {
++ error(logopt,
++ "could not delete map entry offsets for key %s", key);
++ return 0;
++ }
++
++ return 1;
++}
++
+ /* From glibc decode_name() */
+ /* Since the values in a line are separated by spaces, a name cannot
+ * contain a space. Therefore some programs encode spaces in names
--- /dev/null
+autofs-5.1.7 - add tree_mapent_traverse_subtree()
+
+From: Ian Kent <raven@themaw.net>
+
+Add function tree_mapent_traverse_subtree() that enumerates offsets from
+a given base node bounded by subtree nesting points.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 48 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 488b4996..390028ac 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -35,6 +35,7 @@
+ - add mapent tree implementation.
+ - add tree_mapent_add_node().
+ - add tree_mapent_delete_offsets().
++- add tree_mapent_traverse_subtree().
+
+ 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 eb700c79..fded4c09 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1528,6 +1528,53 @@ int tree_mapent_add_node(struct mapent_cache *mc,
+ return 1;
+ }
+
++static inline int tree_mapent_is_root(struct mapent *oe)
++{
++ /* Offset "/" is a special case, it's looked up and mounted
++ * seperately because the offset tree may or may not have a
++ * real mount at the base and the triggers inside it need to
++ * be mounted in either case. Also the order requires the
++ * offset at the top of the (sub)tree to be handled after
++ * the traversal.
++ */
++ return (oe->key[oe->len - 1] == '/' ||
++ MAPENT_ROOT(oe) == MAPENT_NODE(oe));
++}
++
++struct traverse_subtree_context {
++ struct autofs_point *ap;
++ struct tree_node *base;
++ int strict;
++};
++
++static int tree_mapent_traverse_subtree(struct tree_node *n, tree_work_fn_t work, void *ptr)
++{
++ struct traverse_subtree_context *ctxt = ptr;
++ struct mapent *oe = MAPENT(n);
++ int ret = 1;
++
++ if (n->left) {
++ ret = tree_mapent_traverse_subtree(n->left, work, ctxt);
++ if (!ret && ctxt->strict)
++ goto done;
++ }
++
++ /* Node is not multi-mount root and is part of current subtree */
++ if (!tree_mapent_is_root(oe) && MAPENT_PARENT(oe) == ctxt->base) {
++ ret = work(n, ctxt);
++ if (!ret && ctxt->strict)
++ goto done;
++ }
++
++ if (n->right) {
++ ret = tree_mapent_traverse_subtree(n->right, work, ctxt);
++ if (!ret && ctxt->strict)
++ goto done;
++ }
++done:
++ return ret;
++}
++
+ static int tree_mapent_delete_offset_tree(struct tree_node *root)
+ {
+ struct mapent *me = MAPENT(root);
--- /dev/null
+autofs-5.1.7 - add xdr_exports()
+
+From: Ian Kent <raven@themaw.net>
+
+Add an xdr_exports() function to get NFS exports from a server.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 3 +
+ include/rpc_subs.h | 14 ++++++
+ lib/rpc_subs.c | 120 +++++++++++++++++++++++++++++++++++-------------
+ modules/lookup_hosts.c | 25 +++-------
+ 4 files changed, 112 insertions(+), 50 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 2c48484b..84050e91 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -1,3 +1,6 @@
++
++- add xdr_exports().
++
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+ - update ldap READMEs and schema definitions.
+diff --git a/include/rpc_subs.h b/include/rpc_subs.h
+index 7ba4b93f..080f19d9 100644
+--- a/include/rpc_subs.h
++++ b/include/rpc_subs.h
+@@ -17,6 +17,7 @@
+ #define _RPC_SUBS_H
+
+ #include <rpc/rpc.h>
++#include <rpc/types.h>
+ #include <rpc/pmap_prot.h>
+ #include <linux/nfs.h>
+ #include <linux/nfs2.h>
+@@ -47,6 +48,17 @@
+
+ #define HOST_ENT_BUF_SIZE 2048
+
++struct hostinfo {
++ char *name;
++ struct hostinfo *next;
++};
++
++struct exportinfo {
++ char *dir;
++ struct hostinfo *hosts;
++ struct exportinfo *next;
++};
++
+ struct conn_info {
+ const char *host;
+ struct sockaddr *addr;
+@@ -71,6 +83,8 @@ int rpc_portmap_getport(struct conn_info *, struct pmap *, unsigned short *);
+ int rpc_ping_proto(struct conn_info *);
+ int rpc_ping(const char *, int, unsigned int, long, long, unsigned int);
+ double monotonic_elapsed(struct timespec, struct timespec);
++struct exportinfo *rpc_get_exports(const char *host, long seconds, long micros, unsigned int option);
++void rpc_exports_free(struct exportinfo *exports);
+ const char *get_addr_string(struct sockaddr *, char *, socklen_t);
+
+ #endif
+diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
+index 643b7687..7b8162b4 100644
+--- a/lib/rpc_subs.c
++++ b/lib/rpc_subs.c
+@@ -41,7 +41,6 @@ const rpcprog_t rpcb_prog = PMAPPROG;
+ const rpcvers_t rpcb_version = PMAPVERS;
+ #endif
+
+-#include "mount.h"
+ #include "rpc_subs.h"
+ #include "replicated.h"
+ #include "automount.h"
+@@ -58,6 +57,17 @@ const rpcvers_t rpcb_version = PMAPVERS;
+
+ #define MAX_NETWORK_LEN 255
+
++#define EXPPATHLEN 1024
++#define EXPNAMELEN 255
++
++#define MOUNTPROG 100005
++
++#define MOUNTVERS 1
++#define MOUNTVERS_NFSV3 3
++#define MOUNTVERS_POSIX 2
++
++#define MOUNTPROC_EXPORT 5
++
+ /* Get numeric value of the n bits starting at position p */
+ #define getbits(x, p, n) ((x >> (p + 1 - n)) & ~(~0 << n))
+
+@@ -1102,7 +1112,55 @@ double monotonic_elapsed(struct timespec start, struct timespec end)
+ return t2 - t1;
+ }
+
+-static int rpc_get_exports_proto(struct conn_info *info, exports *exp)
++static bool_t xdr_host(XDR *xdrs, struct hostinfo *host)
++{
++ if (!xdr_string(xdrs, &host->name, EXPNAMELEN))
++ return FALSE;
++ return TRUE;
++}
++
++static bool_t xdr_hosts(XDR *xdrs, struct hostinfo **hosts)
++{
++ unsigned int size = sizeof(struct hostinfo);
++ char **host;
++
++ host = (char **) hosts;
++ while (1) {
++ if (!xdr_pointer(xdrs, host, size, (xdrproc_t) xdr_host))
++ return FALSE;
++ if (!*host)
++ break;
++ host = (char **) &((struct hostinfo *) *host)->next;
++ }
++ return TRUE;
++}
++
++static bool_t xdr_export(XDR *xdrs, struct exportinfo *export)
++{
++ if (!xdr_string(xdrs, &export->dir, EXPPATHLEN))
++ return FALSE;
++ if (!xdr_hosts(xdrs, &export->hosts))
++ return FALSE;
++ return TRUE;
++}
++
++bool_t xdr_exports(XDR *xdrs, struct exportinfo **exports)
++{
++ unsigned int size = sizeof(struct exportinfo);
++ char **export;
++
++ export = (char **) exports;
++ while (1) {
++ if (!xdr_pointer(xdrs, export, size, (xdrproc_t) xdr_export))
++ return FALSE;
++ if (!*export)
++ break;
++ export = (char **) &((struct exportinfo *) *export)->next;
++ }
++ return TRUE;
++}
++
++static int rpc_get_exports_proto(struct conn_info *info, struct exportinfo **exports)
+ {
+ CLIENT *client;
+ enum clnt_stat status;
+@@ -1133,7 +1191,7 @@ static int rpc_get_exports_proto(struct conn_info *info, exports *exp)
+ while (1) {
+ status = clnt_call(client, MOUNTPROC_EXPORT,
+ (xdrproc_t) xdr_void, NULL,
+- (xdrproc_t) xdr_exports, (caddr_t) exp,
++ (xdrproc_t) xdr_exports, (caddr_t) exports,
+ info->timeout);
+ if (status == RPC_SUCCESS)
+ break;
+@@ -1168,41 +1226,43 @@ static int rpc_get_exports_proto(struct conn_info *info, exports *exp)
+ return 1;
+ }
+
+-static void rpc_export_free(exports item)
++static void rpc_export_free(struct exportinfo *export)
+ {
+- groups grp;
+- groups tmp;
+-
+- if (item->ex_dir)
+- free(item->ex_dir);
+-
+- grp = item->ex_groups;
+- while (grp) {
+- if (grp->gr_name)
+- free(grp->gr_name);
+- tmp = grp;
+- grp = grp->gr_next;
++ struct hostinfo *host, *tmp;
++
++ if (export->dir)
++ free(export->dir);
++
++ host = export->hosts;
++ while (host) {
++ if (host->name)
++ free(host->name);
++ tmp = host;
++ host = host->next;
+ free(tmp);
+ }
+- free(item);
++ free(export);
+ }
+
+-void rpc_exports_free(exports list)
++void rpc_exports_free(struct exportinfo *exports)
+ {
+- exports tmp;
++ struct exportinfo *export, *tmp;
+
+- while (list) {
+- tmp = list;
+- list = list->ex_next;
++ export = exports;
++ while (export) {
++ tmp = export;
++ export = export->next;
+ rpc_export_free(tmp);
+ }
+ return;
+ }
+
+-exports rpc_get_exports(const char *host, long seconds, long micros, unsigned int option)
++struct exportinfo *rpc_get_exports(const char *host,
++ long seconds, long micros,
++ unsigned int option)
+ {
+ struct conn_info info;
+- exports exportlist;
++ struct exportinfo *exports = NULL;
+ struct pmap parms;
+ int status;
+
+@@ -1231,11 +1291,9 @@ exports rpc_get_exports(const char *host, long seconds, long micros, unsigned in
+ if (status < 0)
+ goto try_tcp;
+
+- memset(&exportlist, '\0', sizeof(exportlist));
+-
+- status = rpc_get_exports_proto(&info, &exportlist);
++ status = rpc_get_exports_proto(&info, &exports);
+ if (status)
+- return exportlist;
++ return exports;
+
+ try_tcp:
+ info.proto = IPPROTO_TCP;
+@@ -1246,13 +1304,11 @@ try_tcp:
+ if (status < 0)
+ return NULL;
+
+- memset(&exportlist, '\0', sizeof(exportlist));
+-
+- status = rpc_get_exports_proto(&info, &exportlist);
++ status = rpc_get_exports_proto(&info, &exports);
+ if (!status)
+ return NULL;
+
+- return exportlist;
++ return exports;
+ }
+
+ const char *get_addr_string(struct sockaddr *sa, char *name, socklen_t len)
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index 744062e2..81a4eb18 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -20,14 +20,6 @@
+ #include <sys/stat.h>
+ #include <netdb.h>
+
+-/*
+- * Avoid annoying compiler noise by using an alternate name for
+- * typedef name in mount.h
+- */
+-#define name __dummy_type_name
+-#include "mount.h"
+-#undef name
+-
+ #define MODULE_LOOKUP
+ #include "automount.h"
+ #include "nsswitch.h"
+@@ -43,9 +35,6 @@ struct lookup_context {
+
+ int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+
+-exports rpc_get_exports(const char *host, long seconds, long micros, unsigned int option);
+-void rpc_exports_free(exports list);
+-
+ int lookup_init(const char *mapfmt,
+ int argc, const char *const *argv, void **context)
+ {
+@@ -99,7 +88,7 @@ static char *get_exports(struct autofs_point *ap, const char *host)
+ {
+ char buf[MAX_ERR_BUF];
+ char *mapent;
+- exports exp, this;
++ struct exportinfo *exp, *this;
+
+ debug(ap->logopt, MODPREFIX "fetchng export list for %s", host);
+
+@@ -111,7 +100,7 @@ static char *get_exports(struct autofs_point *ap, const char *host)
+ if (mapent) {
+ int len = strlen(mapent) + 1;
+
+- len += strlen(host) + 2*(strlen(this->ex_dir) + 2) + 3;
++ len += strlen(host) + 2*(strlen(this->dir) + 2) + 3;
+ mapent = realloc(mapent, len);
+ if (!mapent) {
+ char *estr;
+@@ -121,10 +110,10 @@ static char *get_exports(struct autofs_point *ap, const char *host)
+ return NULL;
+ }
+ strcat(mapent, " \"");
+- strcat(mapent, this->ex_dir);
++ strcat(mapent, this->dir);
+ strcat(mapent, "\"");
+ } else {
+- int len = 2*(strlen(this->ex_dir) + 2) + strlen(host) + 3;
++ int len = 2*(strlen(this->dir) + 2) + strlen(host) + 3;
+
+ mapent = malloc(len);
+ if (!mapent) {
+@@ -135,16 +124,16 @@ static char *get_exports(struct autofs_point *ap, const char *host)
+ return NULL;
+ }
+ strcpy(mapent, "\"");
+- strcat(mapent, this->ex_dir);
++ strcat(mapent, this->dir);
+ strcat(mapent, "\"");
+ }
+ strcat(mapent, " \"");
+ strcat(mapent, host);
+ strcat(mapent, ":");
+- strcat(mapent, this->ex_dir);
++ strcat(mapent, this->dir);
+ strcat(mapent, "\"");
+
+- this = this->ex_next;
++ this = this->next;
+ }
+ rpc_exports_free(exp);
+
--- /dev/null
+autofs-5.1.7 - cater for empty mounts list in mnts_get_expire_list()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: var_deref_model: Passing null pointer "tree" to
+ "tree_traverse_inorder", which dereferences it.
+
+This obviously can't happen but deal with it anyway to quiet Coverity.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 6 ++++--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index b79aebc8..b1b28888 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -64,6 +64,7 @@
+ - fix missing lock release in mount_subtree().
+ - fix double free in parse_mapent().
+ - refactor lookup_prune_one_cache() a bit.
++- cater for empty mounts list in mnts_get_expire_list().
+
+ 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 883e3743..3996eb5e 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1445,8 +1445,10 @@ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap)
+ }
+ }
+
+- tree_traverse_inorder(tree, tree_mnt_expire_list_work, mnts);
+- tree_free(tree);
++ if (tree) {
++ tree_traverse_inorder(tree, tree_mnt_expire_list_work, mnts);
++ tree_free(tree);
++ }
+ done:
+ mnts_hash_mutex_unlock();
+ }
--- /dev/null
+autofs-5.1.7 - check for offset with no mount location
+
+From: Ian Kent <raven@themaw.net>
+
+Offsets need to have a mount location, check for it.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 15 ++++++++++++++-
+ 2 files changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index a9209755..42914160 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -47,6 +47,7 @@
+ - pass root length to mount_fullpath().
+ - remove unused function master_submount_list_empty().
+ - move amd mounts removal into lib/mounts.c.
++- check for offset with no mount location.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index b1c2611c..a81d4028 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -801,7 +801,20 @@ update_offset_entry(struct autofs_point *ap,
+
+ memset(m_mapent, 0, MAPENT_MAX_LEN + 1);
+
+- /* Internal hosts map may have loc == NULL */
++ if (!loc || !*loc) {
++ const char *type = ap->entry->maps->type;
++
++ /* If it's not the internal hosts map it must have a
++ * mount location.
++ */
++ if (!type || strcmp(type, "hosts")) {
++ error(ap->logopt,
++ MODPREFIX "syntax error in offset %s -> %s",
++ m_offset, loc);
++ return CHE_FAIL;
++ }
++ }
++
+ if (!*m_offset) {
+ error(ap->logopt,
+ MODPREFIX "syntax error in offset %s -> %s", m_offset, loc);
--- /dev/null
+autofs-5.1.7 - cleanup cache_delete() a little
+
+From: Ian Kent <raven@themaw.net>
+
+There's no reason to use local function storage for the passed in key
+just use the given key.
+
+Also, if there's no hash array entry for the key then there's no cache
+entry so don't return a fail for this case.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/cache.c | 11 +++--------
+ 2 files changed, 4 insertions(+), 8 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 6419052d..e822efec 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -24,6 +24,7 @@
+ - eliminate some strlen calls in offset handling.
+ - don't add offset mounts to mounted mounts table.
+ - reduce umount EBUSY check delay.
++- cleanup cache_delete() a little.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/lib/cache.c b/lib/cache.c
+index 03d0499a..a90bbb1d 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -917,20 +917,15 @@ int cache_delete(struct mapent_cache *mc, const char *key)
+ struct mapent *me = NULL, *pred;
+ u_int32_t hashval = hash(key, mc->size);
+ int ret = CHE_OK;
+- char this[PATH_MAX];
+-
+- strcpy(this, key);
+
+ me = mc->hash[hashval];
+- if (!me) {
+- ret = CHE_FAIL;
++ if (!me)
+ goto done;
+- }
+
+ while (me->next != NULL) {
+ pred = me;
+ me = me->next;
+- if (strcmp(this, me->key) == 0) {
++ if (strcmp(key, me->key) == 0) {
+ struct stack *s = me->stack;
+ if (me->multi && !list_empty(&me->multi_list)) {
+ ret = CHE_FAIL;
+@@ -959,7 +954,7 @@ int cache_delete(struct mapent_cache *mc, const char *key)
+ if (!me)
+ goto done;
+
+- if (strcmp(this, me->key) == 0) {
++ if (strcmp(key, me->key) == 0) {
+ struct stack *s = me->stack;
+ if (me->multi && !list_empty(&me->multi_list)) {
+ ret = CHE_FAIL;
--- /dev/null
+autofs-5.1.7 - don't add offset mounts to mounted mounts table
+
+From: Ian Kent <raven@themaw.net>
+
+Multi-mount offset mounts are added to the mounted mounts table whether
+they have a real mount or not. If there are a large number of offsets
+this can add unnecessary overhead to the mounted mounts table processing.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/direct.c | 14 ++++----------
+ daemon/indirect.c | 4 +++-
+ include/mounts.h | 2 +-
+ lib/mounts.c | 43 +++++++++++--------------------------------
+ 5 files changed, 20 insertions(+), 44 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index cb709773..b144f6aa 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -22,6 +22,7 @@
+ - remove unused mount offset list lock functions.
+ - eliminate count_mounts() from expire_proc_indirect().
+ - eliminate some strlen calls in offset handling.
++- don't add offset mounts to mounted mounts table.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/direct.c b/daemon/direct.c
+index 311a98ba..fbfebbdd 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -605,9 +605,6 @@ force_umount:
+ } else
+ info(ap->logopt, "umounted offset mount %s", me->key);
+
+- if (!rv)
+- mnts_remove_mount(me->key, MNTS_OFFSET);
+-
+ return rv;
+ }
+
+@@ -761,12 +758,6 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+ notify_mount_result(ap, me->key, timeout, str_offset);
+ ops->close(ap->logopt, ioctlfd);
+
+- mnt = mnts_add_mount(ap, me->key, MNTS_OFFSET);
+- if (!mnt)
+- error(ap->logopt,
+- "failed to add offset mount %s to mounted list",
+- me->key);
+-
+ debug(ap->logopt, "mounted trigger %s", me->key);
+
+ return MOUNT_OFFSET_OK;
+@@ -1214,6 +1205,7 @@ static void *do_mount_direct(void *arg)
+ struct mapent *me;
+ struct statfs fs;
+ unsigned int close_fd = 0;
++ unsigned int flags = MNTS_DIRECT|MNTS_MOUNTED;
+
+ sbmnt = mnts_find_submount(mt.name);
+ if (statfs(mt.name, &fs) == -1 ||
+@@ -1232,6 +1224,8 @@ static void *do_mount_direct(void *arg)
+ close_fd = 0;
+ if (!close_fd)
+ me->ioctlfd = mt.ioctlfd;
++ if (me->multi && me->multi != me)
++ flags |= MNTS_OFFSET;
+ }
+ ops->send_ready(ap->logopt, mt.ioctlfd, mt.wait_queue_token);
+ cache_unlock(mt.mc);
+@@ -1240,7 +1234,7 @@ static void *do_mount_direct(void *arg)
+
+ info(ap->logopt, "mounted %s", mt.name);
+
+- mnts_set_mounted_mount(ap, mt.name);
++ mnts_set_mounted_mount(ap, mt.name, flags);
+
+ conditional_alarm_add(ap, ap->exp_runfreq);
+ } else {
+diff --git a/daemon/indirect.c b/daemon/indirect.c
+index b259ebdc..eddcfff7 100644
+--- a/daemon/indirect.c
++++ b/daemon/indirect.c
+@@ -747,12 +747,14 @@ static void *do_mount_indirect(void *arg)
+ status = lookup_nss_mount(ap, NULL, mt.name, mt.len);
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state);
+ if (status) {
++ unsigned int flags = MNTS_INDIRECT|MNTS_MOUNTED;
++
+ ops->send_ready(ap->logopt,
+ ap->ioctlfd, mt.wait_queue_token);
+
+ info(ap->logopt, "mounted %s", buf);
+
+- mnts_set_mounted_mount(ap, mt.name);
++ mnts_set_mounted_mount(ap, mt.name, flags);
+
+ conditional_alarm_add(ap, ap->exp_runfreq);
+ } else {
+diff --git a/include/mounts.h b/include/mounts.h
+index e3022b23..ac480c06 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -131,7 +131,7 @@ struct mnt_list *get_mnt_list(const char *path, int include);
+ unsigned int mnts_has_mounted_mounts(struct autofs_point *ap);
+ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap);
+ void mnts_put_expire_list(struct list_head *mnts);
+-void mnts_set_mounted_mount(struct autofs_point *ap, const char *name);
++void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned int flags);
+ int unlink_mount_tree(struct autofs_point *ap, const char *mp);
+ void free_mnt_list(struct mnt_list *list);
+ int is_mounted(const char *mp, unsigned int type);
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 04fe3d00..25ae2e1d 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1172,7 +1172,7 @@ struct mnt_list *mnts_add_mount(struct autofs_point *ap,
+ this = mnts_get_mount(mp);
+ if (this) {
+ this->flags |= flags;
+- if (list_empty(&this->mount))
++ if ((this->flags & MNTS_MOUNTED) && list_empty(&this->mount))
+ list_add(&this->mount, &ap->mounts);
+ }
+ mnts_hash_mutex_unlock();
+@@ -1193,42 +1193,23 @@ void mnts_remove_mount(const char *mp, unsigned int flags)
+ this = mnts_lookup(mp);
+ if (this && this->flags & flags) {
+ this->flags &= ~flags;
+- if (!(this->flags & (MNTS_OFFSET|MNTS_MOUNTED)))
++ if (!(this->flags & MNTS_MOUNTED))
+ list_del_init(&this->mount);
+ __mnts_put_mount(this);
+ }
+ mnts_hash_mutex_unlock();
+ }
+
+-void mnts_set_mounted_mount(struct autofs_point *ap, const char *name)
++void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned int flags)
+ {
+ struct mnt_list *mnt;
+
+- mnt = mnts_add_mount(ap, name, MNTS_MOUNTED);
++ mnt = mnts_add_mount(ap, name, flags);
+ if (!mnt) {
+ error(ap->logopt,
+ "failed to add mount %s to mounted list", name);
+ return;
+ }
+-
+- /* Offset mount failed but non-strict returns success */
+- if (mnt->flags & MNTS_OFFSET &&
+- !is_mounted(mnt->mp, MNTS_REAL)) {
+- mnt->flags &= ~MNTS_MOUNTED;
+- mnts_put_mount(mnt);
+- }
+-
+- /* Housekeeping.
+- * Set the base type of the mounted mount.
+- * MNTS_AUTOFS and MNTS_OFFSET are set at mount time and
+- * are used during expire.
+- */
+- if (!(mnt->flags & (MNTS_AUTOFS|MNTS_OFFSET))) {
+- if (ap->type == LKP_INDIRECT)
+- mnt->flags |= MNTS_INDIRECT;
+- else
+- mnt->flags |= MNTS_DIRECT;
+- }
+ }
+
+ unsigned int mnts_has_mounted_mounts(struct autofs_point *ap)
+@@ -1947,17 +1928,13 @@ static int do_remount_direct(struct autofs_point *ap,
+
+ ret = lookup_nss_mount(ap, NULL, path, strlen(path));
+ if (ret) {
+- struct mnt_list *mnt;
++ unsigned int flags = MNTS_DIRECT|MNTS_MOUNTED;
+
+ /* If it's an offset mount add a mount reference */
+- if (type == t_offset) {
+- mnt = mnts_add_mount(ap, path, MNTS_OFFSET);
+- if (!mnt)
+- error(ap->logopt,
+- "failed to add mount %s to mounted list", path);
+- }
++ if (type == t_offset)
++ flags |= MNTS_OFFSET;
+
+- mnts_set_mounted_mount(ap, path);
++ mnts_set_mounted_mount(ap, path, flags);
+
+ info(ap->logopt, "re-connected to %s", path);
+
+@@ -2032,7 +2009,9 @@ static int do_remount_indirect(struct autofs_point *ap, const unsigned int type,
+
+ ret = lookup_nss_mount(ap, NULL, de[n]->d_name, len);
+ if (ret) {
+- mnts_set_mounted_mount(ap, buf);
++ unsigned int flags = MNTS_INDIRECT|MNTS_MOUNTED;
++
++ mnts_set_mounted_mount(ap, buf, flags);
+
+ info(ap->logopt, "re-connected to %s", buf);
+
--- /dev/null
+autofs-5.1.7 - don't pass root to do_mount_autofs_offset()
+
+From: Ian Kent <raven@themaw.net>
+
+The root parameter of do_mount_autofs_offset() is used only in a
+debug log message. It doesn't really add any value to debugging
+so remove it.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 9 ++++-----
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 0e9ca94f..2a07bd45 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -26,6 +26,7 @@
+ - reduce umount EBUSY check delay.
+ - cleanup cache_delete() a little.
+ - rename path to m_offset in update_offset_entry().
++- don't pass root to do_mount_autofs_offset().
+
+ 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 25ae2e1d..289500da 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2453,13 +2453,12 @@ out:
+ return rv;
+ }
+
+-static int do_mount_autofs_offset(struct autofs_point *ap,
+- struct mapent *oe, const char *root)
++static int do_mount_autofs_offset(struct autofs_point *ap, struct mapent *oe)
+ {
+ int mounted = 0;
+ int ret;
+
+- debug(ap->logopt, "mount offset %s at %s", oe->key, root);
++ debug(ap->logopt, "mount offset %s", oe->key);
+
+ ret = mount_autofs_offset(ap, oe);
+ if (ret >= MOUNT_OFFSET_OK)
+@@ -2651,7 +2650,7 @@ static int do_umount_offset(struct autofs_point *ap,
+ */
+ ret = rmdir_path_offset(ap, oe);
+ if (ret == -1 && !stat(oe->key, &st)) {
+- ret = do_mount_autofs_offset(ap, oe, root);
++ ret = do_mount_autofs_offset(ap, oe);
+ if (ret)
+ left++;
+ /* But we did origianlly create this */
+@@ -2697,7 +2696,7 @@ int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
+ goto cont;
+ }
+
+- mounted += do_mount_autofs_offset(ap, oe, root);
++ mounted += do_mount_autofs_offset(ap, oe);
+
+ /*
+ * If re-constructing a multi-mount it's necessary to walk
--- /dev/null
+autofs-5.1.7 - dont try umount after stat() ENOENT fail
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: Calling function "umount" that uses "me->key" after a check
+ function. This can cause a time-of-check, time-of-use race
+ condition.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/direct.c | 6 +++++-
+ 2 files changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 7add6c55..c7bc0c39 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -57,6 +57,7 @@
+ - fix double unlock in parse_mount().
+ - add length check in umount_subtree_mounts().
+ - fix flags check in umount_multi().
++- dont try umount after stat() ENOENT fail.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/direct.c b/daemon/direct.c
+index a33f9f91..3bd714e6 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -739,9 +739,13 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+
+ ret = stat(me->key, &st);
+ if (ret == -1) {
++ int save_errno = errno;
++
+ error(ap->logopt,
+ "failed to stat direct mount trigger %s", me->key);
+- goto out_umount;
++ if (save_errno != ENOENT)
++ goto out_umount;
++ goto out_err;
+ }
+
+ ops->open(ap->logopt, &ioctlfd, st.st_dev, me->key);
--- /dev/null
+autofs-5.1.7 - dont use AUTOFS_DEV_IOCTL_CLOSEMOUNT
+
+From: Ian Kent <raven@themaw.net>
+
+Using an ioctl (AUTOFS_DEV_IOCTL_CLOSEMOUNT) to close an autofs mount
+file handle can race with copy_to_user() so the file handle needs to
+be closed using close(2) instead.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/dev-ioctl-lib.c | 10 +---------
+ 2 files changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 06bf24b8..51e7767e 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -68,6 +68,7 @@
+ - add ext_mount_hash_mutex lock helpers.
+ - fix amd section mounts map reload.
+ - fix dandling symlink creation if nis support is not available.
++- dont use AUTOFS_DEV_IOCTL_CLOSEMOUNT.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/lib/dev-ioctl-lib.c b/lib/dev-ioctl-lib.c
+index e7a1b42a..6b549d73 100644
+--- a/lib/dev-ioctl-lib.c
++++ b/lib/dev-ioctl-lib.c
+@@ -404,15 +404,7 @@ err:
+ /* Close */
+ static int dev_ioctl_close(unsigned int logopt, int ioctlfd)
+ {
+- struct autofs_dev_ioctl param;
+-
+- init_autofs_dev_ioctl(¶m);
+- param.ioctlfd = ioctlfd;
+-
+- if (ioctl(ctl.devfd, AUTOFS_DEV_IOCTL_CLOSEMOUNT, ¶m) == -1)
+- return -1;
+-
+- return 0;
++ return close(ioctlfd);
+ }
+
+ static int ioctl_close(unsigned int logopt, int ioctlfd)
--- /dev/null
+autofs-5.1.7 - dont use realloc in host exports list processing
+
+From: Ian Kent <raven@themaw.net>
+
+If a server exports list is very large calling realloc(3) for each
+export is slow. It's better to traverse the exports list twice, once
+to calculate the length of the mapent then allocate the memory and
+traverse the exports list again to construct the mapent.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/lookup_hosts.c | 59 +++++++++++++++++++++---------------------------
+ 2 files changed, 27 insertions(+), 33 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 19af245e..1bd6ac7f 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -1,6 +1,7 @@
+
+ - add xdr_exports().
+ - remove mount.x and rpcgen dependencies.
++- dont use realloc in host exports list processing.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index 81a4eb18..e3ee0ab8 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -89,44 +89,40 @@ static char *get_exports(struct autofs_point *ap, const char *host)
+ char buf[MAX_ERR_BUF];
+ char *mapent;
+ struct exportinfo *exp, *this;
++ size_t hostlen = strlen(host);
++ size_t mapent_len;
+
+ debug(ap->logopt, MODPREFIX "fetchng export list for %s", host);
+
+ exp = rpc_get_exports(host, 10, 0, RPC_CLOSE_NOLINGER);
+
+- mapent = NULL;
+ this = exp;
++ mapent_len = 0;
+ while (this) {
+- if (mapent) {
+- int len = strlen(mapent) + 1;
+-
+- len += strlen(host) + 2*(strlen(this->dir) + 2) + 3;
+- mapent = realloc(mapent, len);
+- if (!mapent) {
+- char *estr;
+- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "malloc: %s", estr);
+- rpc_exports_free(exp);
+- return NULL;
+- }
+- strcat(mapent, " \"");
+- strcat(mapent, this->dir);
+- strcat(mapent, "\"");
+- } else {
+- int len = 2*(strlen(this->dir) + 2) + strlen(host) + 3;
+-
+- mapent = malloc(len);
+- if (!mapent) {
+- char *estr;
+- estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- error(ap->logopt, MODPREFIX "malloc: %s", estr);
+- rpc_exports_free(exp);
+- return NULL;
+- }
++ mapent_len += hostlen + 2*(strlen(this->dir) + 2) + 3;
++ this = this->next;
++ }
++
++ mapent = malloc(mapent_len + 1);
++ if (!mapent) {
++ char *estr;
++ estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ error(ap->logopt, MODPREFIX "malloc: %s", estr);
++ error(ap->logopt, MODPREFIX "exports lookup failed for %s", host);
++ rpc_exports_free(exp);
++ return NULL;
++ }
++ *mapent = 0;
++
++ this = exp;
++ while (this) {
++ if (!*mapent)
+ strcpy(mapent, "\"");
+- strcat(mapent, this->dir);
+- strcat(mapent, "\"");
+- }
++ else
++ strcat(mapent, " \"");
++ strcat(mapent, this->dir);
++ strcat(mapent, "\"");
++
+ strcat(mapent, " \"");
+ strcat(mapent, host);
+ strcat(mapent, ":");
+@@ -137,9 +133,6 @@ static char *get_exports(struct autofs_point *ap, const char *host)
+ }
+ rpc_exports_free(exp);
+
+- if (!mapent)
+- error(ap->logopt, MODPREFIX "exports lookup failed for %s", host);
+-
+ return mapent;
+ }
+
--- /dev/null
+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);
+
--- /dev/null
+autofs-5.1.7 - eliminate clean_stale_multi_triggers()
+
+From: Ian Kent <raven@themaw.net>
+
+Eliminate clean_stale_multi_triggers() by checking for stale offsets at
+the time mount_subtree() is called.
+
+This should result in the same behaviour but eliminate an additional
+seperate traversal of the offset list.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1
+ lib/mounts.c | 209 ++++++++++-----------------------------------------
+ modules/parse_sun.c | 10 --
+ 3 files changed, 43 insertions(+), 177 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 5a3bedc1..b1ce7b69 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -12,6 +12,7 @@
+ - remove redundant variables from mount_autofs_offset().
+ - remove unused parameter form do_mount_autofs_offset().
+ - refactor umount_multi_triggers().
++- eliminate clean_stale_multi_triggers().
+
+ 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 5268ba5b..a9abbebf 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2601,10 +2601,44 @@ static int do_umount_offset(struct autofs_point *ap, struct mapent *oe, const ch
+ oe_base = oe->key + strlen(root);
+ left += do_umount_multi_triggers(ap, oe, root, oe_base);
+
++ /*
++ * If an offset that has an active mount has been removed
++ * from the multi-mount we don't want to attempt to trigger
++ * mounts for it. Obviously this is because it has been
++ * removed, but less obvious is the potential strange
++ * behaviour that can result if we do try and mount it
++ * again after it's been expired. For example, if an NFS
++ * file system is no longer exported and is later umounted
++ * it can be mounted again without any error message but
++ * shows as an empty directory. That's going to confuse
++ * people for sure.
++ *
++ * If the mount cannot be umounted (the process is now
++ * using a stale mount) the offset needs to be invalidated
++ * so no further mounts will be attempted but the offset
++ * cache entry must remain so expires can continue to
++ * attempt to umount it. If the mount can be umounted and
++ * the offset is removed, at least for NFS we will get
++ * ESTALE errors when attempting list the directory.
++ */
+ if (oe->ioctlfd != -1 ||
+ is_mounted(oe->key, MNTS_REAL)) {
+- left++;
+- return left;
++ if (umount_ent(ap, oe->key) &&
++ is_mounted(oe->key, MNTS_REAL)) {
++ debug(ap->logopt,
++ "offset %s has active mount, invalidate",
++ oe->key);
++ /*
++ * Ok, so we shouldn't modify the mapent but
++ * mount requests are blocked at a point above
++ * this and expire only uses the mapent key.
++ */
++ if (oe->mapent) {
++ free(oe->mapent);
++ oe->mapent = NULL;
++ }
++ return ++left;
++ }
+ }
+
+ debug(ap->logopt, "umount offset %s", oe->key);
+@@ -2666,6 +2700,11 @@ int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
+ oe = cache_lookup_distinct(me->mc, key);
+ if (!oe || !oe->mapent)
+ goto cont;
++ if (oe->age != me->multi->age) {
++ /* Best effort */
++ do_umount_offset(ap, oe, root);
++ goto cont;
++ }
+
+ mounted += do_mount_autofs_offset(ap, oe, root);
+
+@@ -2725,169 +2764,3 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
+
+ return left;
+ }
+-
+-int clean_stale_multi_triggers(struct autofs_point *ap,
+- struct mapent *me, char *top, const char *base)
+-{
+- char *root;
+- char mm_top[PATH_MAX + 1];
+- char path[PATH_MAX + 1];
+- 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)
+- root = top;
+- else {
+- if (!strchr(me->multi->key, '/'))
+- /* Indirect multi-mount root */
+- /* sprintf okay - if it's mounted, it's
+- * PATH_MAX or less bytes */
+- sprintf(mm_top, "%s/%s", ap->path, me->multi->key);
+- else
+- strcpy(mm_top, me->multi->key);
+- root = mm_top;
+- }
+-
+- left = 0;
+- start = strlen(root);
+-
+- mm_root = &me->multi->multi_list;
+-
+- if (!base)
+- mm_base = o_root;
+- else
+- mm_base = base;
+-
+- 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;
+- int ret;
+-
+- 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;
+-
+- /* Check for and umount stale subtree offsets */
+- oe_base = oe->key + strlen(root);
+- ret = clean_stale_multi_triggers(ap, oe, root, oe_base);
+- left += ret;
+- if (ret)
+- continue;
+-
+- if (oe->age == age)
+- continue;
+-
+- /*
+- * If an offset that has an active mount has been removed
+- * from the multi-mount we don't want to attempt to trigger
+- * mounts for it. Obviously this is because it has been
+- * removed, but less obvious is the potential strange
+- * behaviour that can result if we do try and mount it
+- * again after it's been expired. For example, if an NFS
+- * file system is no longer exported and is later umounted
+- * it can be mounted again without any error message but
+- * shows as an empty directory. That's going to confuse
+- * people for sure.
+- *
+- * If the mount cannot be umounted (the process is now
+- * using a stale mount) the offset needs to be invalidated
+- * so no further mounts will be attempted but the offset
+- * cache entry must remain so expires can continue to
+- * attempt to umount it. If the mount can be umounted and
+- * the offset is removed, at least for NFS we will get
+- * ESTALE errors when attempting list the directory.
+- */
+- if (oe->ioctlfd != -1 ||
+- is_mounted(oe->key, MNTS_REAL)) {
+- if (umount_ent(ap, oe->key) &&
+- is_mounted(oe->key, MNTS_REAL)) {
+- debug(ap->logopt,
+- "offset %s has active mount, invalidate",
+- oe->key);
+- if (oe->mapent) {
+- free(oe->mapent);
+- oe->mapent = NULL;
+- }
+- left++;
+- continue;
+- }
+- }
+-
+- debug(ap->logopt, "umount offset %s", oe->key);
+-
+- if (umount_autofs_offset(ap, oe)) {
+- warn(ap->logopt, "failed to umount offset %s", key);
+- left++;
+- } else {
+- struct stat st;
+-
+- /* Mount point not ours to delete ? */
+- if (!(oe->flags & MOUNT_FLAG_DIR_CREATED)) {
+- debug(ap->logopt, "delete offset key %s", key);
+- if (cache_delete_offset(oe->mc, key) == CHE_FAIL)
+- error(ap->logopt,
+- "failed to delete offset key %s", key);
+- continue;
+- }
+-
+- /*
+- * An error due to partial directory removal is
+- * ok so only try and remount the offset if the
+- * actual mount point still exists.
+- */
+- ret = rmdir_path_offset(ap, oe);
+- if (ret == -1 && !stat(oe->key, &st)) {
+- ret = do_mount_autofs_offset(ap, oe, root);
+- if (ret) {
+- left++;
+- /* But we did origianlly create this */
+- oe->flags |= MOUNT_FLAG_DIR_CREATED;
+- continue;
+- }
+- /*
+- * Fall through if the trigger can't be mounted
+- * again, since there is no offset there can't
+- * be any mount requests so remove the map
+- * entry from the cache. There's now a dead
+- * offset mount, but what else can we do ....
+- */
+- }
+-
+- debug(ap->logopt, "delete offset key %s", key);
+-
+- if (cache_delete_offset(oe->mc, key) == CHE_FAIL)
+- error(ap->logopt,
+- "failed to delete offset key %s", key);
+- }
+- }
+-
+- return left;
+-}
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index f42af7b7..f4d5125c 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1176,7 +1176,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
+
+ /* Mount root offset if it exists */
+ ro = cache_lookup_distinct(me->mc, key);
+- if (ro) {
++ if (ro && ro->age == me->multi->age) {
+ char *myoptions, *ro_loc;
+ int namelen = name ? strlen(name) : 0;
+ int ro_len;
+@@ -1610,14 +1610,6 @@ dont_expand:
+ free(myoptions);
+ } while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
+
+- /*
+- * We've got the ordered list of multi-mount entries so go
+- * through and remove any stale entries if this is the top
+- * of the multi-mount and set the parent entry of each.
+- */
+- if (me == me->multi)
+- clean_stale_multi_triggers(ap, me, NULL, NULL);
+-
+ rv = mount_subtree(ap, me, name, NULL, options, ctxt);
+
+ cache_multi_unlock(me);
--- /dev/null
+autofs-5.1.7 - eliminate count_mounts() from expire_proc_indirect()
+
+From: Ian Kent <raven@themaw.net>
+
+The count_mounts() function traverses the directory tree under a given
+automount in order to count the number of mounts.
+
+If there are many directories (such as when there is a very large
+number of offset trigger mounts) this can take a long time.
+
+Eliminate the call in expire_proc_indirect() by changing the expire
+ioctl function to better use the expire return from the kernel.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/direct.c | 4 ++--
+ daemon/indirect.c | 10 +++++-----
+ lib/dev-ioctl-lib.c | 21 +++++++++++++--------
+ 4 files changed, 21 insertions(+), 15 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index c5619d2e..0b78eb62 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -20,6 +20,7 @@
+ - pass mapent_cache to update_offset_entry().
+ - fix inconsistent locking in parse_mount().
+ - remove unused mount offset list lock functions.
++- eliminate count_mounts() from expire_proc_indirect().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/direct.c b/daemon/direct.c
+index c41c680f..311a98ba 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -884,7 +884,7 @@ cont:
+ ioctlfd = me->ioctlfd;
+
+ ret = ops->expire(ap->logopt, ioctlfd, mnt->mp, how);
+- if (ret) {
++ if (ret == 1) {
+ left++;
+ pthread_setcancelstate(cur_state, NULL);
+ continue;
+@@ -910,7 +910,7 @@ cont:
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+ ret = ops->expire(ap->logopt, ioctlfd, mnt->mp, how);
+- if (ret)
++ if (ret == 1)
+ left++;
+ pthread_setcancelstate(cur_state, NULL);
+ }
+diff --git a/daemon/indirect.c b/daemon/indirect.c
+index 65cfe4e3..b259ebdc 100644
+--- a/daemon/indirect.c
++++ b/daemon/indirect.c
+@@ -358,7 +358,6 @@ void *expire_proc_indirect(void *arg)
+ struct expire_args ec;
+ unsigned int how;
+ int offsets, submnts, count;
+- int retries;
+ int ioctlfd, cur_state;
+ int status, ret, left;
+
+@@ -496,7 +495,7 @@ void *expire_proc_indirect(void *arg)
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+ ret = ops->expire(ap->logopt, ioctlfd, mnt->mp, how);
+- if (ret)
++ if (ret == 1)
+ left++;
+ pthread_setcancelstate(cur_state, NULL);
+ }
+@@ -507,10 +506,11 @@ void *expire_proc_indirect(void *arg)
+ * so we need to umount or unlink them here.
+ */
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+- retries = (count_mounts(ap, ap->path, ap->dev) + 1);
+- while (retries--) {
++ while (1) {
+ ret = ops->expire(ap->logopt, ap->ioctlfd, ap->path, how);
+- if (ret)
++ if (ret != 0 && errno == EAGAIN)
++ break;
++ if (ret == 1)
+ left++;
+ }
+ pthread_setcancelstate(cur_state, NULL);
+diff --git a/lib/dev-ioctl-lib.c b/lib/dev-ioctl-lib.c
+index 7040c3da..e7a1b42a 100644
+--- a/lib/dev-ioctl-lib.c
++++ b/lib/dev-ioctl-lib.c
+@@ -650,6 +650,7 @@ static int expire(unsigned int logopt,
+ {
+ int ret, retries = EXPIRE_RETRIES;
+ unsigned int may_umount;
++ int save_errno = 0;
+
+ while (retries--) {
+ struct timespec tm = {0, 100000000};
+@@ -657,9 +658,11 @@ static int expire(unsigned int logopt,
+ /* Ggenerate expire message for the mount. */
+ ret = ioctl(fd, cmd, arg);
+ if (ret == -1) {
++ save_errno = errno;
++
+ /* Mount has gone away */
+ if (errno == EBADF || errno == EINVAL)
+- return 0;
++ break;
+
+ /*
+ * Other than EAGAIN is an expire error so continue.
+@@ -673,14 +676,16 @@ static int expire(unsigned int logopt,
+ nanosleep(&tm, NULL);
+ }
+
+- may_umount = 0;
+- if (ctl.ops->askumount(logopt, ioctlfd, &may_umount))
+- return -1;
+-
+- if (!may_umount)
+- return 1;
++ if (!ret || save_errno == EAGAIN) {
++ may_umount = 0;
++ if (!ctl.ops->askumount(logopt, ioctlfd, &may_umount)) {
++ if (!may_umount)
++ ret = 1;
++ }
++ }
++ errno = save_errno;
+
+- return 0;
++ return ret;
+ }
+
+ static int dev_ioctl_expire(unsigned int logopt,
--- /dev/null
+autofs-5.1.7 - eliminate redundant cache lookup in tree_mapent_add_node()
+
+From: Ian Kent <raven@themaw.net>
+
+Since we need to create the offset tree after adding the offset entries
+to the mapent cache (from a list.h list) there's no need to lookup the
+mapent in tree_mapent_add_node() and validate it. Just use it directly
+when calling tree_mapent_add_node() and avoid a cache lookup on every
+node addition.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/mounts.h | 2 +-
+ lib/mounts.c | 13 ++-----------
+ modules/parse_sun.c | 2 +-
+ 4 files changed, 5 insertions(+), 13 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 5a767360..81b6ce6a 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -73,6 +73,7 @@
+ - fix amd hosts mount expire.
+ - fix offset entries order.
+ - use mapent tree root for tree_mapent_add_node().
++- eliminate redundant cache lookup in tree_mapent_add_node().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/mounts.h b/include/mounts.h
+index f7768ce5..5a7a0b89 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -170,7 +170,7 @@ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap);
+ void mnts_put_expire_list(struct list_head *mnts);
+ void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned int flags);
+ struct tree_node *tree_mapent_root(struct mapent *me);
+-int tree_mapent_add_node(struct mapent_cache *mc, struct tree_node *root, const char *key);
++int tree_mapent_add_node(struct mapent_cache *mc, struct tree_node *root, struct mapent *me);
+ int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key);
+ void tree_mapent_cleanup_offsets(struct mapent *oe);
+ int tree_mapent_mount_offsets(struct mapent *oe, int nonstrict);
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 9ec547ea..6b24a6c2 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1519,19 +1519,10 @@ static void tree_mapent_free(struct tree_node *n)
+ }
+
+ int tree_mapent_add_node(struct mapent_cache *mc,
+- struct tree_node *root, const char *key)
++ struct tree_node *root, struct mapent *me)
+ {
+- unsigned int logopt = mc->ap->logopt;
+ struct tree_node *n;
+ struct mapent *parent;
+- struct mapent *me;
+-
+- me = cache_lookup_distinct(mc, key);
+- if (!me) {
+- error(logopt,
+- "failed to find key %s of multi-mount", key);
+- return 0;
+- }
+
+ n = tree_add_node(root, me);
+ if (!n)
+@@ -1540,7 +1531,7 @@ int tree_mapent_add_node(struct mapent_cache *mc,
+ MAPENT_SET_ROOT(me, root)
+
+ /* Set the subtree parent */
+- parent = cache_get_offset_parent(mc, key);
++ parent = cache_get_offset_parent(mc, me->key);
+ if (!parent)
+ MAPENT_SET_PARENT(me, root)
+ else
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index c75bcc8e..12844a30 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1546,7 +1546,7 @@ dont_expand:
+ return 1;
+ }
+ list_for_each_entry_safe(oe, tmp, &offsets, work) {
+- if (!tree_mapent_add_node(mc, MAPENT_ROOT(me), oe->key))
++ if (!tree_mapent_add_node(mc, MAPENT_ROOT(me), oe))
+ error(ap->logopt, "failed to add offset %s to tree", oe->key);
+ list_del_init(&oe->work);
+ }
--- /dev/null
+autofs-5.1.7 - eliminate some more alloca usage
+
+From: Ian Kent <raven@themaw.net>
+
+Quite a bit of the alloca(3) usage has been eliminated over time.
+Use malloc(3) for some more cases that might need to allocate a largish
+amount of storage.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/lookup_program.c | 11 ++++++++++-
+ modules/lookup_yp.c | 22 +++++++++++++++++++---
+ modules/parse_sun.c | 18 ++++++++++++++----
+ modules/replicated.c | 19 ++++++-------------
+ 5 files changed, 50 insertions(+), 21 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 8d050552..2b7cfaa0 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -79,6 +79,7 @@
+ - add missing description of null map option.
+ - fix nonstrict offset mount fail handling.
+ - fix concat_options() error handling.
++- eliminate some more alloca usage.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/lookup_program.c b/modules/lookup_program.c
+index 6cab52c8..028580e5 100644
+--- a/modules/lookup_program.c
++++ b/modules/lookup_program.c
+@@ -636,7 +636,14 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ char *ent = NULL;
+
+ if (me->mapent) {
+- ent = alloca(strlen(me->mapent) + 1);
++ ent = malloc(strlen(me->mapent) + 1);
++ if (!ent) {
++ char buf[MAX_ERR_BUF];
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ error(ap->logopt, MODPREFIX "malloc: %s", estr);
++ cache_unlock(mc);
++ goto out_free;
++ }
+ strcpy(ent, me->mapent);
+ }
+ cache_unlock(mc);
+@@ -644,6 +651,8 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ ap->entry->current = source;
+ ret = ctxt->parse->parse_mount(ap, name,
+ name_len, ent, ctxt->parse->context);
++ if (ent)
++ free(ent);
+ goto out_free;
+ } else {
+ if (IS_MM(me) && !IS_MM_ROOT(me)) {
+diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
+index 8bccb72f..d2a4b5a5 100644
+--- a/modules/lookup_yp.c
++++ b/modules/lookup_yp.c
+@@ -254,7 +254,7 @@ int yp_all_master_callback(int status, char *ypkey, int ypkeylen,
+
+ len = ypkeylen + 1 + vallen + 2;
+
+- buffer = alloca(len);
++ buffer = malloc(len);
+ if (!buffer) {
+ error(logopt, MODPREFIX "could not malloc parse buffer");
+ return 0;
+@@ -267,6 +267,8 @@ int yp_all_master_callback(int status, char *ypkey, int ypkeylen,
+
+ master_parse_entry(buffer, timeout, logging, age);
+
++ free(buffer);
++
+ return 0;
+ }
+
+@@ -368,7 +370,12 @@ int yp_all_callback(int status, char *ypkey, int ypkeylen,
+ return 0;
+ }
+
+- mapent = alloca(vallen + 1);
++ mapent = malloc(vallen + 1);
++ if (!mapent) {
++ error(logopt, MODPREFIX "could not malloc mapent buffer");
++ free(key);
++ return 0;
++ }
+ strncpy(mapent, val, vallen);
+ *(mapent + vallen) = '\0';
+
+@@ -377,6 +384,7 @@ int yp_all_callback(int status, char *ypkey, int ypkeylen,
+ cache_unlock(mc);
+
+ free(key);
++ free(mapent);
+
+ if (ret == CHE_FAIL)
+ return -1;
+@@ -904,7 +912,14 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ }
+ if (me && (me->source == source || *me->key == '/')) {
+ mapent_len = strlen(me->mapent);
+- mapent = alloca(mapent_len + 1);
++ mapent = malloc(mapent_len + 1);
++ if (!mapent) {
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ error(ap->logopt, MODPREFIX "malloc: %s", estr);
++ cache_unlock(mc);
++ free(lkp_key);
++ return NSS_STATUS_TRYAGAIN;
++ }
+ strcpy(mapent, me->mapent);
+ }
+ }
+@@ -929,6 +944,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+
+ ret = ctxt->parse->parse_mount(ap, key, key_len,
+ mapent, ctxt->parse->context);
++ free(mapent);
+ if (ret) {
+ /* Don't update negative cache when re-connecting */
+ if (ap->flags & MOUNT_FLAG_REMOUNT)
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 9190165d..d9ac0c94 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -668,9 +668,16 @@ static int sun_mount(struct autofs_point *ap, const char *root,
+ }
+ }
+
++ what = malloc(loclen + 1);
++ if (!what) {
++ char buf[MAX_ERR_BUF];
++ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
++ error(ap->logopt, MODPREFIX "malloc: %s", estr);
++ return 1;
++ }
++
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+ if (!strcmp(fstype, "nfs") || !strcmp(fstype, "nfs4")) {
+- what = alloca(loclen + 1);
+ memcpy(what, loc, loclen);
+ what[loclen] = '\0';
+
+@@ -706,10 +713,10 @@ static int sun_mount(struct autofs_point *ap, const char *root,
+ rv = mount_nfs->mount_mount(ap, root, name, namelen,
+ what, fstype, options, mount_nfs->context);
+ } else {
+- if (!loclen)
++ if (!loclen) {
++ free(what);
+ what = NULL;
+- else {
+- what = alloca(loclen + 1);
++ } else {
+ if (*loc == ':') {
+ loclen--;
+ memcpy(what, loc + 1, loclen);
+@@ -728,6 +735,9 @@ static int sun_mount(struct autofs_point *ap, const char *root,
+ /* Generic mount routine */
+ rv = do_mount(ap, root, name, namelen, what, fstype, options);
+ }
++ if (what)
++ free(what);
++
+ pthread_setcancelstate(cur_state, NULL);
+
+ if (nonstrict && rv)
+diff --git a/modules/replicated.c b/modules/replicated.c
+index 03d4ba1e..ffaf519f 100644
+--- a/modules/replicated.c
++++ b/modules/replicated.c
+@@ -1041,25 +1041,18 @@ done:
+ return ret;
+ }
+
+-static int add_path(struct host *hosts, const char *path, int len)
++static int add_path(struct host *hosts, const char *path)
+ {
+ struct host *this;
+- char *tmp, *tmp2;
+-
+- tmp = alloca(len + 1);
+- if (!tmp)
+- return 0;
+-
+- strncpy(tmp, path, len);
+- tmp[len] = '\0';
++ char *tmp;
+
+ this = hosts;
+ while (this) {
+ if (!this->path) {
+- tmp2 = strdup(tmp);
+- if (!tmp2)
++ tmp = strdup(path);
++ if (!tmp)
+ return 0;
+- this->path = tmp2;
++ this->path = tmp;
+ }
+ this = this->next;
+ }
+@@ -1188,7 +1181,7 @@ int parse_location(unsigned logopt, struct host **hosts,
+ }
+ }
+
+- if (!add_path(*hosts, path, strlen(path))) {
++ if (!add_path(*hosts, path)) {
+ free_host_list(hosts);
+ free(str);
+ return 0;
--- /dev/null
+autofs-5.1.7 - eliminate some strlen calls in offset handling
+
+From: Ian Kent <raven@themaw.net>
+
+There are a number of places where strlen() is used to re-calculate
+the length of a string. Eliminate some of those by calculating the
+length once and passing it to the functions that do the re-calculation.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 30 +++++++++++++++++-------------
+ 2 files changed, 18 insertions(+), 13 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 0b78eb62..cb709773 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -21,6 +21,7 @@
+ - fix inconsistent locking in parse_mount().
+ - remove unused mount offset list lock functions.
+ - eliminate count_mounts() from expire_proc_indirect().
++- eliminate some strlen calls in offset handling.
+
+ 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 0fcd4087..04fe3d00 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2540,10 +2540,12 @@ static int rmdir_path_offset(struct autofs_point *ap, struct mapent *oe)
+ return ret;
+ }
+
+-static int do_umount_offset(struct autofs_point *ap, struct mapent *oe, const char *root);
++static int do_umount_offset(struct autofs_point *ap,
++ struct mapent *oe, const char *root, int start);
+
+ static int do_umount_multi_triggers(struct autofs_point *ap,
+- struct mapent *me, const char *root, const char *base)
++ struct mapent *me, const char *root,
++ int start, const char *base)
+ {
+ char path[PATH_MAX + 1];
+ char *offset;
+@@ -2551,12 +2553,11 @@ static int do_umount_multi_triggers(struct autofs_point *ap,
+ struct list_head *mm_root, *pos;
+ const char o_root[] = "/";
+ const char *mm_base;
+- int left, start;
++ int left;
+ unsigned int root_len;
+ unsigned int mm_base_len;
+
+ left = 0;
+- start = strlen(root);
+
+ mm_root = &me->multi->multi_list;
+
+@@ -2592,13 +2593,14 @@ static int do_umount_multi_triggers(struct autofs_point *ap,
+ if (!oe || (strlen(oe->key) - start) == 1)
+ continue;
+
+- left += do_umount_offset(ap, oe, root);
++ left += do_umount_offset(ap, oe, root, start);
+ }
+
+ return left;
+ }
+
+-static int do_umount_offset(struct autofs_point *ap, struct mapent *oe, const char *root)
++static int do_umount_offset(struct autofs_point *ap,
++ struct mapent *oe, const char *root, int start)
+ {
+ char *oe_base;
+ int left = 0;
+@@ -2607,8 +2609,8 @@ static int do_umount_offset(struct autofs_point *ap, struct mapent *oe, const ch
+ * Check for and umount subtree offsets resulting from
+ * nonstrict mount fail.
+ */
+- oe_base = oe->key + strlen(root);
+- left += do_umount_multi_triggers(ap, oe, root, oe_base);
++ oe_base = oe->key + start;
++ left += do_umount_multi_triggers(ap, oe, root, start, oe_base);
+
+ /*
+ * If an offset that has an active mount has been removed
+@@ -2712,7 +2714,7 @@ int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
+ goto cont;
+ if (oe->age != me->multi->age) {
+ /* Best effort */
+- do_umount_offset(ap, oe, root);
++ do_umount_offset(ap, oe, root, start);
+ goto cont;
+ }
+
+@@ -2726,7 +2728,7 @@ 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))
+- mount_multi_triggers(ap, oe, key, strlen(key), base);
++ mount_multi_triggers(ap, oe, key, key_len, base);
+ }
+ cont:
+ offset = cache_get_offset(base,
+@@ -2738,9 +2740,11 @@ cont:
+
+ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root, const char *base)
+ {
+- int left;
++ int left, start;
++
++ start = strlen(root);
+
+- left = do_umount_multi_triggers(ap, me, root, base);
++ left = do_umount_multi_triggers(ap, me, root, start, base);
+
+ if (!left && me->multi == me) {
+ /*
+@@ -2753,7 +2757,7 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
+ info(ap->logopt, "unmounting dir = %s", root);
+ if (umount_ent(ap, root) &&
+ is_mounted(root, MNTS_REAL)) {
+- if (mount_multi_triggers(ap, me, root, strlen(root), "/") < 0)
++ if (mount_multi_triggers(ap, me, root, start, "/") < 0)
+ warn(ap->logopt,
+ "failed to remount offset triggers");
+ return ++left;
--- /dev/null
+autofs-5.1.7 - fix amd hosts mount expire
+
+From: Ian Kent <raven@themaw.net>
+
+When swicthing to use the mnt_list to track mounts for expire, if the
+amd hosts map entry name is for the host short name, the amd mount
+entry for the short name gets removed. This causes a subsequent mounts
+for host exports to fail.
+
+What should happen is the short name amd entry not be removed and a
+mounted mount entry for the symlinked FQDN mount added so it expires.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_amd.c | 9 +++++----
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 698cc27a..94eb6a2c 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -70,6 +70,7 @@
+ - fix dandling symlink creation if nis support is not available.
+ - dont use AUTOFS_DEV_IOCTL_CLOSEMOUNT.
+ - fix lookup_prune_one_cache() refactoring change.
++- fix amd hosts mount expire.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_amd.c b/modules/parse_amd.c
+index 64c1ce63..163174cd 100644
+--- a/modules/parse_amd.c
++++ b/modules/parse_amd.c
+@@ -2341,12 +2341,13 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ if (!rv) {
+ /*
+ * If entry->path doesn't match the mnt->mp then
+- * the mount point path has changed and a new
+- * mnt_list entry added for it, so remove the
+- * original.
++ * it's a "host" map and the mount point path is
++ * different to the lookup name. Add a new mnt_list
++ * entry so that both the symlinked name and the
++ * mount expire.
+ */
+ if (strcmp(this->path, mnt->mp))
+- mnts_remove_amdmount(this->path);
++ mnts_add_mount(ap, this->rhost, MNTS_INDIRECT|MNTS_MOUNTED);
+ break;
+ }
+ /* Not mounted, remove the mnt_list entry from amdmount list */
--- /dev/null
+autofs-5.1.7 - fix amd section mounts map reload
+
+From: Ian Kent <raven@themaw.net>
+
+Master map section mounts (amd format mounts) get umounted on reload.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/master.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 81 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index ff44ac25..ddc07912 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -66,6 +66,7 @@
+ - refactor lookup_prune_one_cache() a bit.
+ - cater for empty mounts list in mnts_get_expire_list().
+ - add ext_mount_hash_mutex lock helpers.
++- fix amd section mounts map reload.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/master.c b/daemon/master.c
+index 84743f80..f99359c5 100644
+--- a/daemon/master.c
++++ b/daemon/master.c
+@@ -882,6 +882,83 @@ struct master *master_new(const char *name, unsigned int timeout, unsigned int f
+ return master;
+ }
+
++static void master_update_amd_mount_section_mount(struct master *master,
++ const char *path, time_t age)
++{
++ unsigned int m_logopt = master->logopt;
++ struct master_mapent *entry;
++ struct map_source *source;
++ unsigned int loglevel;
++ unsigned int logopt;
++ unsigned int flags;
++ time_t timeout;
++ char *map;
++ char *opts;
++
++ entry = master_find_mapent(master, path);
++ if (!entry)
++ return;
++
++ map = conf_amd_get_map_name(path);
++ if (!map)
++ return;
++
++ /* amd top level mounts have only one map */
++ source = entry->maps;
++ if (strcmp(source->name, map) != 0) {
++ struct map_source *new;
++ char *type;
++ char *argv[2];
++
++ type = conf_amd_get_map_type(path);
++ argv[0] = map;
++ argv[1] = NULL;
++
++ new = master_add_map_source(entry, type, "amd",
++ age, 1, (const char **) argv);
++ if (!new) {
++ error(m_logopt,
++ "failed to add source for amd section mount %s",
++ path);
++ if (type)
++ free(type);
++ goto out;
++ }
++ master_free_map_source(source, 0);
++ entry->maps = new;
++ source = new;
++ if (type)
++ free(type);
++ }
++
++ loglevel = conf_amd_get_log_options();
++ logopt = m_logopt;
++ if (loglevel <= LOG_DEBUG && loglevel > LOG_INFO)
++ logopt = LOGOPT_DEBUG;
++ else if (loglevel <= LOG_INFO && loglevel > LOG_ERR)
++ logopt = LOGOPT_VERBOSE;
++
++ flags = conf_amd_get_flags(path);
++ if (flags & CONF_BROWSABLE_DIRS)
++ entry->ap->flags |= MOUNT_FLAG_GHOST;
++
++ opts = conf_amd_get_map_options(path);
++ if (opts) {
++ if (strstr(opts, "cache:=all"))
++ entry->ap->flags |= MOUNT_FLAG_AMD_CACHE_ALL;
++ free(opts);
++ }
++
++ entry->ap->logopt = logopt;
++
++ timeout = conf_amd_get_dismount_interval(path);
++ set_exp_timeout(entry->ap, source, timeout);
++ source->master_line = 0;
++ entry->age = age;
++out:
++ free(map);
++}
++
+ static void master_add_amd_mount_section_mounts(struct master *master, time_t age)
+ {
+ unsigned int m_logopt = master->logopt;
+@@ -916,8 +993,10 @@ static void master_add_amd_mount_section_mounts(struct master *master, time_t ag
+ * master map it's not a duplicate, don't issue
+ * an error message.
+ */
+- if (ret == 1)
++ if (ret == 1) {
++ master_update_amd_mount_section_mount(master, path, age);
+ goto next;
++ }
+ info(m_logopt,
+ "amd section mount path conflict, %s ignored",
+ path);
--- /dev/null
+autofs-5.1.7 - fix arg not used in error print
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: extra_argument: This argument was not used by the format
+ string: "key".
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 4 +---
+ 2 files changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index f11aa1c7..1d56c96f 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -60,6 +60,7 @@
+ - dont try umount after stat() ENOENT fail.
+ - remove redundant assignment in master_add_amd_mount_section_mounts().
+ - fix dead code in mnts_add_mount().
++- fix arg not used in error print.
+
+ 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 018b9c80..883e3743 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1519,9 +1519,7 @@ int tree_mapent_add_node(struct mapent_cache *mc,
+ }
+
+ if (MAPENT_ROOT(base) != MAPENT_NODE(base)) {
+- error(logopt,
+- "failed to find multi-mount root of offset tree",
+- key);
++ error(logopt, "key %s is not multi-mount root", root);
+ return 0;
+ }
+ tree = MAPENT_ROOT(base);
--- /dev/null
+autofs-5.1.7 - fix concat_options() error handling
+
+From: Ian Kent <raven@themaw.net>
+
+There's a possibility of a memory leak in the mount options processing
+when calling concat_options() in parse_mount() of the Sun format map
+entry parsing.
+
+There's also a case in do_init() of the Sun map format parsing where
+a previously freed value is used in a logging statement without being
+set to MULL.
+
+So ensure concat_options() always frees it's arguments so that the
+handling can be consistent in all places.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 24 +++++++++++-------------
+ 2 files changed, 12 insertions(+), 13 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index ecffa933..8d050552 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -78,6 +78,7 @@
+ - fix direct mount deadlock.
+ - add missing description of null map option.
+ - fix nonstrict offset mount fail handling.
++- fix concat_options() error handling.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index cdf515c6..9190165d 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -380,7 +380,8 @@ static int do_init(int argc, const char *const *argv, struct parse_context *ctxt
+ if (!tmp) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ logerr(MODPREFIX "concat_options: %s", estr);
+- free(gbl_options);
++ /* freed in concat_options */
++ ctxt->optstr = NULL;
+ } else
+ ctxt->optstr = tmp;
+ } else {
+@@ -492,12 +493,16 @@ static char *concat_options(char *left, char *right)
+ char *ret;
+
+ if (left == NULL || *left == '\0') {
++ if (!right || *right == '\0')
++ return NULL;
+ ret = strdup(right);
+ free(right);
+ return ret;
+ }
+
+ if (right == NULL || *right == '\0') {
++ if (left == NULL || *left == '\0')
++ return NULL;
+ ret = strdup(left);
+ free(left);
+ return ret;
+@@ -508,6 +513,8 @@ static char *concat_options(char *left, char *right)
+ if (ret == NULL) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ logerr(MODPREFIX "malloc: %s", estr);
++ free(left);
++ free(right);
+ return NULL;
+ }
+
+@@ -989,14 +996,13 @@ static int parse_mapent(const char *ent, char *g_options, char **options, char *
+ if (newopt && strstr(newopt, myoptions)) {
+ free(myoptions);
+ myoptions = newopt;
+- } else {
++ } else if (newopt) {
+ tmp = concat_options(myoptions, newopt);
+ if (!tmp) {
+ char *estr;
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(logopt, MODPREFIX
+ "concat_options: %s", estr);
+- free(myoptions);
+ return 0;
+ }
+ myoptions = tmp;
+@@ -1358,16 +1364,12 @@ dont_expand:
+ if (mnt_options && noptions && strstr(noptions, mnt_options)) {
+ free(mnt_options);
+ mnt_options = noptions;
+- } else {
++ } else if (noptions) {
+ tmp = concat_options(mnt_options, noptions);
+ if (!tmp) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(ap->logopt,
+ MODPREFIX "concat_options: %s", estr);
+- if (noptions)
+- free(noptions);
+- if (mnt_options)
+- free(mnt_options);
+ free(options);
+ free(pmapent);
+ return 1;
+@@ -1387,15 +1389,11 @@ dont_expand:
+ if (options && mnt_options && strstr(mnt_options, options)) {
+ free(options);
+ options = mnt_options;
+- } else {
++ } else if (mnt_options) {
+ tmp = concat_options(options, mnt_options);
+ if (!tmp) {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(ap->logopt, MODPREFIX "concat_options: %s", estr);
+- if (options)
+- free(options);
+- if (mnt_options)
+- free(mnt_options);
+ free(pmapent);
+ return 1;
+ }
--- /dev/null
+autofs-5.1.7 - fix dandling symlink creation if nis support is not available
+
+From: Ian Kent <raven@themaw.net>
+
+If NIS support is not available a dangling symlink is created pointing
+from lookup_nis.so to (a non-existent) lookup_yp.so.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/Makefile | 2 ++
+ 2 files changed, 3 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index ddc07912..06bf24b8 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -67,6 +67,7 @@
+ - cater for empty mounts list in mnts_get_expire_list().
+ - add ext_mount_hash_mutex lock helpers.
+ - fix amd section mounts map reload.
++- fix dandling symlink creation if nis support is not available.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/Makefile b/modules/Makefile
+index 91dc20ab..6908da06 100644
+--- a/modules/Makefile
++++ b/modules/Makefile
+@@ -77,7 +77,9 @@ install: all
+ install -c $(MODS) -m 755 $(INSTALLROOT)$(autofslibdir)
+ -rm -f $(INSTALLROOT)$(autofslibdir)/mount_smbfs.so
+ ln -fs lookup_file.so $(INSTALLROOT)$(autofslibdir)/lookup_files.so
++ifeq ($(YPCLNT), 1)
+ ln -fs lookup_yp.so $(INSTALLROOT)$(autofslibdir)/lookup_nis.so
++endif
+ ifeq ($(LDAP), 1)
+ ln -fs lookup_ldap.so $(INSTALLROOT)$(autofslibdir)/lookup_ldaps.so
+ endif
--- /dev/null
+autofs-5.1.7 - fix dead code in mnts_add_mount()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: dead_error_line: Execution cannot reach this statement: "free(mp);".
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 8 ++------
+ 2 files changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index f95b1aa6..f11aa1c7 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -59,6 +59,7 @@
+ - fix flags check in umount_multi().
+ - dont try umount after stat() ENOENT fail.
+ - remove redundant assignment in master_add_amd_mount_section_mounts().
++- fix dead code in mnts_add_mount().
+
+ 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 ef69cec1..018b9c80 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1205,13 +1205,13 @@ struct mnt_list *mnts_add_mount(struct autofs_point *ap,
+ if (*name == '/') {
+ mp = strdup(name);
+ if (!mp)
+- goto fail;
++ return NULL;
+ } else {
+ int len = ap->len + strlen(name) + 2;
+
+ mp = malloc(len);
+ if (!mp)
+- goto fail;
++ return NULL;
+ strcpy(mp, ap->path);
+ strcat(mp, "/");
+ strcat(mp, name);
+@@ -1228,10 +1228,6 @@ struct mnt_list *mnts_add_mount(struct autofs_point *ap,
+ free(mp);
+
+ return this;
+-fail:
+- if (mp)
+- free(mp);
+- return NULL;
+ }
+
+ void mnts_remove_mount(const char *mp, unsigned int flags)
--- /dev/null
+autofs-5.1.7 - fix direct mount deadlock
+
+From: Ian Kent <raven@themaw.net>
+
+When umounting direct mounts at exit or when umounting mounts no
+longer in the map on re-load a deadlock can occur.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/direct.c | 22 +++++++++++++++++++++-
+ daemon/state.c | 14 +++++++++-----
+ 3 files changed, 31 insertions(+), 6 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 9e341e06..b29d2ed8 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -75,6 +75,7 @@
+ - use mapent tree root for tree_mapent_add_node().
+ - eliminate redundant cache lookup in tree_mapent_add_node().
+ - fix hosts map offset order.
++- fix direct mount deadlock.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/direct.c b/daemon/direct.c
+index 3bd714e6..d37dd676 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -84,11 +84,27 @@ static void mnts_cleanup(void *arg)
+ int do_umount_autofs_direct(struct autofs_point *ap, struct mapent *me)
+ {
+ struct ioctl_ops *ops = get_ioctl_ops();
++ struct mapent_cache *mc = me->mc;
+ char buf[MAX_ERR_BUF];
+ int ioctlfd = -1, rv, left, retries;
++ char key[PATH_MAX + 1];
++ struct mapent *tmp;
+ int opened = 0;
+
+- left = umount_multi(ap, me->key, 0);
++ if (me->len > PATH_MAX) {
++ error(ap->logopt, "path too long");
++ return 1;
++ }
++ strcpy(key, me->key);
++
++ cache_unlock(mc);
++ left = umount_multi(ap, key, 0);
++ cache_readlock(mc);
++ tmp = cache_lookup_distinct(mc, key);
++ if (tmp != me) {
++ error(ap->logopt, "key %s no longer in mapent cache", key);
++ return -1;
++ }
+ if (left) {
+ warn(ap->logopt, "could not unmount %d dirs under %s",
+ left, me->key);
+@@ -213,6 +229,7 @@ int umount_autofs_direct(struct autofs_point *ap)
+ mc = map->mc;
+ pthread_cleanup_push(cache_lock_cleanup, mc);
+ cache_readlock(mc);
++restart:
+ me = cache_enumerate(mc, NULL);
+ while (me) {
+ int error;
+@@ -230,6 +247,9 @@ int umount_autofs_direct(struct autofs_point *ap)
+ * failed umount.
+ */
+ error = do_umount_autofs_direct(ap, me);
++ /* cache became invalid, restart */
++ if (error == -1)
++ goto restart;
+ if (!error)
+ goto done;
+
+diff --git a/daemon/state.c b/daemon/state.c
+index 091210a5..5156bb21 100644
+--- a/daemon/state.c
++++ b/daemon/state.c
+@@ -324,11 +324,12 @@ static void do_readmap_cleanup(void *arg)
+ return;
+ }
+
+-static void do_readmap_mount(struct autofs_point *ap,
++static int do_readmap_mount(struct autofs_point *ap,
+ struct map_source *map, struct mapent *me, time_t now)
+ {
+ struct mapent_cache *nc;
+ struct mapent *ne, *nested, *valid;
++ int ret = 0;
+
+ nc = ap->entry->master->nc;
+
+@@ -387,7 +388,7 @@ static void do_readmap_mount(struct autofs_point *ap,
+ cache_unlock(vmc);
+ error(ap->logopt,
+ "failed to find expected existing valid map entry");
+- return;
++ return ret;
+ }
+ /* Take over the mount if there is one */
+ valid->ioctlfd = me->ioctlfd;
+@@ -406,14 +407,14 @@ static void do_readmap_mount(struct autofs_point *ap,
+ ap->exp_runfreq = runfreq;
+ }
+ } else if (!is_mounted(me->key, MNTS_REAL))
+- do_umount_autofs_direct(ap, me);
++ ret = do_umount_autofs_direct(ap, me);
+ else
+ debug(ap->logopt,
+ "%s is mounted", me->key);
+ } else
+ do_mount_autofs_direct(ap, me, get_exp_timeout(ap, map));
+
+- return;
++ return ret;
+ }
+
+ static void *do_readmap(void *arg)
+@@ -480,9 +481,12 @@ static void *do_readmap(void *arg)
+ mc = map->mc;
+ pthread_cleanup_push(cache_lock_cleanup, mc);
+ cache_readlock(mc);
++restart:
+ me = cache_enumerate(mc, NULL);
+ while (me) {
+- do_readmap_mount(ap, map, me, now);
++ int ret = do_readmap_mount(ap, map, me, now);
++ if (ret == -1)
++ goto restart;
+ me = cache_enumerate(mc, me);
+ }
+ lookup_prune_one_cache(ap, map->mc, now);
--- /dev/null
+autofs-5.1.7 - fix double free in parse_mapent()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity:
+in parse_mapent(): double_free: Calling "free" frees pointer "newopt"
+ which has already been freed.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 2 --
+ 2 files changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index ff3d88eb..81461978 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -62,6 +62,7 @@
+ - fix dead code in mnts_add_mount().
+ - fix arg not used in error print.
+ - fix missing lock release in mount_subtree().
++- fix double free in parse_mapent().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 5d15f892..03a63290 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -974,8 +974,6 @@ static int parse_mapent(const char *ent, char *g_options, char **options, char *
+ estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ error(logopt, MODPREFIX
+ "concat_options: %s", estr);
+- if (newopt)
+- free(newopt);
+ free(myoptions);
+ return 0;
+ }
--- /dev/null
+autofs-5.1.7 - fix double unlock in parse_mount()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: double_unlock: "cache_unlock" unlocks "mc->rwlock" while it
+ is unlocked.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 1 -
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 2e3b9fd7..224f58d6 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -54,6 +54,7 @@
+ - remove redundant if check.
+ - fix possible memory leak in master_parse().
+ - fix possible memory leak in mnts_add_amdmount().
++- fix double unlock in parse_mount().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index a81d4028..05f53fc2 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1526,7 +1526,6 @@ dont_expand:
+ if (!loc) {
+ free(options);
+ free(pmapent);
+- cache_unlock(mc);
+ warn(ap->logopt, MODPREFIX "out of memory");
+ return 1;
+ }
--- /dev/null
+autofs-5.1.7 - fix flags check in umount_multi()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: operator_confusion: "ap->flags | 1" is always 1/true
+ regardless of the values of its operand.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/automount.c | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 9e385ba9..7add6c55 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -56,6 +56,7 @@
+ - fix possible memory leak in mnts_add_amdmount().
+ - fix double unlock in parse_mount().
+ - add length check in umount_subtree_mounts().
++- fix flags check in umount_multi().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 70506d83..23235a7d 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -662,7 +662,7 @@ int umount_multi(struct autofs_point *ap, const char *path, int incl)
+ /* Check if the autofs mount has browse mode enabled.
+ * If so re-create the directory entry.
+ */
+- if (ap->flags | MOUNT_FLAG_GHOST) {
++ if (ap->flags & MOUNT_FLAG_GHOST) {
+ int ret;
+
+ /* If the browse directory create fails log an
--- /dev/null
+autofs-5.1.7 - fix hosts map offset order
+
+From: Ian Kent <raven@themaw.net>
+
+Map entry offset paths need to be in shortest to longest order but
+exports from a server could come in any order. If there are a large
+number of exports this can result in a lot of overhead when adding
+the offset to the ordered list used to mount the offset during parsing
+since the path length of exports can vary a lot.
+
+So leverage the tree implemention to sort the export offsets into
+shortest to longest order as we go when constructing the mapent from
+the exports list.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/automount.h | 2 +
+ include/mounts.h | 8 ++++++
+ include/rpc_subs.h | 3 ++
+ lib/mounts.c | 57 ++++++++++++++++++++++++++++++++++++++--
+ modules/lookup_hosts.c | 69 ++++++++++++++++++++++++++++++++++++++----------
+ 6 files changed, 123 insertions(+), 17 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 81b6ce6a..9e341e06 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -74,6 +74,7 @@
+ - fix offset entries order.
+ - use mapent tree root for tree_mapent_add_node().
+ - eliminate redundant cache lookup in tree_mapent_add_node().
++- fix hosts map offset order.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/automount.h b/include/automount.h
+index d279744d..947ed16d 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -31,9 +31,9 @@
+ #include "master.h"
+ #include "macros.h"
+ #include "log.h"
++#include "mounts.h"
+ #include "rpc_subs.h"
+ #include "parse_subs.h"
+-#include "mounts.h"
+ #include "dev-ioctl-lib.h"
+ #include "parse_amd.h"
+
+diff --git a/include/mounts.h b/include/mounts.h
+index 5a7a0b89..ddb7e4c5 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -52,6 +52,7 @@ extern const unsigned int t_direct;
+ extern const unsigned int t_offset;
+
+ struct mnt_list;
++struct exportinfo;
+ struct mapent;
+
+ struct tree_ops;
+@@ -66,6 +67,9 @@ struct tree_node {
+ #define MNT_LIST(n) (container_of(n, struct mnt_list, node))
+ #define MNT_LIST_NODE(ptr) ((struct tree_node *) &((struct mnt_list *) ptr)->node)
+
++#define EXPORTINFO(n) (container_of(n, struct exportinfo, node))
++#define EXPORT_NODE(ptr) ((struct tree_node *) &((struct exportinfo *) ptr)->node)
++
+ #define MAPENT(n) (container_of(n, struct mapent, node))
+ #define MAPENT_NODE(p) ((struct tree_node *) &((struct mapent *) p)->node)
+ #define MAPENT_ROOT(p) ((struct tree_node *) ((struct mapent *) p)->mm_root)
+@@ -166,9 +170,13 @@ struct mnt_list *mnts_add_mount(struct autofs_point *ap, const char *name, unsig
+ void mnts_remove_mount(const char *mp, unsigned int flags);
+ struct mnt_list *get_mnt_list(const char *path, int include);
+ unsigned int mnts_has_mounted_mounts(struct autofs_point *ap);
++int tree_traverse_inorder(struct tree_node *n, tree_work_fn_t work, void *ptr);
++void tree_free(struct tree_node *root);
+ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap);
+ void mnts_put_expire_list(struct list_head *mnts);
+ void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned int flags);
++struct tree_node *tree_host_root(struct exportinfo *exp);
++struct tree_node *tree_host_add_node(struct tree_node *root, struct exportinfo *exp);
+ struct tree_node *tree_mapent_root(struct mapent *me);
+ int tree_mapent_add_node(struct mapent_cache *mc, struct tree_node *root, struct mapent *me);
+ int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key);
+diff --git a/include/rpc_subs.h b/include/rpc_subs.h
+index 080f19d9..debf2df0 100644
+--- a/include/rpc_subs.h
++++ b/include/rpc_subs.h
+@@ -23,6 +23,8 @@
+ #include <linux/nfs2.h>
+ #include <linux/nfs3.h>
+
++#include "automount.h"
++
+ #define NFS4_VERSION 4
+
+ /* rpc helper subs */
+@@ -57,6 +59,7 @@ struct exportinfo {
+ char *dir;
+ struct hostinfo *hosts;
+ struct exportinfo *next;
++ struct tree_node node;
+ };
+
+ struct conn_info {
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 6b24a6c2..5a4602e3 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -79,6 +79,17 @@ static struct tree_ops mnt_ops = {
+ };
+ static struct tree_ops *tree_mnt_ops = &mnt_ops;
+
++static struct tree_node *tree_host_new(void *ptr);
++static int tree_host_cmp(struct tree_node *n, void *ptr);
++static void tree_host_free(struct tree_node *n);
++
++static struct tree_ops host_ops = {
++ .new = tree_host_new,
++ .cmp = tree_host_cmp,
++ .free = tree_host_free,
++};
++static struct tree_ops *tree_host_ops = &host_ops;
++
+ static struct tree_node *tree_mapent_new(void *ptr);
+ static int tree_mapent_cmp(struct tree_node *n, void *ptr);
+ static void tree_mapent_free(struct tree_node *n);
+@@ -1341,7 +1352,7 @@ static struct tree_node *tree_add_node(struct tree_node *root, void *ptr)
+ return NULL;
+ }
+
+-static void tree_free(struct tree_node *root)
++void tree_free(struct tree_node *root)
+ {
+ struct tree_ops *ops = root->ops;
+
+@@ -1352,7 +1363,7 @@ static void tree_free(struct tree_node *root)
+ ops->free(root);
+ }
+
+-static int tree_traverse_inorder(struct tree_node *n, tree_work_fn_t work, void *ptr)
++int tree_traverse_inorder(struct tree_node *n, tree_work_fn_t work, void *ptr)
+ {
+ int ret;
+
+@@ -1479,6 +1490,48 @@ void mnts_put_expire_list(struct list_head *mnts)
+ mnts_hash_mutex_unlock();
+ }
+
++struct tree_node *tree_host_root(struct exportinfo *exp)
++{
++ return tree_root(tree_host_ops, exp);
++}
++
++static struct tree_node *tree_host_new(void *ptr)
++{
++ struct tree_node *n = EXPORT_NODE(ptr);
++
++ n->ops = tree_host_ops;
++ n->left = NULL;
++ n->right = NULL;
++
++ return n;
++}
++
++static int tree_host_cmp(struct tree_node *n, void *ptr)
++{
++ struct exportinfo *n_exp = EXPORTINFO(n);
++ size_t n_exp_len = strlen(n_exp->dir);
++ struct exportinfo *exp = ptr;
++ size_t exp_len = strlen(exp->dir);
++ int eq;
++
++ eq = strcmp(exp->dir, n_exp->dir);
++ if (!eq)
++ return 0;
++ return (exp_len < n_exp_len) ? -1 : 1;
++}
++
++static void tree_host_free(struct tree_node *n)
++{
++ n->ops = NULL;
++ n->left = NULL;
++ n->right = NULL;
++}
++
++struct tree_node *tree_host_add_node(struct tree_node *root, struct exportinfo *exp)
++{
++ return tree_add_node(root, exp);
++}
++
+ struct tree_node *tree_mapent_root(struct mapent *me)
+ {
+ return tree_root(tree_mapent_ops, me);
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index 24edf00c..26c224f6 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -84,14 +84,38 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ return NSS_STATUS_UNKNOWN;
+ }
+
++struct work_info {
++ char *mapent;
++ const char *host;
++ int pos;
++};
++
++static int tree_host_work(struct tree_node *n, void *ptr)
++{
++ struct exportinfo *exp = EXPORTINFO(n);
++ struct work_info *wi = ptr;
++ int len;
++
++ if (!wi->pos)
++ len = sprintf(wi->mapent, "\"%s\" \"%s:%s\"",
++ exp->dir, wi->host, exp->dir);
++ else
++ len = sprintf(wi->mapent + wi->pos, " \"%s\" \"%s:%s\"",
++ exp->dir, wi->host, exp->dir);
++ wi->pos += len;
++
++ return 1;
++}
++
+ static char *get_exports(struct autofs_point *ap, const char *host)
+ {
+ char buf[MAX_ERR_BUF];
+ char *mapent;
+ struct exportinfo *exp, *this;
++ struct tree_node *tree = NULL;
++ struct work_info wi;
+ size_t hostlen = strlen(host);
+ size_t mapent_len;
+- int len, pos;
+
+ debug(ap->logopt, MODPREFIX "fetchng export list for %s", host);
+
+@@ -100,7 +124,28 @@ static char *get_exports(struct autofs_point *ap, const char *host)
+ this = exp;
+ mapent_len = 0;
+ while (this) {
++ struct tree_node *n;
++
+ mapent_len += hostlen + 2*(strlen(this->dir) + 2) + 3;
++
++ if (!tree) {
++ tree = tree_host_root(this);
++ if (!tree) {
++ error(ap->logopt, "failed to create exports tree root");
++ rpc_exports_free(exp);
++ return NULL;
++ }
++ goto next;
++ }
++
++ n = tree_host_add_node(tree, this);
++ if (!n) {
++ error(ap->logopt, "failed to add exports tree node");
++ tree_free(tree);
++ rpc_exports_free(exp);
++ return NULL;
++ }
++next:
+ this = this->next;
+ }
+
+@@ -115,20 +160,16 @@ static char *get_exports(struct autofs_point *ap, const char *host)
+ }
+ *mapent = 0;
+
+- pos = 0;
+- this = exp;
+- if (this) {
+- len = sprintf(mapent, "\"%s\" \"%s:%s\"",
+- this->dir, host, this->dir);
+- pos += len;
+- this = this->next;
+- }
++ wi.mapent = mapent;
++ wi.host = host;
++ wi.pos = 0;
+
+- while (this) {
+- len = sprintf(mapent + pos, " \"%s\" \"%s:%s\"",
+- this->dir, host, this->dir);
+- pos += len;
+- this = this->next;
++ if (!tree) {
++ free(mapent);
++ mapent = NULL;
++ } else {
++ tree_traverse_inorder(tree, tree_host_work, &wi);
++ tree_free(tree);
+ }
+ rpc_exports_free(exp);
+
--- /dev/null
+autofs-5.1.7 - fix inconsistent locking in parse_mount()
+
+From: Ian Kent <raven@themaw.net>
+
+Some map entry cache locking inconsistencies have crept in.
+
+In parse_mount() of the sun format parser the cache read lock is too
+heavily used and has too broad a scope. This has lead to some operations
+that should hold the write lock being called with only the read lock.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 9 ++++++++-
+ modules/parse_sun.c | 53 ++++++++++++++++++++++++++++++++-------------------
+ 3 files changed, 42 insertions(+), 21 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index c60a9ed3..d25b19c8 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -18,6 +18,7 @@
+ - fix inconsistent locking in umount_subtree_mounts().
+ - fix return from umount_subtree_mounts() on offset list delete.
+ - pass mapent_cache to update_offset_entry().
++- fix inconsistent locking in parse_mount().
+
+ 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 5ebfe5fd..0fcd4087 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2491,6 +2491,12 @@ static int do_mount_autofs_offset(struct autofs_point *ap,
+ else {
+ debug(ap->logopt, "ignoring \"nohide\" trigger %s",
+ oe->key);
++ /*
++ * Ok, so we shouldn't modify the mapent but
++ * mount requests are blocked at a point above
++ * this and expire only uses the mapent key or
++ * holds the cache write lock.
++ */
+ free(oe->mapent);
+ oe->mapent = NULL;
+ }
+@@ -2634,7 +2640,8 @@ static int do_umount_offset(struct autofs_point *ap, struct mapent *oe, const ch
+ /*
+ * Ok, so we shouldn't modify the mapent but
+ * mount requests are blocked at a point above
+- * this and expire only uses the mapent key.
++ * this and expire only uses the mapent key or
++ * holds the cache write lock.
+ */
+ if (oe->mapent) {
+ free(oe->mapent);
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 95251bee..a6630a76 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -851,10 +851,12 @@ update_offset_entry(struct autofs_point *ap,
+ strcpy(m_mapent, loc);
+ }
+
++ cache_writelock(mc);
+ ret = cache_update_offset(mc, name, m_key, m_mapent, age);
+
+ if (!cache_set_offset_parent(mc, m_key))
+ error(ap->logopt, "failed to set offset parent");
++ cache_unlock(mc);
+
+ if (ret == CHE_DUPLICATE) {
+ warn(ap->logopt, MODPREFIX
+@@ -1128,14 +1130,22 @@ static void cleanup_multi_triggers(struct autofs_point *ap,
+ return;
+ }
+
+-static int mount_subtree(struct autofs_point *ap, struct mapent *me,
++static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ const char *name, char *loc, char *options, void *ctxt)
+ {
++ struct mapent *me;
+ struct mapent *ro;
+ char *mm_root, *mm_base, *mm_key;
+ unsigned int mm_root_len;
+ int start, ret = 0, rv;
+
++ cache_readlock(mc);
++ me = cache_lookup_distinct(mc, name);
++ if (!me) {
++ cache_unlock(mc);
++ return 0;
++ }
++
+ rv = 0;
+
+ mm_key = me->multi->key;
+@@ -1180,9 +1190,12 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
+ rv = parse_mapent(ro->mapent,
+ options, &myoptions, &ro_loc, ap->logopt);
+ if (!rv) {
++ cache_unlock(mc);
+ warn(ap->logopt,
+ MODPREFIX "failed to parse root offset");
+- cache_delete_offset_list(me->mc, name);
++ cache_writelock(mc);
++ cache_delete_offset_list(mc, name);
++ cache_unlock(mc);
+ return 1;
+ }
+ ro_len = 0;
+@@ -1199,9 +1212,10 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
+ if ((ro && rv == 0) || rv <= 0) {
+ ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
+ if (ret == -1) {
++ cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
++ cache_unlock(mc);
+ error(ap->logopt, MODPREFIX
+ "failed to mount offset triggers");
+- cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
+ return 1;
+ }
+ }
+@@ -1217,9 +1231,10 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
+ if (rv == 0) {
+ ret = mount_multi_triggers(ap, me->multi, name, start, mm_base);
+ if (ret == -1) {
++ cleanup_multi_triggers(ap, me, name, start, mm_base);
++ cache_unlock(mc);
+ error(ap->logopt, MODPREFIX
+ "failed to mount offset triggers");
+- cleanup_multi_triggers(ap, me, name, start, mm_base);
+ return 1;
+ }
+ } else if (rv < 0) {
+@@ -1227,8 +1242,11 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
+ unsigned int mm_root_base_len = mm_root_len + strlen(mm_base) + 1;
+
+ if (mm_root_base_len > PATH_MAX) {
++ cache_unlock(mc);
+ warn(ap->logopt, MODPREFIX "path too long");
+- cache_delete_offset_list(me->mc, name);
++ cache_writelock(mc);
++ cache_delete_offset_list(mc, name);
++ cache_unlock(mc);
+ return 1;
+ }
+
+@@ -1237,13 +1255,15 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
+
+ ret = mount_multi_triggers(ap, me->multi, mm_root_base, start, mm_base);
+ if (ret == -1) {
++ cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
++ cache_unlock(mc);
+ error(ap->logopt, MODPREFIX
+ "failed to mount offset triggers");
+- cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
+ return 1;
+ }
+ }
+ }
++ cache_unlock(mc);
+
+ /* Mount for base of tree failed */
+ if (rv > 0)
+@@ -1484,7 +1504,6 @@ dont_expand:
+ return 1;
+ }
+
+- cache_multi_writelock(me);
+ /* So we know we're the multi-mount root */
+ if (!me->multi)
+ me->multi = me;
+@@ -1509,14 +1528,13 @@ dont_expand:
+ if (source->flags & MAP_FLAG_FORMAT_AMD) {
+ free(options);
+ free(pmapent);
+- cache_multi_unlock(me);
+ cache_unlock(mc);
+ pthread_setcancelstate(cur_state, NULL);
+ return 0;
+ }
+ }
+-
+ age = me->age;
++ cache_unlock(mc);
+
+ /* It's a multi-mount; deal with it */
+ do {
+@@ -1537,8 +1555,8 @@ dont_expand:
+
+ if (!path) {
+ warn(ap->logopt, MODPREFIX "null path or out of memory");
++ cache_writelock(mc);
+ cache_delete_offset_list(mc, name);
+- cache_multi_unlock(me);
+ cache_unlock(mc);
+ free(options);
+ free(pmapent);
+@@ -1554,8 +1572,8 @@ dont_expand:
+
+ l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
+ if (!l) {
++ cache_writelock(mc);
+ cache_delete_offset_list(mc, name);
+- cache_multi_unlock(me);
+ cache_unlock(mc);
+ free(path);
+ free(options);
+@@ -1573,8 +1591,8 @@ dont_expand:
+
+ if (status != CHE_OK) {
+ warn(ap->logopt, MODPREFIX "error adding multi-mount");
++ cache_writelock(mc);
+ cache_delete_offset_list(mc, name);
+- cache_multi_unlock(me);
+ cache_unlock(mc);
+ free(path);
+ free(options);
+@@ -1592,10 +1610,7 @@ dont_expand:
+ free(myoptions);
+ } while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
+
+- rv = mount_subtree(ap, me, name, NULL, options, ctxt);
+-
+- cache_multi_unlock(me);
+- cache_unlock(mc);
++ rv = mount_subtree(ap, mc, name, NULL, options, ctxt);
+
+ free(options);
+ free(pmapent);
+@@ -1616,6 +1631,7 @@ dont_expand:
+ cache_readlock(mc);
+ if (*name == '/' &&
+ (me = cache_lookup_distinct(mc, name)) && me->multi) {
++ cache_unlock(mc);
+ loc = strdup(p);
+ if (!loc) {
+ free(options);
+@@ -1624,10 +1640,7 @@ dont_expand:
+ warn(ap->logopt, MODPREFIX "out of memory");
+ return 1;
+ }
+- cache_multi_writelock(me);
+- rv = mount_subtree(ap, me, name, loc, options, ctxt);
+- cache_multi_unlock(me);
+- cache_unlock(mc);
++ rv = mount_subtree(ap, mc, name, loc, options, ctxt);
+ free(loc);
+ free(options);
+ free(pmapent);
--- /dev/null
+autofs-5.1.7 - fix inconsistent locking in umount_subtree_mounts()
+
+From: Ian Kent <raven@themaw.net>
+
+Some map entry cache locking inconsistencies have crept in.
+
+In umount_subtree_mounts() the cache write lock should be held when
+deleting multi-mount cache entries.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/automount.c | 42 ++++++++++++++++++++++++++++++------------
+ lib/mounts.c | 8 --------
+ 3 files changed, 31 insertions(+), 20 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 1dded118..64e619ec 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -15,6 +15,7 @@
+ - eliminate clean_stale_multi_triggers().
+ - simplify mount_subtree() mount check.
+ - fix mnts_get_expire_list() expire list construction.
++- fix inconsistent locking in umount_subtree_mounts().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 7fa92877..93bd8556 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -527,8 +527,11 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+ struct mapent_cache *mc;
+ struct mapent *me;
+ unsigned int is_mm_root = 0;
++ int cur_state;
+ int left;
+
++ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
++
+ me = lookup_source_mapent(ap, path, LKP_DISTINCT);
+ if (!me) {
+ char *ind_key;
+@@ -548,11 +551,11 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+ left = 0;
+
+ if (me && me->multi) {
+- char root[PATH_MAX];
++ char root[PATH_MAX + 1];
++ char key[PATH_MAX + 1];
++ struct mapent *tmp;
++ int status;
+ char *base;
+- int cur_state;
+-
+- pthread_cleanup_push(cache_lock_cleanup, mc);
+
+ if (!strchr(me->multi->key, '/'))
+ /* Indirect multi-mount root */
+@@ -567,25 +570,40 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+ else
+ base = me->key + strlen(root);
+
+- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
+- /* Lock the closest parent nesting point for umount */
+- cache_multi_writelock(me->parent);
+- if (umount_multi_triggers(ap, me, root, base)) {
++ left = umount_multi_triggers(ap, me, root, base);
++ if (left) {
+ warn(ap->logopt,
+ "some offset mounts still present under %s", path);
++ }
++
++ strcpy(key, me->key);
++
++ cache_unlock(mc);
++ cache_writelock(mc);
++ tmp = cache_lookup_distinct(mc, key);
++ /* mapent went away while we waited? */
++ if (tmp != me) {
++ cache_unlock(mc);
++ pthread_setcancelstate(cur_state, NULL);
++ return 0;
++ }
++
++ if (!left && is_mm_root) {
++ status = cache_delete_offset_list(mc, me->key);
++ if (status != CHE_OK)
++ warn(ap->logopt, "couldn't delete offset list");
+ left++;
+ }
+- cache_multi_unlock(me->parent);
++
+ if (ap->entry->maps &&
+ (ap->entry->maps->flags & MAP_FLAG_FORMAT_AMD))
+ cache_pop_mapent(me);
+- pthread_setcancelstate(cur_state, NULL);
+- pthread_cleanup_pop(0);
+ }
+-
+ if (me)
+ cache_unlock(mc);
+
++ pthread_setcancelstate(cur_state, NULL);
++
+ if (left || is_autofs_fs)
+ return left;
+
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 87813b16..5ebfe5fd 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2736,9 +2736,6 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
+ left = do_umount_multi_triggers(ap, me, root, base);
+
+ if (!left && me->multi == me) {
+- struct mapent_cache *mc = me->mc;
+- int status;
+-
+ /*
+ * Special case.
+ * If we can't umount the root container then we can't
+@@ -2756,11 +2753,6 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
+ }
+ }
+
+- /* We're done - clean out the offsets */
+- status = cache_delete_offset_list(mc, me->key);
+- if (status != CHE_OK)
+- warn(ap->logopt, "couldn't delete offset list");
+-
+ /* check for mounted mount entry and remove it if found */
+ mnts_remove_mount(root, MNTS_MOUNTED);
+ }
--- /dev/null
+autofs-5.1.7 - fix is mounted check on non existent path
+
+From: Ian Kent <raven@themaw.net>
+
+When checking if a path is a mount point the case of a non-existent path
+was not being handled.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/dev-ioctl-lib.c | 3 +++
+ lib/mounts.c | 12 +++++++++++-
+ 3 files changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 484bd866..e55fd66a 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -6,6 +6,7 @@
+ - fix mnts_remove_amdmount() uses wrong list.
+ - Fix option for master read wait.
+ - eliminate cache_lookup_offset() usage.
++- fix is mounted check on non existent path.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/lib/dev-ioctl-lib.c b/lib/dev-ioctl-lib.c
+index e8519236..7040c3da 100644
+--- a/lib/dev-ioctl-lib.c
++++ b/lib/dev-ioctl-lib.c
+@@ -759,6 +759,9 @@ static int dev_ioctl_ismountpoint(unsigned int logopt,
+ int save_errno = errno;
+ free_dev_ioctl_path(param);
+ errno = save_errno;
++ /* Path doesn't exist */
++ if (errno == ENOENT)
++ return 0;
+ return -1;
+ }
+
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 42e8ef07..fe931b20 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1649,8 +1649,18 @@ static int table_is_mounted(const char *mp, unsigned int type)
+ struct mntent mnt_wrk;
+ char buf[PATH_MAX * 3];
+ size_t mp_len = strlen(mp);
++ struct stat st;
+ FILE *tab;
+- int ret = 0;
++ int ret;
++
++ ret = stat(mp, &st);
++ if (ret == -1) {
++ if (errno == ENOENT) {
++ /* Path does not exist */
++ return 0;
++ }
++ ret = 0;
++ }
+
+ if (!mp || !mp_len || mp_len >= PATH_MAX)
+ return 0;
--- /dev/null
+autofs-5.1.7 - fix lookup_prune_one_cache() refactoring change
+
+From: Ian Kent <raven@themaw.net>
+
+Commit 256963d6b (autofs-5.1.7 - refactor lookup_prune_one_cache() a bit)
+changed the position of the getting the next enumeration map entry but
+failed to update a couple of other locations that assume the next map
+entry has been set. Under certain fairly common conditions this leads
+to an infinite loop.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/lookup.c | 5 ++++-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 51e7767e..698cc27a 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -69,6 +69,7 @@
+ - fix amd section mounts map reload.
+ - fix dandling symlink creation if nis support is not available.
+ - dont use AUTOFS_DEV_IOCTL_CLOSEMOUNT.
++- fix lookup_prune_one_cache() refactoring change.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index 3e9722e4..0b281f83 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -1379,6 +1379,7 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti
+ if (!key || strchr(key, '*')) {
+ if (key)
+ free(key);
++ me = cache_enumerate(mc, me);
+ continue;
+ }
+
+@@ -1386,6 +1387,7 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti
+ if (!path) {
+ warn(ap->logopt, "can't malloc storage for path");
+ free(key);
++ me = cache_enumerate(mc, me);
+ continue;
+ }
+
+@@ -1413,9 +1415,10 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti
+ }
+ if (!valid &&
+ is_mounted(path, MNTS_REAL)) {
+- debug(ap->logopt, "prune posponed, %s mounted", path);
++ debug(ap->logopt, "prune postponed, %s mounted", path);
+ free(key);
+ free(path);
++ me = cache_enumerate(mc, me);
+ continue;
+ }
+ if (valid)
--- /dev/null
+autofs-5.1.7 - fix missing lock release in mount_subtree()
+
+From: Ian Kent <raven@themaw.net>
+
+Covarity: missing_unlock: Returning without unlocking "mc->rwlock".
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 1d56c96f..ff3d88eb 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -61,6 +61,7 @@
+ - remove redundant assignment in master_add_amd_mount_section_mounts().
+ - fix dead code in mnts_add_mount().
+ - fix arg not used in error print.
++- fix missing lock release in mount_subtree().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 05f53fc2..5d15f892 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1105,6 +1105,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ len = mount_fullpath(key, PATH_MAX, ap->path, ap->len, me->key);
+ if (!len) {
+ warn(ap->logopt, "path loo long");
++ cache_unlock(mc);
+ return 1;
+ }
+ key[len] = '/';
--- /dev/null
+autofs-5.1.7 - fix mnts_get_expire_list() expire list construction
+
+From: Ian Kent <raven@themaw.net>
+
+The mnts_get_expire_list() function is supposed to return an ordered
+list of expire candidates but it is not checking the mounted status
+of list entries and is returning a larger list than is needed.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 3 +++
+ 2 files changed, 4 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index f5c5641a..1dded118 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -14,6 +14,7 @@
+ - refactor umount_multi_triggers().
+ - eliminate clean_stale_multi_triggers().
+ - simplify mount_subtree() mount check.
++- fix mnts_get_expire_list() expire list construction.
+
+ 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 a9abbebf..87813b16 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1364,6 +1364,9 @@ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap)
+ list_for_each_entry(mnt, &ap->mounts, mount) {
+ struct node *n;
+
++ if (!(mnt->flags & MNTS_MOUNTED))
++ continue;
++
+ __mnts_get_mount(mnt);
+
+ if (!tree) {
--- /dev/null
+autofs-5.1.7 - fix mnts_remove_amdmount() uses wrong list
+
+From: Ian Kent <raven@themaw.net>
+
+Function mnts_remove_amdmount() uses the wrong list when removing an
+amd mount.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index d613e5ca..fe49740e 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -3,6 +3,7 @@
+ - remove mount.x and rpcgen dependencies.
+ - dont use realloc in host exports list processing.
+ - use sprintf() when constructing hosts mapent.
++- fix mnts_remove_amdmount() uses wrong list.
+
+ 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 dbeb77b5..ccbd52e0 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1124,7 +1124,7 @@ void mnts_remove_amdmount(const char *mp)
+ if (!(this && this->flags & MNTS_AMD_MOUNT))
+ goto done;
+ this->flags &= ~MNTS_AMD_MOUNT;
+- list_del_init(&this->submount);
++ list_del_init(&this->amdmount);
+ if (this->ext_mp) {
+ free(this->ext_mp);
+ this->ext_mp = NULL;
--- /dev/null
+autofs-5.1.7 - fix mount_fullpath()
+
+From: Ian Kent <raven@themaw.net>
+
+mount_fullpath() incorrecly fills fullpath with the contents of root
+when name[0] == '/'. The cases root[last] == '/' and name[0] == '/'
+need to be handled seperately.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 4 +++-
+ modules/parse_amd.c | 6 ++++--
+ 3 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 390028ac..e2fd532c 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -36,6 +36,7 @@
+ - add tree_mapent_add_node().
+ - add tree_mapent_delete_offsets().
+ - add tree_mapent_traverse_subtree().
++- fix mount_fullpath().
+
+ 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 fded4c09..497c28c9 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -371,8 +371,10 @@ int mount_fullpath(char *fullpath, size_t max_len,
+ /* Root offset of multi-mount or direct or offset mount.
+ * Direct or offset mount, name (or root) is absolute path.
+ */
+- if (root[last] == '/' || *name == '/')
++ if (root[last] == '/')
+ len = snprintf(fullpath, max_len, "%s", root);
++ else if (*name == '/')
++ len = snprintf(fullpath, max_len, "%s", name);
+ else
+ len = snprintf(fullpath, max_len, "%s/%s", root, name);
+
+diff --git a/modules/parse_amd.c b/modules/parse_amd.c
+index 5a9079d6..64c1ce63 100644
+--- a/modules/parse_amd.c
++++ b/modules/parse_amd.c
+@@ -1177,7 +1177,8 @@ static int do_generic_mount(struct autofs_point *ap, const char *name,
+ * the automount filesystem.
+ */
+ if (!is_mounted(entry->fs, MNTS_REAL)) {
+- ret = do_mount(ap, entry->fs, "/", 1,
++ ret = do_mount(ap, entry->fs,
++ entry->fs, strlen(entry->fs),
+ target, entry->type, opts);
+ if (ret)
+ goto out;
+@@ -1227,7 +1228,8 @@ static int do_nfs_mount(struct autofs_point *ap, const char *name,
+ mount_nfs->context);
+ } else {
+ if (!is_mounted(entry->fs, MNTS_REAL)) {
+- ret = mount_nfs->mount_mount(ap, entry->fs, "/", 1,
++ ret = mount_nfs->mount_mount(ap, entry->fs,
++ entry->fs, strlen(entry->fs),
+ target, entry->type, opts,
+ mount_nfs->context);
+ if (ret)
--- /dev/null
+autofs-5.1.7 - fix nonstrict offset mount fail handling
+
+From: Ian Kent <raven@themaw.net>
+
+If a triggered offset mount fails automount is not handling nonstrict
+mount failure correctly.
+
+The nonstrict mount failure handling needs to convert an offset mount
+failure to a success if the offset subtree below the failed mount is not
+empty otherwise it must return the failure. The previous implementation
+used -1 to indicate the subtree was empty and that was used to detect
+when the mount should fail instead of converting the fail to a success.
+
+Make the new implementation do the same.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 2 +-
+ modules/parse_sun.c | 2 +-
+ 3 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index f5f0da76..ecffa933 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -77,6 +77,7 @@
+ - fix hosts map offset order.
+ - fix direct mount deadlock.
+ - add missing description of null map option.
++- fix nonstrict offset mount fail handling.
+
+ 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 5a4602e3..4c866885 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1616,7 +1616,7 @@ static int tree_mapent_traverse_subtree(struct tree_node *n, tree_work_fn_t work
+ {
+ struct traverse_subtree_context *ctxt = ptr;
+ struct mapent *oe = MAPENT(n);
+- int ret = 1;
++ int ret = -1;
+
+ if (n->left) {
+ ret = tree_mapent_traverse_subtree(n->left, work, ctxt);
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 12844a30..cdf515c6 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1181,7 +1181,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ * offsets to be mounted.
+ */
+ rv = sun_mount(ap, name, name, namelen, loc, loclen, options, ctxt);
+- if (rv == 0) {
++ if (rv <= 0) {
+ ret = tree_mapent_mount_offsets(me, 1);
+ if (!ret) {
+ tree_mapent_cleanup_offsets(me);
--- /dev/null
+autofs-5.1.7 - fix offset entries order
+
+From: Ian Kent <raven@themaw.net>
+
+While it's rare it's possible that a mapent entry might not have
+it's offsets in shortest to longest path order.
+
+If this happens adding an entry to the mapent tree can result in
+an incorrect tree topology that doesn't work. That's because adding
+tree entries ensures that nodes in a sub-tree are placed below the
+containing node so the containing node must be present for that to
+work. This topology is critical to the performance of map entries
+that have a very large number of offsets such as an NFS server with
+many exports.
+
+There's no other choice but make a traversal after the offset entries
+have all been added to create the mapent tree.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/automount.h | 1 +
+ lib/cache.c | 1 +
+ modules/parse_sun.c | 74 +++++++++++++++++++++++++++++++++++++++++----------
+ 4 files changed, 62 insertions(+), 15 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 94eb6a2c..7b360f52 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -71,6 +71,7 @@
+ - dont use AUTOFS_DEV_IOCTL_CLOSEMOUNT.
+ - fix lookup_prune_one_cache() refactoring change.
+ - fix amd hosts mount expire.
++- fix offset entries order.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/automount.h b/include/automount.h
+index 51a0bf0e..d279744d 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -169,6 +169,7 @@ struct mapent {
+ /* Parent nesting point within multi-mount */
+ struct tree_node *mm_parent;
+ struct tree_node node;
++ struct list_head work;
+ char *key;
+ size_t len;
+ char *mapent;
+diff --git a/lib/cache.c b/lib/cache.c
+index ef761739..66dda5d9 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -559,6 +559,7 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
+ me->mm_parent = NULL;
+ INIT_TREE_NODE(&me->node);
+ INIT_LIST_HEAD(&me->ino_index);
++ INIT_LIST_HEAD(&me->work);
+ me->ioctlfd = -1;
+ me->dev = (dev_t) -1;
+ me->ino = (ino_t) -1;
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 03a63290..b206a326 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -789,14 +789,15 @@ static int check_is_multi(const char *mapent)
+
+ static int
+ update_offset_entry(struct autofs_point *ap,
+- struct mapent_cache *mc, const char *name,
+- const char *m_root, int m_root_len,
++ struct mapent_cache *mc, struct list_head *offsets,
++ const char *name, const char *m_root, int m_root_len,
+ const char *m_offset, const char *myoptions,
+ const char *loc, time_t age)
+ {
+ char m_key[PATH_MAX + 1];
+ char m_mapent[MAPENT_MAX_LEN + 1];
+ int o_len, m_key_len, m_options_len, m_mapent_len;
++ struct mapent *me;
+ int ret;
+
+ memset(m_mapent, 0, MAPENT_MAX_LEN + 1);
+@@ -862,8 +863,29 @@ update_offset_entry(struct autofs_point *ap,
+ cache_writelock(mc);
+ ret = cache_update_offset(mc, name, m_key, m_mapent, age);
+
+- if (!tree_mapent_add_node(mc, name, m_key))
+- error(ap->logopt, "failed to add offset %s to tree", m_key);
++ me = cache_lookup_distinct(mc, m_key);
++ if (me && list_empty(&me->work)) {
++ struct list_head *last;
++
++ /* Offset entries really need to be in shortest to
++ * longest path order. If not and the list of offsets
++ * is large there will be a performace hit.
++ */
++ list_for_each_prev(last, offsets) {
++ struct mapent *this;
++
++ this = list_entry(last, struct mapent, work);
++ if (me->len >= this->len) {
++ if (last->next == offsets)
++ list_add_tail(&me->work, offsets);
++ else
++ list_add_tail(&me->work, last);
++ break;
++ }
++ }
++ if (list_empty(&me->work))
++ list_add(&me->work, offsets);
++ }
+ cache_unlock(mc);
+
+ if (ret == CHE_DUPLICATE) {
+@@ -1209,6 +1231,25 @@ static char *do_expandsunent(const char *src, const char *key,
+ return mapent;
+ }
+
++static void cleanup_offset_entries(struct autofs_point *ap,
++ struct mapent_cache *mc,
++ struct list_head *offsets)
++{
++ struct mapent *me, *tmp;
++ int ret;
++
++ if (list_empty(offsets))
++ return;
++ cache_writelock(mc);
++ list_for_each_entry_safe(me, tmp, offsets, work) {
++ list_del(&me->work);
++ ret = cache_delete(mc, me->key);
++ if (ret != CHE_OK)
++ crit(ap->logopt, "failed to delete offset %s", me->key);
++ }
++ cache_unlock(mc);
++}
++
+ /*
+ * syntax is:
+ * [-options] location [location] ...
+@@ -1228,7 +1269,8 @@ int parse_mount(struct autofs_point *ap, const char *name,
+ char buf[MAX_ERR_BUF];
+ struct map_source *source;
+ struct mapent_cache *mc;
+- struct mapent *me;
++ struct mapent *me, *oe, *tmp;
++ LIST_HEAD(offsets);
+ char *pmapent, *options;
+ const char *p;
+ int mapent_len, rv = 0;
+@@ -1444,9 +1486,7 @@ dont_expand:
+
+ if (!m_offset) {
+ warn(ap->logopt, MODPREFIX "null path or out of memory");
+- cache_writelock(mc);
+- tree_mapent_delete_offsets(mc, name);
+- cache_unlock(mc);
++ cleanup_offset_entries(ap, mc, &offsets);
+ free(options);
+ free(pmapent);
+ pthread_setcancelstate(cur_state, NULL);
+@@ -1461,9 +1501,7 @@ dont_expand:
+
+ l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
+ if (!l) {
+- cache_writelock(mc);
+- tree_mapent_delete_offsets(mc, name);
+- cache_unlock(mc);
++ cleanup_offset_entries(ap, mc, &offsets);
+ free(m_offset);
+ free(options);
+ free(pmapent);
+@@ -1474,15 +1512,13 @@ dont_expand:
+ p += l;
+ p = skipspace(p);
+
+- status = update_offset_entry(ap, mc,
++ status = update_offset_entry(ap, mc, &offsets,
+ name, m_root, m_root_len,
+ m_offset, myoptions, loc, age);
+
+ if (status != CHE_OK) {
+ warn(ap->logopt, MODPREFIX "error adding multi-mount");
+- cache_writelock(mc);
+- tree_mapent_delete_offsets(mc, name);
+- cache_unlock(mc);
++ cleanup_offset_entries(ap, mc, &offsets);
+ free(m_offset);
+ free(options);
+ free(pmapent);
+@@ -1499,6 +1535,14 @@ dont_expand:
+ free(myoptions);
+ } while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
+
++ cache_writelock(mc);
++ list_for_each_entry_safe(oe, tmp, &offsets, work) {
++ if (!tree_mapent_add_node(mc, name, oe->key))
++ error(ap->logopt, "failed to add offset %s to tree", oe->key);
++ list_del_init(&oe->work);
++ }
++ cache_unlock(mc);
++
+ rv = mount_subtree(ap, mc, name, NULL, options, ctxt);
+
+ free(options);
--- /dev/null
+autofs-5.1.7 - fix possible memory leak in master_parse()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: Overwriting "path" in "path = master_strdup(yyvsp[-1].strtype)"
+ leaks the storage that "path" points to.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/master_parse.y | 2 ++
+ 2 files changed, 3 insertions(+)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 2186cbe3..b797f6dc 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -52,6 +52,7 @@
+ - remove unused variable from get_exports().
+ - add missing free in handle_mounts().
+ - remove redundant if check.
++- fix possible memory leak in master_parse().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/master_parse.y b/daemon/master_parse.y
+index 08e44b57..7480c36a 100644
+--- a/daemon/master_parse.y
++++ b/daemon/master_parse.y
+@@ -155,6 +155,8 @@ file: {
+ line:
+ | PATH mapspec
+ {
++ if (path)
++ free(path);
+ path = master_strdup($1);
+ if (!path) {
+ local_free_vars();
--- /dev/null
+autofs-5.1.7 - fix possible memory leak in mnts_add_amdmount()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: leaked_storage: Variable "ext_mp" going out of scope leaks
+ the storage it points to.
+
+Same applies to the other duped fields destined for the mnt_list struct.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 20 ++++++++++----------
+ 2 files changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index b797f6dc..2e3b9fd7 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -53,6 +53,7 @@
+ - add missing free in handle_mounts().
+ - remove redundant if check.
+ - fix possible memory leak in master_parse().
++- fix possible memory leak in mnts_add_amdmount().
+
+ 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 c8a7bf00..ef69cec1 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1119,16 +1119,16 @@ struct mnt_list *mnts_add_amdmount(struct autofs_point *ap, struct amd_entry *en
+
+ mnts_hash_mutex_lock();
+ this = mnts_get_mount(entry->path);
+- if (this) {
+- this->ext_mp = ext_mp;
+- this->amd_pref = pref;
+- this->amd_type = type;
+- this->amd_opts = opts;
+- this->amd_cache_opts = entry->cache_opts;
+- this->flags |= MNTS_AMD_MOUNT;
+- if (list_empty(&this->amdmount))
+- list_add_tail(&this->amdmount, &ap->amdmounts);
+- }
++ if (!this)
++ goto fail;
++ this->ext_mp = ext_mp;
++ this->amd_pref = pref;
++ this->amd_type = type;
++ this->amd_opts = opts;
++ this->amd_cache_opts = entry->cache_opts;
++ this->flags |= MNTS_AMD_MOUNT;
++ if (list_empty(&this->amdmount))
++ list_add_tail(&this->amdmount, &ap->amdmounts);
+ mnts_hash_mutex_unlock();
+
+ return this;
--- /dev/null
+autofs-5.1.7 - fix return from umount_subtree_mounts() on offset list delete
+
+From: Ian Kent <raven@themaw.net>
+
+When there are no mounts left in a subtree of offset mounts the offset
+list is deleted. If all goes well deleting the list this shouldn't cause
+a positive return from umount_subtree_mounts() (essentially saying that
+the umount of the subtree has not succeeded).
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/automount.c | 5 +++--
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 64e619ec..6e0edd74 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -16,6 +16,7 @@
+ - simplify mount_subtree() mount check.
+ - fix mnts_get_expire_list() expire list construction.
+ - fix inconsistent locking in umount_subtree_mounts().
++- fix return from umount_subtree_mounts() on offset list delete.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 93bd8556..62530b6b 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -590,9 +590,10 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+
+ if (!left && is_mm_root) {
+ status = cache_delete_offset_list(mc, me->key);
+- if (status != CHE_OK)
++ if (status != CHE_OK) {
+ warn(ap->logopt, "couldn't delete offset list");
+- left++;
++ left++;
++ }
+ }
+
+ if (ap->entry->maps &&
--- /dev/null
+autofs-5.1.7 - make tree implementation data independent
+
+From: Ian Kent <raven@themaw.net>
+
+Generalise the tree implementation so that it's independent of the
+data structure that's used.
+
+Do this by refactoring it into core tree functions and functions
+specific to the data structure to be used so that different data
+structures can be used when needed by adding an implementation for
+the data structure specific functions.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1
+ include/mounts.h | 29 +++++++++
+ lib/mounts.c | 174 ++++++++++++++++++++++++++++++++++--------------------
+ 3 files changed, 140 insertions(+), 64 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 0dae6761..74571570 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -31,6 +31,7 @@
+ - add some multi-mount macros.
+ - remove unused functions cache_dump_multi() and cache_dump_cache().
+ - add a len field to struct autofs_point.
++- make tree implementation data independent.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/mounts.h b/include/mounts.h
+index ac480c06..71d29566 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -51,10 +51,36 @@ extern const unsigned int t_indirect;
+ extern const unsigned int t_direct;
+ extern const unsigned int t_offset;
+
++struct mnt_list;
+ struct mapent;
+
++struct tree_ops;
++
++struct tree_node {
++ struct tree_ops *ops;
++ struct tree_node *left;
++ struct tree_node *right;
++};
++#define INIT_TREE_NODE(ptr) ((ptr)->ops = NULL, (ptr)->left = NULL, (ptr)->right = NULL)
++
++#define MNT_LIST(n) (container_of(n, struct mnt_list, node))
++#define MNT_LIST_NODE(ptr) ((struct tree_node *) &((struct mnt_list *) ptr)->node)
++
++typedef struct tree_node *(*tree_new_t) (void *ptr);
++typedef int (*tree_cmp_t) (struct tree_node *n, void *ptr);
++typedef void (*tree_free_t) (struct tree_node *n);
++
++struct tree_ops {
++ tree_new_t new;
++ tree_cmp_t cmp;
++ tree_free_t free;
++};
++
++typedef int (*tree_work_fn_t) (struct tree_node *n, void *ptr);
++
+ struct mnt_list {
+ char *mp;
++ size_t len;
+ unsigned int flags;
+
+ /* Hash of all mounts */
+@@ -79,6 +105,9 @@ struct mnt_list {
+ unsigned int amd_cache_opts;
+ struct list_head amdmount;
+
++ /* Tree operations */
++ struct tree_node node;
++
+ /*
+ * List operations ie. get_mnt_list.
+ */
+diff --git a/lib/mounts.c b/lib/mounts.c
+index b478ecb4..a6d1c5a7 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -68,6 +68,17 @@ static pthread_mutex_t ext_mount_hash_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static DEFINE_HASHTABLE(mnts_hash, MNTS_HASH_BITS);
+ static pthread_mutex_t mnts_hash_mutex = PTHREAD_MUTEX_INITIALIZER;
+
++static struct tree_node *tree_mnt_new(void *ptr);
++static int tree_mnt_cmp(struct tree_node *n, void *ptr);
++static void tree_mnt_free(struct tree_node *n);
++
++static struct tree_ops mnt_ops = {
++ .new = tree_mnt_new,
++ .cmp = tree_mnt_cmp,
++ .free = tree_mnt_free,
++};
++static struct tree_ops *tree_mnt_ops = &mnt_ops;
++
+ unsigned int linux_version_code(void)
+ {
+ struct utsname my_utsname;
+@@ -904,6 +915,7 @@ static struct mnt_list *mnts_alloc_mount(const char *mp)
+ this = NULL;
+ goto done;
+ }
++ this->len = strlen(mp);
+
+ this->ref = 1;
+ INIT_HLIST_NODE(&this->hash);
+@@ -912,6 +924,7 @@ static struct mnt_list *mnts_alloc_mount(const char *mp)
+ INIT_LIST_HEAD(&this->submount_work);
+ INIT_LIST_HEAD(&this->amdmount);
+ INIT_LIST_HEAD(&this->expire);
++ INIT_TREE_NODE(&this->node);
+ done:
+ return this;
+ }
+@@ -1225,91 +1238,58 @@ done:
+ return has_mounted_mounts;
+ }
+
+-struct tree_node {
+- struct mnt_list *mnt;
+- struct tree_node *left;
+- struct tree_node *right;
+-};
+-
+-static struct tree_node *tree_new(struct mnt_list *mnt)
++static inline struct tree_node *tree_root(struct tree_ops *ops, void *ptr)
+ {
+- struct tree_node *n;
+-
+- n = malloc(sizeof(struct tree_node));
+- if (!n)
+- return NULL;
+- memset(n, 0, sizeof(struct tree_node));
+- n->mnt = mnt;
+-
+- return n;
+-}
+-
+-static struct tree_node *tree_root(struct mnt_list *mnt)
+-{
+- struct tree_node *n;
+-
+- n = tree_new(mnt);
+- if (!n) {
+- error(LOGOPT_ANY, "failed to allcate tree root");
+- return NULL;
+- }
+-
+- return n;
++ return ops->new(ptr);
+ }
+
+-static struct tree_node *tree_add_left(struct tree_node *n, struct mnt_list *mnt)
++static struct tree_node *tree_add_left(struct tree_node *n, void *ptr)
+ {
+ struct tree_node *new;
+
+- new = tree_new(mnt);
+- if (!new) {
+- error(LOGOPT_ANY, "failed to allcate tree node");
+- return NULL;
+- }
++ new = n->ops->new(ptr);
+ n->left = new;
+
+- return n;
++ return new;
+ }
+
+-static struct tree_node *tree_add_right(struct tree_node *n, struct mnt_list *mnt)
++static struct tree_node *tree_add_right(struct tree_node *n, void *ptr)
+ {
+ struct tree_node *new;
+
+- new = tree_new(mnt);
+- if (!new) {
+- error(LOGOPT_ANY, "failed to allcate tree node");
+- return NULL;
+- }
++ new = n->ops->new(ptr);
+ n->right = new;
+
+- return n;
++ return new;
+ }
+
+-static struct tree_node *tree_add_node(struct tree_node *root, struct mnt_list *mnt)
++static struct tree_node *tree_add_node(struct tree_node *root, void *ptr)
+ {
+ struct tree_node *p, *q;
+- unsigned int mp_len;
+-
+- mp_len = strlen(mnt->mp);
++ struct tree_ops *ops = root->ops;
++ int eq;
+
+ q = root;
+ p = root;
+
+- while (q && strcmp(mnt->mp, p->mnt->mp)) {
++ while (q) {
+ p = q;
+- if (mp_len < strlen(p->mnt->mp))
++ eq = ops->cmp(p, ptr);
++ if (!eq)
++ break;
++ if (eq < 0)
+ q = p->left;
+ else
+ q = p->right;
+ }
+
+- if (strcmp(mnt->mp, p->mnt->mp) == 0)
+- error(LOGOPT_ANY, "duplicate entry in mounts list");
++ if (!eq)
++ error(LOGOPT_ANY, "cannot add duplicate entry to tree");
+ else {
+- if (mp_len < strlen(p->mnt->mp))
+- return tree_add_left(p, mnt);
++ if (eq < 0)
++ return tree_add_left(p, ptr);
+ else
+- return tree_add_right(p, mnt);
++ return tree_add_right(p, ptr);
+ }
+
+ return NULL;
+@@ -1317,26 +1297,92 @@ static struct tree_node *tree_add_node(struct tree_node *root, struct mnt_list *
+
+ static void tree_free(struct tree_node *root)
+ {
++ struct tree_ops *ops = root->ops;
++
+ if (root->right)
+ tree_free(root->right);
+ if (root->left)
+ tree_free(root->left);
+- free(root);
++ ops->free(root);
+ }
+
+-static void tree_traverse(struct tree_node *n, struct list_head *mnts)
++static int tree_traverse_inorder(struct tree_node *n, tree_work_fn_t work, void *ptr)
+ {
+- if (n->right)
+- tree_traverse(n->right, mnts);
+- list_add_tail(&n->mnt->expire, mnts);
+- if (n->left)
+- tree_traverse(n->left, mnts);
++ int ret;
++
++ if (n->left) {
++ ret = tree_traverse_inorder(n->left, work, ptr);
++ if (!ret)
++ goto done;
++ }
++ ret = work(n, ptr);
++ if (!ret)
++ goto done;
++ if (n->right) {
++ ret = tree_traverse_inorder(n->right, work, ptr);
++ if (!ret)
++ goto done;
++ }
++done:
++ return ret;
++}
++
++static struct tree_node *tree_mnt_root(struct mnt_list *mnt)
++{
++ return tree_root(tree_mnt_ops, mnt);
++}
++
++static struct tree_node *tree_mnt_new(void *ptr)
++{
++ struct tree_node *n = MNT_LIST_NODE(ptr);
++
++ n->ops = tree_mnt_ops;
++ n->left = NULL;
++ n->right = NULL;
++
++ return n;
++}
++
++static int tree_mnt_cmp(struct tree_node *n, void *ptr)
++{
++ struct mnt_list *n_mnt = MNT_LIST(n);
++ size_t n_mnt_len = n_mnt->len;
++ struct mnt_list *mnt = ptr;
++ size_t mnt_len = mnt->len;
++ int eq;
++
++ eq = strcmp(mnt->mp, n_mnt->mp);
++ if (!eq)
++ return 0;
++ return (mnt_len < n_mnt_len) ? -1 : 1;
++}
++
++static void tree_mnt_free(struct tree_node *n)
++{
++ n->ops = NULL;
++ n->left = NULL;
++ n->right = NULL;
++}
++
++static int tree_mnt_expire_list_work(struct tree_node *n, void *ptr)
++{
++ struct mnt_list *mnt = MNT_LIST(n);
++ struct list_head *mnts = ptr;
++
++ /* The expire of the root offset of an offset tree is the same
++ * as expiring the offset tree root itself (if theree is a root
++ * offset).
++ */
++ if (mnt->mp[mnt->len - 1] != '/')
++ list_add(&mnt->expire, mnts);
++
++ return 1;
+ }
+
+ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap)
+ {
+- struct mnt_list *mnt;
+ struct tree_node *tree = NULL;
++ struct mnt_list *mnt;
+
+ mnts_hash_mutex_lock();
+ if (list_empty(&ap->mounts))
+@@ -1351,7 +1397,7 @@ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap)
+ __mnts_get_mount(mnt);
+
+ if (!tree) {
+- tree = tree_root(mnt);
++ tree = tree_mnt_root(mnt);
+ if (!tree) {
+ error(LOGOPT_ANY, "failed to create expire tree root");
+ goto done;
+@@ -1367,7 +1413,7 @@ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap)
+ }
+ }
+
+- tree_traverse(tree, mnts);
++ tree_traverse_inorder(tree, tree_mnt_expire_list_work, mnts);
+ tree_free(tree);
+ done:
+ mnts_hash_mutex_unlock();
--- /dev/null
+autofs-5.1.7 - move amd mounts removal into lib/mounts.c
+
+From: Ian Kent <raven@themaw.net>
+
+Move the amd mounts removal from master_free_autofs_point() into
+lib/mounts.c along with the rest of the amd mount handling.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/master.c | 12 +-----------
+ include/mounts.h | 1 +
+ lib/mounts.c | 28 ++++++++++++++++++++++++----
+ 4 files changed, 27 insertions(+), 15 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 002da042..a9209755 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -46,6 +46,7 @@
+ - use mount_fullpath() in one spot in parse_mount().
+ - pass root length to mount_fullpath().
+ - remove unused function master_submount_list_empty().
++- move amd mounts removal into lib/mounts.c.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/master.c b/daemon/master.c
+index af9cd79f..b288e070 100644
+--- a/daemon/master.c
++++ b/daemon/master.c
+@@ -143,22 +143,12 @@ int master_add_autofs_point(struct master_mapent *entry, unsigned logopt,
+
+ void master_free_autofs_point(struct autofs_point *ap)
+ {
+- struct list_head *p, *head;
+ int status;
+
+ if (!ap)
+ return;
+
+- mounts_mutex_lock(ap);
+- head = &ap->amdmounts;
+- p = head->next;
+- while (p != head) {
+- struct mnt_list *mnt = list_entry(p, struct mnt_list, amdmount);
+- p = p->next;
+- ext_mount_remove(mnt->ext_mp);
+- mnts_remove_amdmount(mnt->mp);
+- }
+- mounts_mutex_unlock(ap);
++ mnts_remove_amdmounts(ap);
+
+ status = pthread_mutex_destroy(&ap->mounts_mutex);
+ if (status)
+diff --git a/include/mounts.h b/include/mounts.h
+index d7980976..1b376b3d 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -161,6 +161,7 @@ void mnts_remove_submount(const char *mp);
+ struct mnt_list *mnts_find_amdmount(const char *path);
+ struct mnt_list *mnts_add_amdmount(struct autofs_point *ap, struct amd_entry *entry);
+ void mnts_remove_amdmount(const char *mp);
++void mnts_remove_amdmounts(struct autofs_point *ap);
+ struct mnt_list *mnts_add_mount(struct autofs_point *ap, const char *name, unsigned int flags);
+ void mnts_remove_mount(const char *mp, unsigned int flags);
+ struct mnt_list *get_mnt_list(const char *path, int include);
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 6b8e4c92..c8a7bf00 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1144,14 +1144,13 @@ fail:
+ return NULL;
+ }
+
+-void mnts_remove_amdmount(const char *mp)
++static void __mnts_remove_amdmount(const char *mp)
+ {
+ struct mnt_list *this;
+
+- mnts_hash_mutex_lock();
+ this = mnts_lookup(mp);
+ if (!(this && this->flags & MNTS_AMD_MOUNT))
+- goto done;
++ return;
+ this->flags &= ~MNTS_AMD_MOUNT;
+ list_del_init(&this->amdmount);
+ if (this->ext_mp) {
+@@ -1172,7 +1171,28 @@ void mnts_remove_amdmount(const char *mp)
+ }
+ this->amd_cache_opts = 0;
+ __mnts_put_mount(this);
+-done:
++}
++
++void mnts_remove_amdmount(const char *mp)
++{
++ mnts_hash_mutex_lock();
++ __mnts_remove_amdmount(mp);
++ mnts_hash_mutex_unlock();
++}
++
++void mnts_remove_amdmounts(struct autofs_point *ap)
++{
++ struct list_head *head, *p;
++
++ mnts_hash_mutex_lock();
++ head = &ap->amdmounts;
++ p = head->next;
++ while (p != head) {
++ struct mnt_list *mnt = list_entry(p, struct mnt_list, amdmount);
++ p = p->next;
++ ext_mount_remove(mnt->ext_mp);
++ __mnts_remove_amdmount(mnt->mp);
++ }
+ mnts_hash_mutex_unlock();
+ }
+
--- /dev/null
+autofs-5.1.7 - pass mapent_cache to update_offset_entry()
+
+From: Ian Kent <raven@themaw.net>
+
+Pass mapent_cache to update_offset_entry() rather than use the wait/signal
+mechanism, it isn't needed here.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 22 ++++++----------------
+ 2 files changed, 7 insertions(+), 16 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 6e0edd74..c60a9ed3 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -17,6 +17,7 @@
+ - fix mnts_get_expire_list() expire list construction.
+ - fix inconsistent locking in umount_subtree_mounts().
+ - fix return from umount_subtree_mounts() on offset list delete.
++- pass mapent_cache to update_offset_entry().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 1142e8a3..95251bee 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -793,24 +793,17 @@ static int check_is_multi(const char *mapent)
+ }
+
+ static int
+-update_offset_entry(struct autofs_point *ap, const char *name,
++update_offset_entry(struct autofs_point *ap,
++ struct mapent_cache *mc, const char *name,
+ const char *m_root, int m_root_len,
+- const char *path, const char *myoptions, const char *loc,
+- time_t age)
++ const char *path, const char *myoptions,
++ const char *loc, time_t age)
+ {
+- struct map_source *source;
+- struct mapent_cache *mc;
+ char m_key[PATH_MAX + 1];
+ char m_mapent[MAPENT_MAX_LEN + 1];
+ int p_len, m_key_len, m_options_len, m_mapent_len;
+ int ret;
+
+- source = ap->entry->current;
+- ap->entry->current = NULL;
+- master_source_current_signal(ap->entry);
+-
+- mc = source->mc;
+-
+ memset(m_mapent, 0, MAPENT_MAX_LEN + 1);
+
+ /* Internal hosts map may have loc == NULL */
+@@ -1574,11 +1567,8 @@ dont_expand:
+ p += l;
+ p = skipspace(p);
+
+- master_source_current_wait(ap->entry);
+- ap->entry->current = source;
+-
+- status = update_offset_entry(ap, name,
+- m_root, m_root_len,
++ status = update_offset_entry(ap, mc,
++ name, m_root, m_root_len,
+ path, myoptions, loc, age);
+
+ if (status != CHE_OK) {
--- /dev/null
+autofs-5.1.7 - pass root length to mount_fullpath()
+
+From: Ian Kent <raven@themaw.net>
+
+The length of root may already be known, add a parameter to allow
+passing it to mount_fullpath() so a strlen() call can be avoided.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/mounts.h | 2 +-
+ lib/mounts.c | 11 +++++++----
+ modules/mount_bind.c | 2 +-
+ modules/mount_changer.c | 2 +-
+ modules/mount_ext2.c | 2 +-
+ modules/mount_generic.c | 2 +-
+ modules/mount_nfs.c | 2 +-
+ modules/parse_sun.c | 4 ++--
+ 9 files changed, 16 insertions(+), 12 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 8494f0dc..1c9e2a2d 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -44,6 +44,7 @@
+ - remove obsolete functions.
+ - remove redundant local var from sun_mount().
+ - use mount_fullpath() in one spot in parse_mount().
++- pass root length to mount_fullpath().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/mounts.h b/include/mounts.h
+index ec895e1c..d7980976 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -131,7 +131,7 @@ int check_nfs_mount_version(struct nfs_mount_vers *, struct nfs_mount_vers *);
+ extern unsigned int nfs_mount_uses_string_options;
+
+ int mount_fullpath(char *fullpath, size_t max_len,
+- const char *root, const char *name);
++ const char *root, size_t root_len, const char *name);
+
+ struct amd_entry;
+
+diff --git a/lib/mounts.c b/lib/mounts.c
+index c120d2a8..6b8e4c92 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -362,11 +362,14 @@ int check_nfs_mount_version(struct nfs_mount_vers *vers,
+ #endif
+
+ int mount_fullpath(char *fullpath, size_t max_len,
+- const char *root, const char *name)
++ const char *root, size_t root_len, const char *name)
+ {
+ int last, len;
+
+- last = strlen(root) - 1;
++ if (root_len)
++ last = root_len - 1;
++ else
++ last = strlen(root) - 1;
+
+ /* Root offset of multi-mount or direct or offset mount.
+ * Direct or offset mount, name (or root) is absolute path.
+@@ -1685,7 +1688,7 @@ void tree_mapent_cleanup_offsets(struct mapent *oe)
+ else {
+ char mp[PATH_MAX + 1];
+
+- if (!mount_fullpath(mp, PATH_MAX, ap->path, oe->key))
++ if (!mount_fullpath(mp, PATH_MAX, ap->path, ap->len, oe->key))
+ error(ap->logopt, "mount path is too long");
+ else
+ tree_mapent_umount_mount(ap, mp);
+@@ -1922,7 +1925,7 @@ int tree_mapent_umount_offsets(struct mapent *oe, int nonstrict)
+ * one of these keys is the root of a multi-mount the mount
+ * path must be constructed.
+ */
+- if (!mount_fullpath(mp, PATH_MAX, ap->path, oe->key)) {
++ if (!mount_fullpath(mp, PATH_MAX, ap->path, ap->len, oe->key)) {
+ error(ap->logopt, "mount path is too long");
+ return 0;
+ }
+diff --git a/modules/mount_bind.c b/modules/mount_bind.c
+index c17c6f18..7f64332b 100644
+--- a/modules/mount_bind.c
++++ b/modules/mount_bind.c
+@@ -122,7 +122,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ }
+ }
+
+- len = mount_fullpath(fullpath, PATH_MAX, root, name);
++ len = mount_fullpath(fullpath, PATH_MAX, root, 0, name);
+ if (!len) {
+ error(ap->logopt,
+ MODPREFIX "mount point path too long");
+diff --git a/modules/mount_changer.c b/modules/mount_changer.c
+index d02b5f45..8adb9f9a 100644
+--- a/modules/mount_changer.c
++++ b/modules/mount_changer.c
+@@ -59,7 +59,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+
+ fstype = "iso9660";
+
+- len = mount_fullpath(fullpath, PATH_MAX, root, name);
++ len = mount_fullpath(fullpath, PATH_MAX, root, 0, name);
+ if (!len) {
+ error(ap->logopt,
+ MODPREFIX "mount point path too long");
+diff --git a/modules/mount_ext2.c b/modules/mount_ext2.c
+index 53e6ee10..f4002e58 100644
+--- a/modules/mount_ext2.c
++++ b/modules/mount_ext2.c
+@@ -55,7 +55,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ if (defaults_get_mount_verbose())
+ mountlog = &log_info;
+
+- len = mount_fullpath(fullpath, PATH_MAX, root, name);
++ len = mount_fullpath(fullpath, PATH_MAX, root, 0, name);
+ if (!len) {
+ error(ap->logopt,
+ MODPREFIX "mount point path too long");
+diff --git a/modules/mount_generic.c b/modules/mount_generic.c
+index c9deb7ae..8cd0f4ab 100644
+--- a/modules/mount_generic.c
++++ b/modules/mount_generic.c
+@@ -54,7 +54,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ if (defaults_get_mount_verbose())
+ mountlog = &log_info;
+
+- len = mount_fullpath(fullpath, PATH_MAX, root, name);
++ len = mount_fullpath(fullpath, PATH_MAX, root, 0, name);
+ if (!len) {
+ error(ap->logopt,
+ MODPREFIX "mount point path too long");
+diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
+index c70210f4..0314a78f 100644
+--- a/modules/mount_nfs.c
++++ b/modules/mount_nfs.c
+@@ -213,7 +213,7 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name, int
+ }
+
+ /* Construct mount point directory */
+- len = mount_fullpath(fullpath, PATH_MAX, root, name);
++ len = mount_fullpath(fullpath, PATH_MAX, root, 0, name);
+ if (!len) {
+ error(ap->logopt,
+ MODPREFIX "mount point path too long");
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index d3fc6c7f..b1c2611c 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1089,7 +1089,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ struct mapent *ro;
+ size_t len;
+
+- len = mount_fullpath(key, PATH_MAX, ap->path, me->key);
++ len = mount_fullpath(key, PATH_MAX, ap->path, ap->len, me->key);
+ if (!len) {
+ warn(ap->logopt, "path loo long");
+ return 1;
+@@ -1359,7 +1359,7 @@ dont_expand:
+ time_t age;
+ int l;
+
+- m_root_len = mount_fullpath(m_root, PATH_MAX, ap->path, name);
++ m_root_len = mount_fullpath(m_root, PATH_MAX, ap->path, ap->len, name);
+ if (!m_root_len) {
+ error(ap->logopt,
+ MODPREFIX "multi-mount root path too long");
--- /dev/null
+autofs-5.1.7 - reduce umount EBUSY check delay
+
+From: Ian Kent <raven@themaw.net>
+
+Some time ago I had to wait and retry umount() for autofs mounts
+becuase I found EBUSY would be returned for a time after the call
+causing false negative umount returns.
+
+I think that problem has been resolved but removing the retry is
+probably a little risky.
+
+But the wait time is quite long at one fifth of a second so reduce
+that to one twentieth of a second and increase the retries to make
+it more resposive.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/direct.c | 4 ++--
+ daemon/indirect.c | 2 +-
+ include/automount.h | 2 +-
+ 4 files changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index b144f6aa..6419052d 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -23,6 +23,7 @@
+ - eliminate count_mounts() from expire_proc_indirect().
+ - eliminate some strlen calls in offset handling.
+ - don't add offset mounts to mounted mounts table.
++- reduce umount EBUSY check delay.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/direct.c b/daemon/direct.c
+index fbfebbdd..5c1146a7 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -150,7 +150,7 @@ int do_umount_autofs_direct(struct autofs_point *ap, struct mapent *me)
+
+ retries = UMOUNT_RETRIES;
+ while ((rv = umount(me->key)) == -1 && retries--) {
+- struct timespec tm = {0, 200000000};
++ struct timespec tm = {0, 50000000};
+ if (errno != EBUSY)
+ break;
+ nanosleep(&tm, NULL);
+@@ -573,7 +573,7 @@ int umount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+
+ retries = UMOUNT_RETRIES;
+ while ((rv = umount(me->key)) == -1 && retries--) {
+- struct timespec tm = {0, 200000000};
++ struct timespec tm = {0, 50000000};
+ if (errno != EBUSY)
+ break;
+ nanosleep(&tm, NULL);
+diff --git a/daemon/indirect.c b/daemon/indirect.c
+index eddcfff7..9f2ca6a0 100644
+--- a/daemon/indirect.c
++++ b/daemon/indirect.c
+@@ -265,7 +265,7 @@ int umount_autofs_indirect(struct autofs_point *ap, const char *root)
+
+ retries = UMOUNT_RETRIES;
+ while ((rv = umount(mountpoint)) == -1 && retries--) {
+- struct timespec tm = {0, 200000000};
++ struct timespec tm = {0, 50000000};
+ if (errno != EBUSY)
+ break;
+ nanosleep(&tm, NULL);
+diff --git a/include/automount.h b/include/automount.h
+index 69445b92..fa6f5d63 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -140,7 +140,7 @@ struct autofs_point;
+ #define NULL_MAP_HASHSIZE 64
+ #define NEGATIVE_TIMEOUT 10
+ #define POSITIVE_TIMEOUT 120
+-#define UMOUNT_RETRIES 8
++#define UMOUNT_RETRIES 16
+ #define EXPIRE_RETRIES 3
+
+ struct mapent_cache {
--- /dev/null
+autofs-5.1.7 - refactor lookup_prune_one_cache() a bit
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: use: Using an unreliable value of "me" inside the second locked
+ section.
+
+Change lookup_prune_one_cache() a little, move the location the next
+key is set (before releasing the lock) and add a comment explaining
+why we don't care about the side effects of the read lock release/
+write lock aquire/write lock release/read lock reaquire.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/lookup.c | 20 +++++++++++++++++++-
+ 2 files changed, 20 insertions(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 81461978..b79aebc8 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -63,6 +63,7 @@
+ - fix arg not used in error print.
+ - fix missing lock release in mount_subtree().
+ - fix double free in parse_mapent().
++- refactor lookup_prune_one_cache() a bit.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index 32dbc24d..3e9722e4 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -1375,7 +1375,6 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti
+ }
+
+ key = strdup(me->key);
+- me = cache_enumerate(mc, me);
+ /* Don't consider any entries with a wildcard */
+ if (!key || strchr(key, '*')) {
+ if (key)
+@@ -1422,6 +1421,7 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti
+ if (valid)
+ cache_unlock(valid->mc);
+
++ me = cache_enumerate(mc, me);
+ if (me)
+ next_key = strdup(me->key);
+
+@@ -1456,6 +1456,24 @@ void lookup_prune_one_cache(struct autofs_point *ap, struct mapent_cache *mc, ti
+ next:
+ cache_readlock(mc);
+ if (next_key) {
++ /* The lock release and reaquire above can mean
++ * a number of things could happen.
++ *
++ * First, mapents could be added between the
++ * current mapent and the mapent of next_key.
++ * Don't care about that because there's no
++ * need to prune newly added entries.
++ *
++ * Second, the next mapent data could have
++ * changed. Don't care about that either since
++ * we are looking to prune stale map entries
++ * and don't care when they become stale.
++ *
++ * Finally, the mapent of next_key could have
++ * gone away. Again don't care about this either,
++ * the loop will exit prematurely so just wait
++ * until the next prune and try again.
++ */
+ me = cache_lookup_distinct(mc, next_key);
+ free(next_key);
+ }
--- /dev/null
+autofs-5.1.7 - refactor umount_multi_triggers()
+
+From: Ian Kent <raven@themaw.net>
+
+Refactor umount_multi_triggers() to try the umount of an offset subtree
+in a seperate function.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1
+ lib/mounts.c | 187 ++++++++++++++++++++++++++++++++--------------------------
+ 2 files changed, 104 insertions(+), 84 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 3eda995c..5a3bedc1 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -11,6 +11,7 @@
+ - set offset parent in update_offset_entry().
+ - remove redundant variables from mount_autofs_offset().
+ - remove unused parameter form do_mount_autofs_offset().
++- refactor umount_multi_triggers().
+
+ 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 8e88182f..5268ba5b 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2496,57 +2496,6 @@ static int do_mount_autofs_offset(struct autofs_point *ap,
+ return mounted;
+ }
+
+-int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
+- const char *root, unsigned int start, const char *base)
+-{
+- char path[PATH_MAX + 1];
+- char *offset = path;
+- struct mapent *oe;
+- struct list_head *pos = NULL;
+- unsigned int root_len = strlen(root);
+- int mounted;
+-
+- mounted = 0;
+- offset = cache_get_offset(base, offset, start, &me->multi_list, &pos);
+- while (offset) {
+- char key[PATH_MAX + 1];
+- int key_len = root_len + strlen(offset);
+-
+- if (key_len > PATH_MAX) {
+- warn(ap->logopt, "path loo long");
+- goto cont;
+- }
+-
+- /* 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;
+-
+- mounted += do_mount_autofs_offset(ap, oe, root);
+-
+- /*
+- * If re-constructing a multi-mount it's necessary to walk
+- * into nested mounts, unlike the usual "mount only what's
+- * needed as you go" behavior.
+- */
+- if (ap->state == ST_READMAP && ap->flags & MOUNT_FLAG_REMOUNT) {
+- if (oe->ioctlfd != -1 ||
+- is_mounted(oe->key, MNTS_REAL))
+- mount_multi_triggers(ap, oe, key, strlen(key), base);
+- }
+-cont:
+- offset = cache_get_offset(base,
+- offset, start, &me->multi_list, &pos);
+- }
+-
+- return mounted;
+-}
+-
+ static int rmdir_path_offset(struct autofs_point *ap, struct mapent *oe)
+ {
+ char *dir, *path;
+@@ -2582,7 +2531,10 @@ static int rmdir_path_offset(struct autofs_point *ap, struct mapent *oe)
+ return ret;
+ }
+
+-int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root, const char *base)
++static int do_umount_offset(struct autofs_point *ap, struct mapent *oe, const char *root);
++
++static int do_umount_multi_triggers(struct autofs_point *ap,
++ struct mapent *me, const char *root, const char *base)
+ {
+ char path[PATH_MAX + 1];
+ char *offset;
+@@ -2612,7 +2564,6 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
+ 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;
+
+ if (mm_base_len > 1)
+ key_len += mm_base_len;
+@@ -2632,47 +2583,116 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
+ if (!oe || (strlen(oe->key) - start) == 1)
+ continue;
+
++ left += do_umount_offset(ap, oe, root);
++ }
++
++ return left;
++}
++
++static int do_umount_offset(struct autofs_point *ap, struct mapent *oe, const char *root)
++{
++ char *oe_base;
++ int left = 0;
++
++ /*
++ * Check for and umount subtree offsets resulting from
++ * nonstrict mount fail.
++ */
++ oe_base = oe->key + strlen(root);
++ left += do_umount_multi_triggers(ap, oe, root, oe_base);
++
++ if (oe->ioctlfd != -1 ||
++ is_mounted(oe->key, MNTS_REAL)) {
++ left++;
++ return left;
++ }
++
++ debug(ap->logopt, "umount offset %s", oe->key);
++
++ if (umount_autofs_offset(ap, oe)) {
++ warn(ap->logopt, "failed to umount offset");
++ left++;
++ } else {
++ struct stat st;
++ int ret;
++
++ if (!(oe->flags & MOUNT_FLAG_DIR_CREATED))
++ return left;
++
+ /*
+- * Check for and umount subtree offsets resulting from
+- * nonstrict mount fail.
++ * An error due to partial directory removal is
++ * ok so only try and remount the offset if the
++ * actual mount point still exists.
+ */
+- oe_base = oe->key + strlen(root);
+- left += umount_multi_triggers(ap, oe, root, oe_base);
++ ret = rmdir_path_offset(ap, oe);
++ if (ret == -1 && !stat(oe->key, &st)) {
++ ret = do_mount_autofs_offset(ap, oe, root);
++ if (ret)
++ left++;
++ /* But we did origianlly create this */
++ oe->flags |= MOUNT_FLAG_DIR_CREATED;
++ }
++ }
++ return left;
++}
+
+- if (oe->ioctlfd != -1 ||
+- is_mounted(oe->key, MNTS_REAL)) {
+- left++;
+- continue;
++int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
++ const char *root, unsigned int start, const char *base)
++{
++ char path[PATH_MAX + 1];
++ char *offset = path;
++ struct mapent *oe;
++ struct list_head *pos = NULL;
++ unsigned int root_len = strlen(root);
++ int mounted;
++
++ mounted = 0;
++ offset = cache_get_offset(base, offset, start, &me->multi_list, &pos);
++ while (offset) {
++ char key[PATH_MAX + 1];
++ int key_len = root_len + strlen(offset);
++
++ if (key_len > PATH_MAX) {
++ warn(ap->logopt, "path loo long");
++ goto cont;
+ }
+
+- debug(ap->logopt, "umount offset %s", oe->key);
++ /* The root offset is always mounted seperately so the
++ * offset path will always be root + offset.
++ */
++ strcpy(key, root);
++ strcat(key, offset);
+
+- if (umount_autofs_offset(ap, oe)) {
+- warn(ap->logopt, "failed to umount offset");
+- left++;
+- } else {
+- struct stat st;
+- int ret;
++ oe = cache_lookup_distinct(me->mc, key);
++ if (!oe || !oe->mapent)
++ goto cont;
+
+- if (!(oe->flags & MOUNT_FLAG_DIR_CREATED))
+- continue;
++ mounted += do_mount_autofs_offset(ap, oe, root);
+
+- /*
+- * An error due to partial directory removal is
+- * ok so only try and remount the offset if the
+- * actual mount point still exists.
+- */
+- ret = rmdir_path_offset(ap, oe);
+- if (ret == -1 && !stat(oe->key, &st)) {
+- ret = do_mount_autofs_offset(ap, oe, root);
+- if (ret)
+- left++;
+- /* But we did origianlly create this */
+- oe->flags |= MOUNT_FLAG_DIR_CREATED;
+- }
++ /*
++ * If re-constructing a multi-mount it's necessary to walk
++ * into nested mounts, unlike the usual "mount only what's
++ * needed as you go" behavior.
++ */
++ if (ap->state == ST_READMAP && ap->flags & MOUNT_FLAG_REMOUNT) {
++ if (oe->ioctlfd != -1 ||
++ is_mounted(oe->key, MNTS_REAL))
++ mount_multi_triggers(ap, oe, key, strlen(key), base);
+ }
++cont:
++ offset = cache_get_offset(base,
++ offset, start, &me->multi_list, &pos);
+ }
+
++ return mounted;
++}
++
++int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root, const char *base)
++{
++ int left;
++
++ left = do_umount_multi_triggers(ap, me, root, base);
++
+ if (!left && me->multi == me) {
+ struct mapent_cache *mc = me->mc;
+ int status;
+@@ -2871,4 +2891,3 @@ int clean_stale_multi_triggers(struct autofs_point *ap,
+
+ return left;
+ }
+-
--- /dev/null
+autofs-5.1.7 - remove mount.x and rpcgen dependencies
+
+From: Ian Kent <raven@themaw.net>
+
+Adding a local implementation to get the exports list from a server
+means the the rpcgen generataed code is no longer needed so remove
+mount.x and the build dependencies.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1
+ Makefile.conf.in | 1
+ autofs.spec | 2
+ configure | 58 ---------
+ configure.in | 1
+ include/automount.h | 1
+ include/config.h.in | 3
+ lib/Makefile | 26 ----
+ lib/mount.x | 345 ---------------------------------------------------
+ 9 files changed, 5 insertions(+), 433 deletions(-)
+ delete mode 100644 lib/mount.x
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 84050e91..19af245e 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -1,5 +1,6 @@
+
+ - add xdr_exports().
++- remove mount.x and rpcgen dependencies.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/Makefile.conf.in b/Makefile.conf.in
+index df678eec..12f26eb8 100644
+--- a/Makefile.conf.in
++++ b/Makefile.conf.in
+@@ -65,7 +65,6 @@ FEDFS = @ENABLE_FEDFS@
+
+ LEX = @PATH_LEX@
+ YACC = @PATH_YACC@
+-RPCGEN = @PATH_RPCGEN@
+ RANLIB = @PATH_RANLIB@
+
+ # Use libtirpc if requested and available
+diff --git a/autofs.spec b/autofs.spec
+index 3c2b144a..823735a3 100644
+--- a/autofs.spec
++++ b/autofs.spec
+@@ -39,7 +39,7 @@ BuildRequires: libtirpc-devel
+ %endif
+ BuildRequires: autoconf, openldap-devel, bison, flex, libxml2-devel
+ BuildRequires: cyrus-sasl-devel, openssl-devel, util-linux
+-BuildRequires: libtirpc-devel, rpcgen, libnsl2-devel, krb5-devel
++BuildRequires: libtirpc-devel, libnsl2-devel, krb5-devel
+ Requires: chkconfig
+ Requires: /bin/bash sed grep /bin/ps
+ %if %{with_systemd}
+diff --git a/configure b/configure
+index de968f0e..3c5fe78b 100755
+--- a/configure
++++ b/configure
+@@ -650,8 +650,6 @@ XML_CFLAGS
+ ENABLE_FEDFS
+ sssldir
+ HAVE_SSS_AUTOFS
+-PATH_RPCGEN
+-RPCGEN
+ PATH_RANLIB
+ RANLIB
+ PATH_YACC
+@@ -4205,62 +4203,6 @@ else
+ as_fn_error $? "required program RANLIB not found" "$LINENO" 5
+ fi
+
+-for ac_prog in rpcgen
+-do
+- # Extract the first word of "$ac_prog", so it can be a program name with args.
+-set dummy $ac_prog; ac_word=$2
+-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+-$as_echo_n "checking for $ac_word... " >&6; }
+-if ${ac_cv_path_RPCGEN+:} false; then :
+- $as_echo_n "(cached) " >&6
+-else
+- case $RPCGEN in
+- [\\/]* | ?:[\\/]*)
+- ac_cv_path_RPCGEN="$RPCGEN" # Let the user override the test with a path.
+- ;;
+- *)
+- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+-for as_dir in $searchpath
+-do
+- IFS=$as_save_IFS
+- test -z "$as_dir" && as_dir=.
+- for ac_exec_ext in '' $ac_executable_extensions; do
+- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+- ac_cv_path_RPCGEN="$as_dir/$ac_word$ac_exec_ext"
+- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+- break 2
+- fi
+-done
+- done
+-IFS=$as_save_IFS
+-
+- ;;
+-esac
+-fi
+-RPCGEN=$ac_cv_path_RPCGEN
+-if test -n "$RPCGEN"; then
+- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RPCGEN" >&5
+-$as_echo "$RPCGEN" >&6; }
+-else
+- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+-$as_echo "no" >&6; }
+-fi
+-
+-
+- test -n "$RPCGEN" && break
+-done
+-
+-if test -n "$RPCGEN"; then
+-
+-cat >>confdefs.h <<_ACEOF
+-#define PATH_RPCGEN "$RPCGEN"
+-_ACEOF
+-
+- PATH_RPCGEN="$RPCGEN"
+-else
+- as_fn_error $? "required program RPCGEN not found" "$LINENO" 5
+-fi
+-
+
+ if test -z "$sssldir"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sssd autofs library" >&5
+diff --git a/configure.in b/configure.in
+index a38d6655..e774b4cc 100644
+--- a/configure.in
++++ b/configure.in
+@@ -164,7 +164,6 @@ AF_PATH_INCLUDE(E4FSCK, fsck.ext4 e4fsck, , $searchpath)
+ AF_CHECK_PROG(LEX, flex lex, , $searchpath)
+ AF_CHECK_PROG(YACC, bison, , $searchpath)
+ AF_CHECK_PROG(RANLIB, ranlib, , $searchpath)
+-AF_CHECK_PROG(RPCGEN, rpcgen, , $searchpath)
+
+ AF_CHECK_SSS_LIB(SSS_AUTOFS, libsss_autofs.so)
+ AC_SUBST(HAVE_SSS_AUTOFS)
+diff --git a/include/automount.h b/include/automount.h
+index 1ae40786..2f09e8e7 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -32,7 +32,6 @@
+ #include "macros.h"
+ #include "log.h"
+ #include "rpc_subs.h"
+-#include "mounts.h"
+ #include "parse_subs.h"
+ #include "mounts.h"
+ #include "dev-ioctl-lib.h"
+diff --git a/include/config.h.in b/include/config.h.in
+index a4879494..4e36b390 100644
+--- a/include/config.h.in
++++ b/include/config.h.in
+@@ -135,9 +135,6 @@
+ /* define if you have RANLIB */
+ #undef PATH_RANLIB
+
+-/* define if you have RPCGEN */
+-#undef PATH_RPCGEN
+-
+ /* define if you have UMOUNT */
+ #undef PATH_UMOUNT
+
+diff --git a/lib/Makefile b/lib/Makefile
+index 83a80a1e..d18c67b5 100644
+--- a/lib/Makefile
++++ b/lib/Makefile
+@@ -8,10 +8,9 @@ include ../Makefile.rules
+ SRCS = cache.c cat_path.c rpc_subs.c mounts.c log.c nsswitch.c \
+ nss_tok.c nss_parse.tab.c args.c alarm.c macros.c defaults.c \
+ parse_subs.c dev-ioctl-lib.c
+-RPCS = mount.h mount_clnt.c mount_xdr.c
+-OBJS = cache.o mount_clnt.o mount_xdr.o cat_path.o rpc_subs.o \
+- mounts.o log.o nsswitch.o nss_tok.o nss_parse.tab.o args.o \
+- alarm.o macros.o defaults.o parse_subs.o dev-ioctl-lib.o
++OBJS = cache.o cat_path.o rpc_subs.o mounts.o log.o nsswitch.o \
++ nss_tok.o nss_parse.tab.o args.o alarm.o macros.o defaults.o \
++ parse_subs.o dev-ioctl-lib.o
+
+ YACCSRC = nss_tok.c nss_parse.tab.c nss_parse.tab.h
+
+@@ -33,23 +32,6 @@ libautofs.so: $(OBJS)
+ $(CC) $(SOLDFLAGS) $(CFLAGS) -o $*.so $^ $(LDFLAGS) $(LIBS)
+ $(STRIP) $*.so
+
+-mount.h: mount.x
+- $(RPCGEN) -h -o mount.h mount.x
+-
+-mount_clnt.c: mount.h
+- $(RPCGEN) -l -o mount_clnt.c mount.x
+-
+-mount_clnt.o: mount_clnt.c
+- $(CC) $(CFLAGS) -o mount_clnt.o -c mount_clnt.c
+- $(STRIP) mount_clnt.o
+-
+-mount_xdr.c: mount.h
+- $(RPCGEN) -c -o mount_xdr.c mount.x
+-
+-mount_xdr.o: mount_xdr.c
+- $(CC) $(CFLAGS) -Wno-unused-variable -o mount_xdr.o -c mount_xdr.c
+- $(STRIP) mount_xdr.o
+-
+ nss_tok.c: nss_tok.l
+ $(LEX) -o$@ -Pnss_ $?
+
+@@ -60,8 +42,6 @@ nss_tok.o: nss_tok.c nss_parse.tab.h
+
+ nss_parse.tab.o: nss_parse.tab.c nss_parse.tab.h
+
+-rpc_subs.o: mount.h
+-
+ install: all
+ install -d -m 755 $(INSTALLROOT)$(autofslibdir)
+ install -c $(LIB) -m 755 $(INSTALLROOT)$(sharedlibdir)
+diff --git a/lib/mount.x b/lib/mount.x
+deleted file mode 100644
+index f504e7cf..00000000
+--- a/lib/mount.x
++++ /dev/null
+@@ -1,345 +0,0 @@
+-%/*
+-% * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+-% * unrestricted use provided that this legend is included on all tape
+-% * media and as a part of the software program in whole or part. Users
+-% * may copy or modify Sun RPC without charge, but are not authorized
+-% * to license or distribute it to anyone else except as part of a product or
+-% * program developed by the user or with the express written consent of
+-% * Sun Microsystems, Inc.
+-% *
+-% * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+-% * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+-% * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+-% *
+-% * Sun RPC is provided with no support and without any obligation on the
+-% * part of Sun Microsystems, Inc. to assist in its use, correction,
+-% * modification or enhancement.
+-% *
+-% * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+-% * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+-% * OR ANY PART THEREOF.
+-% *
+-% * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+-% * or profits or other special, indirect and consequential damages, even if
+-% * Sun has been advised of the possibility of such damages.
+-% *
+-% * Sun Microsystems, Inc.
+-% * 2550 Garcia Avenue
+-% * Mountain View, California 94043
+-% */
+-
+-%/*
+-% * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
+-% */
+-%
+-%/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */
+-
+-/*
+- * Protocol description for the mount program
+- */
+-
+-#ifdef RPC_HDR
+-%#ifndef _rpcsvc_mount_h
+-%#define _rpcsvc_mount_h
+-%#include <memory.h>
+-#endif
+-
+-const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */
+-const MNTNAMLEN = 255; /* maximum bytes in a name argument */
+-const FHSIZE = 32; /* size in bytes of a file handle */
+-
+-/*
+- * The fhandle is the file handle that the server passes to the client.
+- * All file operations are done using the file handles to refer to a file
+- * or a directory. The file handle can contain whatever information the
+- * server needs to distinguish an individual file.
+- */
+-typedef opaque fhandle[FHSIZE];
+-
+-/*
+- * If a status of zero is returned, the call completed successfully, and
+- * a file handle for the directory follows. A non-zero status indicates
+- * some sort of error. The status corresponds with UNIX error numbers.
+- */
+-union fhstatus switch (unsigned fhs_status) {
+-case 0:
+- fhandle fhs_fhandle;
+-default:
+- void;
+-};
+-
+-/*
+- * The type dirpath is the pathname of a directory
+- */
+-typedef string dirpath<MNTPATHLEN>;
+-
+-/*
+- * The type name is used for arbitrary names (hostnames, groupnames)
+- */
+-typedef string name<MNTNAMLEN>;
+-
+-/*
+- * A list of who has what mounted
+- */
+-typedef struct mountbody *mountlist;
+-struct mountbody {
+- name ml_hostname;
+- dirpath ml_directory;
+- mountlist ml_next;
+-};
+-
+-/*
+- * A list of netgroups
+- */
+-typedef struct groupnode *groups;
+-struct groupnode {
+- name gr_name;
+- groups gr_next;
+-};
+-
+-/*
+- * A list of what is exported and to whom
+- */
+-typedef struct exportnode *exports;
+-struct exportnode {
+- dirpath ex_dir;
+- groups ex_groups;
+- exports ex_next;
+-};
+-
+-/*
+- * POSIX pathconf information
+- */
+-struct ppathcnf {
+- int pc_link_max; /* max links allowed */
+- short pc_max_canon; /* max line len for a tty */
+- short pc_max_input; /* input a tty can eat all at once */
+- short pc_name_max; /* max file name length (dir entry) */
+- short pc_path_max; /* max path name length (/x/y/x/.. ) */
+- short pc_pipe_buf; /* size of a pipe (bytes) */
+- u_char pc_vdisable; /* safe char to turn off c_cc[i] */
+- char pc_xxx; /* alignment padding; cc_t == char */
+- short pc_mask[2]; /* validity and boolean bits */
+-};
+-
+-/*
+- * NFSv3 file handle
+- */
+-const FHSIZE3 = 64; /* max size of NFSv3 file handle in bytes */
+-typedef opaque fhandle3<FHSIZE3>;
+-
+-/*
+- * NFSv3 mount status
+- */
+-enum mountstat3 {
+- MNT_OK = 0, /* no error */
+- MNT3ERR_PERM = 1, /* not owner */
+- MNT3ERR_NOENT = 2, /* no such file or directory */
+- MNT3ERR_IO = 5, /* I/O error */
+- MNT3ERR_ACCES = 13, /* Permission denied */
+- MNT3ERR_NOTDIR = 20, /* Not a directory */
+- MNT3ERR_INVAL = 22, /* Invalid argument */
+- MNT3ERR_NAMETOOLONG = 63, /* File name too long */
+- MNT3ERR_NOTSUPP = 10004,/* Operation not supported */
+- MNT3ERR_SERVERFAULT = 10006 /* A failure on the server */
+-};
+-
+-/*
+- * NFSv3 mount result
+- */
+-struct mountres3_ok {
+- fhandle3 fhandle;
+- int auth_flavors<>;
+-};
+-
+-union mountres3 switch (mountstat3 fhs_status) {
+-case MNT_OK:
+- mountres3_ok mountinfo; /* File handle and supported flavors */
+-default:
+- void;
+-};
+-
+-program MOUNTPROG {
+- /*
+- * Version one of the mount protocol communicates with version two
+- * of the NFS protocol. The only connecting point is the fhandle
+- * structure, which is the same for both protocols.
+- */
+- version MOUNTVERS {
+- /*
+- * Does no work. It is made available in all RPC services
+- * to allow server reponse testing and timing
+- */
+- void
+- MOUNTPROC_NULL(void) = 0;
+-
+- /*
+- * If fhs_status is 0, then fhs_fhandle contains the
+- * file handle for the directory. This file handle may
+- * be used in the NFS protocol. This procedure also adds
+- * a new entry to the mount list for this client mounting
+- * the directory.
+- * Unix authentication required.
+- */
+- fhstatus
+- MOUNTPROC_MNT(dirpath) = 1;
+-
+- /*
+- * Returns the list of remotely mounted filesystems. The
+- * mountlist contains one entry for each hostname and
+- * directory pair.
+- */
+- mountlist
+- MOUNTPROC_DUMP(void) = 2;
+-
+- /*
+- * Removes the mount list entry for the directory
+- * Unix authentication required.
+- */
+- void
+- MOUNTPROC_UMNT(dirpath) = 3;
+-
+- /*
+- * Removes all of the mount list entries for this client
+- * Unix authentication required.
+- */
+- void
+- MOUNTPROC_UMNTALL(void) = 4;
+-
+- /*
+- * Returns a list of all the exported filesystems, and which
+- * machines are allowed to import it.
+- */
+- exports
+- MOUNTPROC_EXPORT(void) = 5;
+-
+- /*
+- * Identical to MOUNTPROC_EXPORT above
+- */
+- exports
+- MOUNTPROC_EXPORTALL(void) = 6;
+- } = 1;
+-
+- /*
+- * Version two of the mount protocol communicates with version two
+- * of the NFS protocol.
+- * The only difference from version one is the addition of a POSIX
+- * pathconf call.
+- */
+- version MOUNTVERS_POSIX {
+- /*
+- * Does no work. It is made available in all RPC services
+- * to allow server reponse testing and timing
+- */
+- void
+- MOUNTPROC_NULL(void) = 0;
+-
+- /*
+- * If fhs_status is 0, then fhs_fhandle contains the
+- * file handle for the directory. This file handle may
+- * be used in the NFS protocol. This procedure also adds
+- * a new entry to the mount list for this client mounting
+- * the directory.
+- * Unix authentication required.
+- */
+- fhstatus
+- MOUNTPROC_MNT(dirpath) = 1;
+-
+- /*
+- * Returns the list of remotely mounted filesystems. The
+- * mountlist contains one entry for each hostname and
+- * directory pair.
+- */
+- mountlist
+- MOUNTPROC_DUMP(void) = 2;
+-
+- /*
+- * Removes the mount list entry for the directory
+- * Unix authentication required.
+- */
+- void
+- MOUNTPROC_UMNT(dirpath) = 3;
+-
+- /*
+- * Removes all of the mount list entries for this client
+- * Unix authentication required.
+- */
+- void
+- MOUNTPROC_UMNTALL(void) = 4;
+-
+- /*
+- * Returns a list of all the exported filesystems, and which
+- * machines are allowed to import it.
+- */
+- exports
+- MOUNTPROC_EXPORT(void) = 5;
+-
+- /*
+- * Identical to MOUNTPROC_EXPORT above
+- */
+- exports
+- MOUNTPROC_EXPORTALL(void) = 6;
+-
+- /*
+- * POSIX pathconf info (Sun hack)
+- */
+- ppathcnf
+- MOUNTPROC_PATHCONF(dirpath) = 7;
+- } = 2;
+-
+- /*
+- * Version 3 of the protocol is for NFSv3
+- */
+- version MOUNTVERS_NFSV3 {
+- /*
+- * Does no work. It is made available in all RPC services
+- * to allow server reponse testing and timing
+- */
+- void
+- MOUNTPROC3_NULL(void) = 0;
+-
+- /*
+- * If fhs_status is 0, then fhs_fhandle contains the
+- * file handle for the directory. This file handle may
+- * be used in the NFS protocol. This procedure also adds
+- * a new entry to the mount list for this client mounting
+- * the directory.
+- * Unix authentication required.
+- */
+- mountres3
+- MOUNTPROC3_MNT(dirpath) = 1;
+-
+- /*
+- * Returns the list of remotely mounted filesystems. The
+- * mountlist contains one entry for each hostname and
+- * directory pair.
+- */
+- mountlist
+- MOUNTPROC3_DUMP(void) = 2;
+-
+- /*
+- * Removes the mount list entry for the directory
+- * Unix authentication required.
+- */
+- void
+- MOUNTPROC3_UMNT(dirpath) = 3;
+-
+- /*
+- * Removes all of the mount list entries for this client
+- * Unix authentication required.
+- */
+- void
+- MOUNTPROC3_UMNTALL(void) = 4;
+-
+- /*
+- * Returns a list of all the exported filesystems, and which
+- * machines are allowed to import it.
+- */
+- exports
+- MOUNTPROC3_EXPORT(void) = 5;
+- } = 3;
+-} = 100005;
+-
+-#ifdef RPC_HDR
+-%#endif /*!_rpcsvc_mount_h*/
+-#endif
--- /dev/null
+autofs-5.1.7 - remove mounts_mutex
+
+From: Ian Kent <raven@themaw.net>
+
+The mounts_mutex is no longer used, remove it.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/automount.c | 8 +-------
+ daemon/master.c | 13 -------------
+ include/automount.h | 1 -
+ modules/mount_autofs.c | 8 --------
+ 5 files changed, 2 insertions(+), 29 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 42914160..9d0f4278 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -48,6 +48,7 @@
+ - remove unused function master_submount_list_empty().
+ - move amd mounts removal into lib/mounts.c.
+ - check for offset with no mount location.
++- remove mounts_mutex.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 7833dfae..28c4d1ee 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -1754,7 +1754,6 @@ static void handle_mounts_cleanup(void *arg)
+ * here.
+ */
+ if (submount) {
+- mounts_mutex_unlock(ap->parent);
+ master_source_unlock(ap->parent->entry);
+ master_free_mapent_sources(ap->entry, 1);
+ master_free_mapent(ap->entry);
+@@ -1792,13 +1791,9 @@ static int submount_source_writelock_nested(struct autofs_point *ap)
+ if (status)
+ goto done;
+
+- mounts_mutex_lock(parent);
+-
+ status = pthread_rwlock_trywrlock(&ap->entry->source_lock);
+- if (status) {
+- mounts_mutex_unlock(parent);
++ if (status)
+ master_source_unlock(parent->entry);
+- }
+
+ done:
+ if (status && status != EBUSY) {
+@@ -1814,7 +1809,6 @@ static void submount_source_unlock_nested(struct autofs_point *ap)
+ struct autofs_point *parent = ap->parent;
+
+ master_source_unlock(ap->entry);
+- mounts_mutex_unlock(parent);
+ master_source_unlock(parent->entry);
+ }
+
+diff --git a/daemon/master.c b/daemon/master.c
+index b288e070..30d7cf98 100644
+--- a/daemon/master.c
++++ b/daemon/master.c
+@@ -69,7 +69,6 @@ int master_add_autofs_point(struct master_mapent *entry, unsigned logopt,
+ unsigned nobind, unsigned ghost, int submount)
+ {
+ struct autofs_point *ap;
+- int status;
+
+ ap = malloc(sizeof(struct autofs_point));
+ if (!ap)
+@@ -128,12 +127,6 @@ int master_add_autofs_point(struct master_mapent *entry, unsigned logopt,
+ INIT_LIST_HEAD(&ap->amdmounts);
+ ap->shutdown = 0;
+
+- status = pthread_mutex_init(&ap->mounts_mutex, NULL);
+- if (status) {
+- free(ap->path);
+- free(ap);
+- return 0;
+- }
+ ap->mode = 0;
+
+ entry->ap = ap;
+@@ -143,17 +136,11 @@ int master_add_autofs_point(struct master_mapent *entry, unsigned logopt,
+
+ void master_free_autofs_point(struct autofs_point *ap)
+ {
+- int status;
+-
+ if (!ap)
+ return;
+
+ mnts_remove_amdmounts(ap);
+
+- status = pthread_mutex_destroy(&ap->mounts_mutex);
+- if (status)
+- fatal(status);
+-
+ if (ap->pref)
+ free(ap->pref);
+ free(ap->path);
+diff --git a/include/automount.h b/include/automount.h
+index e33ee8d2..51a0bf0e 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -565,7 +565,6 @@ struct autofs_point {
+ enum states state; /* Current state */
+ int state_pipe[2]; /* State change router pipe */
+ struct autofs_point *parent; /* Owner of mounts list for submount */
+- pthread_mutex_t mounts_mutex; /* Protect mount lists */
+ struct list_head mounts; /* List of autofs mounts at current level */
+ unsigned int submount; /* Is this a submount */
+ unsigned int submnt_count; /* Number of submounts */
+diff --git a/modules/mount_autofs.c b/modules/mount_autofs.c
+index 1c40e27a..0bcbb343 100644
+--- a/modules/mount_autofs.c
++++ b/modules/mount_autofs.c
+@@ -283,8 +283,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ set_exp_timeout(nap, NULL, timeout);
+ nap->exp_runfreq = (timeout + CHECK_RATIO - 1) / CHECK_RATIO;
+
+- mounts_mutex_lock(ap);
+-
+ if (source->flags & MAP_FLAG_FORMAT_AMD) {
+ struct mnt_list *mnt;
+
+@@ -305,7 +303,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ if (handle_mounts_startup_cond_init(&suc)) {
+ crit(ap->logopt, MODPREFIX
+ "failed to init startup cond for mount %s", entry->path);
+- mounts_mutex_unlock(ap);
+ master_free_map_source(source, 1);
+ master_free_mapent(entry);
+ return 1;
+@@ -316,7 +313,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ crit(ap->logopt,
+ MODPREFIX "failed to allocate mount %s", realpath);
+ handle_mounts_startup_cond_destroy(&suc);
+- mounts_mutex_unlock(ap);
+ master_free_map_source(source, 1);
+ master_free_mapent(entry);
+ return 1;
+@@ -335,7 +331,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ realpath);
+ handle_mounts_startup_cond_destroy(&suc);
+ mnts_remove_submount(nap->path);
+- mounts_mutex_unlock(ap);
+ master_free_map_source(source, 1);
+ master_free_mapent(entry);
+ return 1;
+@@ -346,7 +341,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ if (status) {
+ handle_mounts_startup_cond_destroy(&suc);
+ mnts_remove_submount(nap->path);
+- mounts_mutex_unlock(ap);
+ master_free_map_source(source, 1);
+ master_free_mapent(entry);
+ fatal(status);
+@@ -358,7 +352,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ MODPREFIX "failed to create submount for %s", realpath);
+ handle_mounts_startup_cond_destroy(&suc);
+ mnts_remove_submount(nap->path);
+- mounts_mutex_unlock(ap);
+ master_free_map_source(source, 1);
+ master_free_mapent(entry);
+ return 1;
+@@ -368,7 +361,6 @@ int mount_mount(struct autofs_point *ap, const char *root, const char *name,
+ ap->submnt_count++;
+
+ handle_mounts_startup_cond_destroy(&suc);
+- mounts_mutex_unlock(ap);
+
+ return 0;
+ }
--- /dev/null
+autofs-5.1.7 - remove obsolete functions
+
+From: Ian Kent <raven@themaw.net>
+
+Remove the code that's no longer used due to the tree mapent
+implementation.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1
+ include/automount.h | 10 --
+ include/mounts.h | 2
+ lib/cache.c | 227 -------------------------------------
+ lib/mounts.c | 311 ---------------------------------------------------
+ modules/parse_sun.c | 56 ---------
+ 6 files changed, 2 insertions(+), 605 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 5ac09f77..76fccf70 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -41,6 +41,7 @@
+ - add set_offset_tree_catatonic().
+ - add mount and umount offsets functions.
+ - switch to use tree implementation for offsets.
++- remove obsolete functions.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/automount.h b/include/automount.h
+index a71b8674..e33ee8d2 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -162,16 +162,13 @@ struct stack {
+ struct mapent {
+ struct mapent *next;
+ struct list_head ino_index;
+- struct list_head multi_list;
+ struct mapent_cache *mc;
+ struct map_source *source;
+ /* Need to know owner if we're a multi-mount */
+ struct tree_node *mm_root;
++ /* Parent nesting point within multi-mount */
+ struct tree_node *mm_parent;
+ struct tree_node node;
+- struct mapent *multi;
+- /* Parent nesting point within multi-mount */
+- struct mapent *parent;
+ char *key;
+ size_t len;
+ char *mapent;
+@@ -209,7 +206,6 @@ struct mapent *cache_lookup_next(struct mapent_cache *mc, struct mapent *me);
+ struct mapent *cache_lookup_key_next(struct mapent *me);
+ struct mapent *cache_lookup(struct mapent_cache *mc, const char *key);
+ struct mapent *cache_lookup_distinct(struct mapent_cache *mc, const char *key);
+-struct mapent *cache_lookup_offset(const char *prefix, const char *offset, int start, struct list_head *head);
+ struct mapent *cache_partial_match(struct mapent_cache *mc, const char *prefix);
+ struct mapent *cache_partial_match_wild(struct mapent_cache *mc, const char *prefix);
+ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age);
+@@ -217,16 +213,12 @@ int cache_update_offset(struct mapent_cache *mc, const char *mkey, const char *k
+ int cache_lookup_negative(struct mapent *me, const char *key);
+ void cache_update_negative(struct mapent_cache *mc, struct map_source *ms, const char *key, time_t timeout);
+ struct mapent *cache_get_offset_parent(struct mapent_cache *mc, const char *key);
+-int cache_set_offset_parent(struct mapent_cache *mc, const char *offset);
+ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age);
+ int cache_delete(struct mapent_cache *mc, const char *key);
+-int cache_delete_offset(struct mapent_cache *mc, const char *key);
+-int cache_delete_offset_list(struct mapent_cache *mc, const char *key);
+ void cache_release(struct map_source *map);
+ void cache_clean_null_cache(struct mapent_cache *mc);
+ void cache_release_null_cache(struct master *master);
+ struct mapent *cache_enumerate(struct mapent_cache *mc, struct mapent *me);
+-char *cache_get_offset(const char *prefix, char *offset, int start, struct list_head *head, struct list_head **pos);
+
+ /* Utility functions */
+
+diff --git a/include/mounts.h b/include/mounts.h
+index e56f80ba..ec895e1c 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -187,8 +187,6 @@ void set_indirect_mount_tree_catatonic(struct autofs_point *);
+ void set_direct_mount_tree_catatonic(struct autofs_point *, struct mapent *);
+ int umount_ent(struct autofs_point *, const char *);
+ int umount_amd_ext_mount(struct autofs_point *, const char *);
+-int mount_multi_triggers(struct autofs_point *, struct mapent *, const char *, unsigned int, const char *);
+-int umount_multi_triggers(struct autofs_point *, struct mapent *, char *, const char *);
+ int clean_stale_multi_triggers(struct autofs_point *, struct mapent *, char *, const char *);
+
+ #endif
+diff --git a/lib/cache.c b/lib/cache.c
+index 93b02daf..ef761739 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -461,30 +461,6 @@ struct mapent *cache_lookup_distinct(struct mapent_cache *mc, const char *key)
+ return NULL;
+ }
+
+-/* Lookup an offset within a multi-mount entry */
+-struct mapent *cache_lookup_offset(const char *prefix, const char *offset, int start, struct list_head *head)
+-{
+- struct list_head *p;
+- struct mapent *this;
+- /* Keys for direct maps may be as long as a path name */
+- char o_key[PATH_MAX];
+- /* Avoid "//" at the beginning of paths */
+- const char *path_prefix = strlen(prefix) > 1 ? prefix : "";
+- size_t size;
+-
+- /* root offset duplicates "/" */
+- size = snprintf(o_key, sizeof(o_key), "%s%s", path_prefix, offset);
+- if (size >= sizeof(o_key))
+- return NULL;
+-
+- list_for_each(p, head) {
+- this = list_entry(p, struct mapent, multi_list);
+- if (!strcmp(&this->key[start], o_key))
+- return this;
+- }
+- return NULL;
+-}
+-
+ /* cache must be read locked by caller */
+ static struct mapent *__cache_partial_match(struct mapent_cache *mc,
+ const char *prefix,
+@@ -583,9 +559,6 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
+ me->mm_parent = NULL;
+ INIT_TREE_NODE(&me->node);
+ INIT_LIST_HEAD(&me->ino_index);
+- INIT_LIST_HEAD(&me->multi_list);
+- me->multi = NULL;
+- me->parent = NULL;
+ me->ioctlfd = -1;
+ me->dev = (dev_t) -1;
+ me->ino = (ino_t) -1;
+@@ -615,33 +588,6 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
+ return CHE_OK;
+ }
+
+-/* cache must be write locked by caller */
+-static void cache_add_ordered_offset(struct mapent *me, struct list_head *head)
+-{
+- struct list_head *p;
+- struct mapent *this;
+-
+- list_for_each(p, head) {
+- size_t tlen;
+- int eq;
+-
+- this = list_entry(p, struct mapent, multi_list);
+- tlen = strlen(this->key);
+-
+- eq = strncmp(this->key, me->key, tlen);
+- if (!eq && tlen == strlen(me->key))
+- return;
+-
+- if (eq > 0) {
+- list_add_tail(&me->multi_list, p);
+- return;
+- }
+- }
+- list_add_tail(&me->multi_list, p);
+-
+- return;
+-}
+-
+ /* cache must be write locked by caller */
+ int cache_update_offset(struct mapent_cache *mc, const char *mkey, const char *key, const char *mapent, time_t age)
+ {
+@@ -777,25 +723,6 @@ struct mapent *cache_get_offset_parent(struct mapent_cache *mc, const char *key)
+ return NULL;
+ }
+
+-int cache_set_offset_parent(struct mapent_cache *mc, const char *offset)
+-{
+- struct mapent *this, *parent;
+-
+- this = cache_lookup_distinct(mc, offset);
+- if (!this)
+- return 0;
+- if (!IS_MM(this))
+- return 0;
+-
+- parent = cache_get_offset_parent(mc, offset);
+- if (parent)
+- this->parent = parent;
+- else
+- this->parent = MM_ROOT(this);
+-
+- return 1;
+-}
+-
+ /* cache must be write locked by caller */
+ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age)
+ {
+@@ -837,50 +764,6 @@ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key
+ return ret;
+ }
+
+-/* cache write lock of the multi mount owner must be held by caller */
+-int cache_delete_offset(struct mapent_cache *mc, const char *key)
+-{
+- u_int32_t hashval = hash(key, mc->size);
+- struct mapent *me = NULL, *pred;
+- int status;
+-
+- me = mc->hash[hashval];
+- if (!me)
+- return CHE_FAIL;
+-
+- if (strcmp(key, me->key) == 0) {
+- if (IS_MM(me) && IS_MM_ROOT(me))
+- return CHE_FAIL;
+- mc->hash[hashval] = me->next;
+- goto delete;
+- }
+-
+- while (me->next != NULL) {
+- pred = me;
+- me = me->next;
+- if (strcmp(key, me->key) == 0) {
+- if (IS_MM(me) && IS_MM_ROOT(me))
+- return CHE_FAIL;
+- pred->next = me->next;
+- goto delete;
+- }
+- }
+-
+- return CHE_FAIL;
+-
+-delete:
+- list_del(&me->multi_list);
+- ino_index_lock(mc);
+- list_del(&me->ino_index);
+- ino_index_unlock(mc);
+- free(me->key);
+- if (me->mapent)
+- free(me->mapent);
+- free(me);
+-
+- return CHE_OK;
+-}
+-
+ /* cache must be write locked by caller */
+ int cache_delete(struct mapent_cache *mc, const char *key)
+ {
+@@ -1054,113 +937,3 @@ struct mapent *cache_enumerate(struct mapent_cache *mc, struct mapent *me)
+
+ return cache_lookup_next(mc, me);
+ }
+-
+-/*
+- * Get each offset from list head under prefix.
+- * Maintain traversal current position in pos for subsequent calls.
+- * Return each offset into offset.
+- */
+-/* cache must be read locked by caller */
+-char *cache_get_offset(const char *prefix, char *offset, int start,
+- struct list_head *head, struct list_head **pos)
+-{
+- struct list_head *next;
+- struct mapent *this;
+- size_t plen = strlen(prefix);
+- size_t len = 0;
+-
+- if (*pos == head)
+- return NULL;
+-
+- /* Find an offset */
+- *offset = '\0';
+- next = *pos ? (*pos)->next : head->next;
+- while (next != head) {
+- char *offset_start, *pstart, *pend;
+-
+- this = list_entry(next, struct mapent, multi_list);
+- *pos = next;
+- next = next->next;
+-
+- offset_start = &this->key[start];
+- if (strlen(offset_start) <= plen)
+- continue;
+-
+- if (!strncmp(prefix, offset_start, plen)) {
+- struct mapent *np = NULL;
+- char pe[PATH_MAX + 1];
+-
+- /* "/" doesn't count for root offset */
+- if (plen == 1)
+- pstart = &offset_start[plen - 1];
+- else
+- pstart = &offset_start[plen];
+-
+- /* not part of this sub-tree */
+- if (*pstart != '/')
+- continue;
+-
+- /* get next offset */
+- pend = pstart;
+- while (*pend++) {
+- size_t nest_pt_offset;
+-
+- if (*pend != '/')
+- continue;
+-
+- nest_pt_offset = start + pend - pstart;
+- if (plen > 1)
+- nest_pt_offset += plen;
+- strcpy(pe, this->key);
+- pe[nest_pt_offset] = '\0';
+-
+- np = cache_lookup_distinct(this->mc, pe);
+- if (np)
+- break;
+- }
+- if (np)
+- continue;
+- len = pend - pstart - 1;
+- strncpy(offset, pstart, len);
+- offset[len] ='\0';
+- break;
+- }
+- }
+-
+- /* Seek to next offset */
+- while (next != head) {
+- char *offset_start, *pstart;
+-
+- this = list_entry(next, struct mapent, multi_list);
+-
+- offset_start = &this->key[start];
+- if (strlen(offset_start) <= plen + len)
+- break;
+-
+- /* "/" doesn't count for root offset */
+- if (plen == 1)
+- pstart = &offset_start[plen - 1];
+- else
+- pstart = &offset_start[plen];
+-
+- /* not part of this sub-tree */
+- if (*pstart != '/')
+- break;
+-
+- /* new offset */
+- if (!*(pstart + len + 1))
+- break;
+-
+- /* compare offset */
+- if (pstart[len] != '/' ||
+- strlen(pstart) != len ||
+- strncmp(offset, pstart, len))
+- break;
+-
+- *pos = next;
+- next = next->next;
+- }
+-
+- return *offset ? offset : NULL;
+-}
+-
+diff --git a/lib/mounts.c b/lib/mounts.c
+index 6ca7eff1..c120d2a8 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2853,21 +2853,6 @@ static void set_offset_tree_catatonic(struct autofs_point *ap, struct mapent *me
+ tree_traverse_inorder(MAPENT_ROOT(me), set_offset_tree_catatonic_work, NULL);
+ }
+
+-static void set_multi_mount_tree_catatonic(struct autofs_point *ap, struct mapent *me)
+-{
+- if (!list_empty(&me->multi_list)) {
+- struct list_head *head = &me->multi_list;
+- struct list_head *p;
+-
+- list_for_each(p, head) {
+- struct mapent *this;
+-
+- this = list_entry(p, struct mapent, multi_list);
+- set_mount_catatonic(ap, this, this->ioctlfd);
+- }
+- }
+-}
+-
+ void set_indirect_mount_tree_catatonic(struct autofs_point *ap)
+ {
+ struct master_mapent *entry = ap->entry;
+@@ -3034,299 +3019,3 @@ done:
+ out:
+ return rv;
+ }
+-
+-static int do_mount_autofs_offset(struct autofs_point *ap, struct mapent *oe)
+-{
+- int mounted = 0;
+- int ret;
+-
+- debug(ap->logopt, "mount offset %s", oe->key);
+-
+- ret = mount_autofs_offset(ap, oe);
+- if (ret >= MOUNT_OFFSET_OK)
+- mounted++;
+- else {
+- if (ret != MOUNT_OFFSET_IGNORE)
+- warn(ap->logopt, "failed to mount offset");
+- else {
+- debug(ap->logopt, "ignoring \"nohide\" trigger %s",
+- oe->key);
+- /*
+- * Ok, so we shouldn't modify the mapent but
+- * mount requests are blocked at a point above
+- * this and expire only uses the mapent key or
+- * holds the cache write lock.
+- */
+- free(oe->mapent);
+- oe->mapent = NULL;
+- }
+- }
+-
+- return mounted;
+-}
+-
+-static int rmdir_path_offset(struct autofs_point *ap, struct mapent *oe)
+-{
+- char *dir, *path;
+- unsigned int split;
+- int ret;
+-
+- if (ap->type == LKP_DIRECT)
+- return rmdir_path(ap, oe->key, MM_ROOT(oe)->dev);
+-
+- dir = strdup(oe->key);
+-
+- if (ap->flags & MOUNT_FLAG_GHOST)
+- split = ap->len + strlen(MM_ROOT(oe)->key) + 1;
+- else
+- split = ap->len;
+-
+- dir[split] = '\0';
+- path = &dir[split + 1];
+-
+- if (chdir(dir) == -1) {
+- error(ap->logopt, "failed to chdir to %s", dir);
+- free(dir);
+- return -1;
+- }
+-
+- ret = rmdir_path(ap, path, ap->dev);
+-
+- free(dir);
+-
+- if (chdir("/") == -1)
+- error(ap->logopt, "failed to chdir to /");
+-
+- return ret;
+-}
+-
+-static int do_umount_offset(struct autofs_point *ap,
+- struct mapent *oe, const char *root, int start);
+-
+-static int do_umount_multi_triggers(struct autofs_point *ap,
+- struct mapent *me, const char *root,
+- int start, const char *base)
+-{
+- char path[PATH_MAX + 1];
+- char *offset;
+- struct mapent *oe;
+- struct list_head *mm_root, *pos;
+- const char o_root[] = "/";
+- const char *mm_base;
+- int left;
+- unsigned int root_len;
+- unsigned int mm_base_len;
+-
+- left = 0;
+-
+- mm_root = &me->multi->multi_list;
+-
+- if (!base)
+- mm_base = o_root;
+- else
+- mm_base = base;
+-
+- 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);
+-
+- 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;
+-
+- left += do_umount_offset(ap, oe, root, start);
+- }
+-
+- return left;
+-}
+-
+-static int do_umount_offset(struct autofs_point *ap,
+- struct mapent *oe, const char *root, int start)
+-{
+- char *oe_base;
+- int left = 0;
+-
+- /*
+- * Check for and umount subtree offsets resulting from
+- * nonstrict mount fail.
+- */
+- oe_base = oe->key + start;
+- left += do_umount_multi_triggers(ap, oe, root, start, oe_base);
+-
+- /*
+- * If an offset that has an active mount has been removed
+- * from the multi-mount we don't want to attempt to trigger
+- * mounts for it. Obviously this is because it has been
+- * removed, but less obvious is the potential strange
+- * behaviour that can result if we do try and mount it
+- * again after it's been expired. For example, if an NFS
+- * file system is no longer exported and is later umounted
+- * it can be mounted again without any error message but
+- * shows as an empty directory. That's going to confuse
+- * people for sure.
+- *
+- * If the mount cannot be umounted (the process is now
+- * using a stale mount) the offset needs to be invalidated
+- * so no further mounts will be attempted but the offset
+- * cache entry must remain so expires can continue to
+- * attempt to umount it. If the mount can be umounted and
+- * the offset is removed, at least for NFS we will get
+- * ESTALE errors when attempting list the directory.
+- */
+- if (oe->ioctlfd != -1 ||
+- is_mounted(oe->key, MNTS_REAL)) {
+- if (umount_ent(ap, oe->key) &&
+- is_mounted(oe->key, MNTS_REAL)) {
+- debug(ap->logopt,
+- "offset %s has active mount, invalidate",
+- oe->key);
+- /*
+- * Ok, so we shouldn't modify the mapent but
+- * mount requests are blocked at a point above
+- * this and expire only uses the mapent key or
+- * holds the cache write lock.
+- */
+- if (oe->mapent) {
+- free(oe->mapent);
+- oe->mapent = NULL;
+- }
+- return ++left;
+- }
+- }
+-
+- debug(ap->logopt, "umount offset %s", oe->key);
+-
+- if (umount_autofs_offset(ap, oe)) {
+- warn(ap->logopt, "failed to umount offset");
+- left++;
+- } else {
+- struct stat st;
+- int ret;
+-
+- if (!(oe->flags & MOUNT_FLAG_DIR_CREATED))
+- return left;
+-
+- /*
+- * An error due to partial directory removal is
+- * ok so only try and remount the offset if the
+- * actual mount point still exists.
+- */
+- ret = rmdir_path_offset(ap, oe);
+- if (ret == -1 && !stat(oe->key, &st)) {
+- ret = do_mount_autofs_offset(ap, oe);
+- if (ret)
+- left++;
+- /* But we did origianlly create this */
+- oe->flags |= MOUNT_FLAG_DIR_CREATED;
+- }
+- }
+- return left;
+-}
+-
+-int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
+- const char *root, unsigned int start, const char *base)
+-{
+- char path[PATH_MAX + 1];
+- char *offset = path;
+- struct mapent *oe;
+- struct list_head *pos = NULL;
+- unsigned int root_len = strlen(root);
+- int mounted;
+-
+- mounted = 0;
+- offset = cache_get_offset(base, offset, start, &me->multi_list, &pos);
+- while (offset) {
+- char key[PATH_MAX + 1];
+- int key_len = root_len + strlen(offset);
+-
+- if (key_len > PATH_MAX) {
+- warn(ap->logopt, "path loo long");
+- goto cont;
+- }
+-
+- /* 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;
+- if (oe->age != MM_ROOT(me)->age) {
+- /* Best effort */
+- do_umount_offset(ap, oe, root, start);
+- goto cont;
+- }
+-
+- mounted += do_mount_autofs_offset(ap, oe);
+-
+- /*
+- * If re-constructing a multi-mount it's necessary to walk
+- * into nested mounts, unlike the usual "mount only what's
+- * needed as you go" behavior.
+- */
+- if (ap->state == ST_READMAP && ap->flags & MOUNT_FLAG_REMOUNT) {
+- if (oe->ioctlfd != -1 ||
+- is_mounted(oe->key, MNTS_REAL))
+- mount_multi_triggers(ap, oe, key, key_len, base);
+- }
+-cont:
+- offset = cache_get_offset(base,
+- offset, start, &me->multi_list, &pos);
+- }
+-
+- return mounted;
+-}
+-
+-int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root, const char *base)
+-{
+- int left, start;
+-
+- start = strlen(root);
+-
+- left = do_umount_multi_triggers(ap, me, root, start, base);
+-
+- if (!left && IS_MM_ROOT(me)) {
+- /*
+- * Special case.
+- * If we can't umount the root container then we can't
+- * delete the offsets from the cache and we need to put
+- * the offset triggers back.
+- */
+- if (is_mounted(root, MNTS_REAL)) {
+- info(ap->logopt, "unmounting dir = %s", root);
+- if (umount_ent(ap, root) &&
+- is_mounted(root, MNTS_REAL)) {
+- if (mount_multi_triggers(ap, me, root, start, "/") < 0)
+- warn(ap->logopt,
+- "failed to remount offset triggers");
+- return ++left;
+- }
+- }
+-
+- /* check for mounted mount entry and remove it if found */
+- mnts_remove_mount(root, MNTS_MOUNTED);
+- }
+-
+- return left;
+-}
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index d6ef48b8..ef74eda9 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1074,62 +1074,6 @@ next:
+ return (p - ent);
+ }
+
+-static void cleanup_multi_triggers(struct autofs_point *ap,
+- struct mapent *me, const char *root, int start,
+- const char *base)
+-{
+- char path[PATH_MAX + 1];
+- char offset[PATH_MAX + 1];
+- char *poffset = offset;
+- struct mapent *oe;
+- 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;
+-
+- if (!base)
+- mm_base = o_root;
+- else
+- 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))) {
+- 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);
+- }
+- }
+-
+- return;
+-}
+-
+ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ const char *name, char *loc, char *options, void *ctxt)
+ {
--- /dev/null
+autofs-5.1.7 - remove redundant assignment in master_add_amd_mount_section_mounts()
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: missing_lock: Accessing "entry->current" without holding lock
+ "master_mapent.current_mutex".
+
+This is initialization not clearing current source. But the field has
+already been initialized in the master_new_mapent() call.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/master.c | 1 -
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index c7bc0c39..f95b1aa6 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -58,6 +58,7 @@
+ - add length check in umount_subtree_mounts().
+ - fix flags check in umount_multi().
+ - dont try umount after stat() ENOENT fail.
++- remove redundant assignment in master_add_amd_mount_section_mounts().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/master.c b/daemon/master.c
+index 30d7cf98..84743f80 100644
+--- a/daemon/master.c
++++ b/daemon/master.c
+@@ -996,7 +996,6 @@ static void master_add_amd_mount_section_mounts(struct master *master, time_t ag
+ source->master_line = 0;
+
+ entry->age = age;
+- entry->current = NULL;
+
+ master_add_mapent(master, entry);
+ next:
--- /dev/null
+autofs-5.1.7 - remove redundant if check
+
+From: Ian Kent <raven@themaw.net>
+
+Coverity: identical code in if condition branches.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/direct.c | 5 +----
+ 2 files changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 62a918a9..2186cbe3 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -51,6 +51,7 @@
+ - remove mounts_mutex.
+ - remove unused variable from get_exports().
+ - add missing free in handle_mounts().
++- remove redundant if check.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/direct.c b/daemon/direct.c
+index 3f4f5704..a33f9f91 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -752,10 +752,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+
+ ops->timeout(ap->logopt, ioctlfd, timeout);
+ cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
+- if (ap->logopt & LOGOPT_DEBUG)
+- notify_mount_result(ap, me->key, timeout, str_offset);
+- else
+- notify_mount_result(ap, me->key, timeout, str_offset);
++ notify_mount_result(ap, me->key, timeout, str_offset);
+ ops->close(ap->logopt, ioctlfd);
+
+ debug(ap->logopt, "mounted trigger %s", me->key);
--- /dev/null
+autofs-5.1.7 - remove redundant local var from sun_mount()
+
+From: Ian Kent <raven@themaw.net>
+
+The local variable mountpoint in sun_mount() is set directly from a
+passed in parameter and never changed and the source isn't changed
+either, so use the variable directly.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 13 ++++---------
+ 2 files changed, 5 insertions(+), 9 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 76fccf70..444ade5b 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -42,6 +42,7 @@
+ - add mount and umount offsets functions.
+ - switch to use tree implementation for offsets.
+ - remove obsolete functions.
++- remove redundant local var from sun_mount().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index ef74eda9..437869b5 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -530,7 +530,6 @@ static int sun_mount(struct autofs_point *ap, const char *root,
+ int nonstrict = 1;
+ int use_weight_only = ap->flags & MOUNT_FLAG_USE_WEIGHT_ONLY;
+ int rv, cur_state;
+- char *mountpoint;
+ char *what;
+ char *type;
+
+@@ -624,9 +623,6 @@ static int sun_mount(struct autofs_point *ap, const char *root,
+ }
+ }
+
+- mountpoint = alloca(namelen + 1);
+- sprintf(mountpoint, "%.*s", namelen, name);
+-
+ type = ap->entry->maps->type;
+ if (type && !strcmp(type, "hosts")) {
+ if (options && *options != '\0') {
+@@ -698,9 +694,9 @@ static int sun_mount(struct autofs_point *ap, const char *root,
+ debug(ap->logopt, MODPREFIX
+ "mounting root %s, mountpoint %s, "
+ "what %s, fstype %s, options %s",
+- root, mountpoint, what, fstype, options);
++ root, name, what, fstype, options);
+
+- rv = mount_nfs->mount_mount(ap, root, mountpoint, strlen(mountpoint),
++ rv = mount_nfs->mount_mount(ap, root, name, namelen,
+ what, fstype, options, mount_nfs->context);
+ } else {
+ if (!loclen)
+@@ -720,11 +716,10 @@ static int sun_mount(struct autofs_point *ap, const char *root,
+ debug(ap->logopt, MODPREFIX
+ "mounting root %s, mountpoint %s, "
+ "what %s, fstype %s, options %s",
+- root, mountpoint, what, fstype, options);
++ root, name, what, fstype, options);
+
+ /* Generic mount routine */
+- rv = do_mount(ap, root, mountpoint, strlen(mountpoint), what, fstype,
+- options);
++ rv = do_mount(ap, root, name, namelen, what, fstype, options);
+ }
+ pthread_setcancelstate(cur_state, NULL);
+
--- /dev/null
+autofs-5.1.7 - remove redundant variables from mount_autofs_offset()
+
+From: Ian Kent <raven@themaw.net>
+
+The path to be mounted is the key in the passed in mapent.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/direct.c | 42 +++++++++++++++++++-----------------------
+ include/automount.h | 2 +-
+ lib/mounts.c | 2 +-
+ 4 files changed, 22 insertions(+), 25 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index c4ebb52f..45be4783 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -9,6 +9,7 @@
+ - fix is mounted check on non existent path.
+ - simplify cache_get_parent().
+ - set offset parent in update_offset_entry().
++- remove redundant variables from mount_autofs_offset().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/direct.c b/daemon/direct.c
+index 9fe4903a..c41c680f 100644
+--- a/daemon/direct.c
++++ b/daemon/direct.c
+@@ -611,7 +611,7 @@ force_umount:
+ return rv;
+ }
+
+-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset)
++int mount_autofs_offset(struct autofs_point *ap, struct mapent *me)
+ {
+ const char *str_offset = mount_type_str(t_offset);
+ struct ioctl_ops *ops = get_ioctl_ops();
+@@ -623,7 +623,6 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *
+ const char *hosts_map_name = "-hosts";
+ const char *map_name = hosts_map_name;
+ const char *type;
+- char mountpoint[PATH_MAX];
+ struct mnt_list *mnt;
+
+ if (ops->version && ap->flags & MOUNT_FLAG_REMOUNT) {
+@@ -681,11 +680,8 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *
+ return MOUNT_OFFSET_OK;
+ }
+
+- strcpy(mountpoint, root);
+- strcat(mountpoint, offset);
+-
+ /* In case the directory doesn't exist, try to mkdir it */
+- if (mkdir_path(mountpoint, mp_mode) < 0) {
++ if (mkdir_path(me->key, mp_mode) < 0) {
+ if (errno == EEXIST) {
+ /*
+ * If the mount point directory is a real mount
+@@ -694,7 +690,7 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *
+ * the kernel NFS client.
+ */
+ if (me->multi != me &&
+- is_mounted(mountpoint, MNTS_REAL))
++ is_mounted(me->key, MNTS_REAL))
+ return MOUNT_OFFSET_IGNORE;
+
+ /*
+@@ -714,13 +710,13 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ debug(ap->logopt,
+ "can't create mount directory: %s, %s",
+- mountpoint, estr);
++ me->key, estr);
+ return MOUNT_OFFSET_FAIL;
+ } else {
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+ crit(ap->logopt,
+ "failed to create mount directory: %s, %s",
+- mountpoint, estr);
++ me->key, estr);
+ return MOUNT_OFFSET_FAIL;
+ }
+ } else {
+@@ -730,56 +726,56 @@ int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *
+
+ debug(ap->logopt,
+ "calling mount -t autofs " SLOPPY " -o %s automount %s",
+- mp->options, mountpoint);
++ mp->options, me->key);
+
+ type = ap->entry->maps->type;
+ if (!type || strcmp(ap->entry->maps->type, "hosts"))
+ map_name = me->mc->map->argv[0];
+
+- ret = mount(map_name, mountpoint, "autofs", MS_MGC_VAL, mp->options);
++ ret = mount(map_name, me->key, "autofs", MS_MGC_VAL, mp->options);
+ if (ret) {
+ crit(ap->logopt,
+ "failed to mount offset trigger %s at %s",
+- me->key, mountpoint);
++ me->key, me->key);
+ goto out_err;
+ }
+
+- ret = stat(mountpoint, &st);
++ ret = stat(me->key, &st);
+ if (ret == -1) {
+ error(ap->logopt,
+- "failed to stat direct mount trigger %s", mountpoint);
++ "failed to stat direct mount trigger %s", me->key);
+ goto out_umount;
+ }
+
+- ops->open(ap->logopt, &ioctlfd, st.st_dev, mountpoint);
++ ops->open(ap->logopt, &ioctlfd, st.st_dev, me->key);
+ if (ioctlfd < 0) {
+- crit(ap->logopt, "failed to create ioctl fd for %s", mountpoint);
++ crit(ap->logopt, "failed to create ioctl fd for %s", me->key);
+ goto out_umount;
+ }
+
+ ops->timeout(ap->logopt, ioctlfd, timeout);
+ cache_set_ino_index(me->mc, me->key, st.st_dev, st.st_ino);
+ if (ap->logopt & LOGOPT_DEBUG)
+- notify_mount_result(ap, mountpoint, timeout, str_offset);
++ notify_mount_result(ap, me->key, timeout, str_offset);
+ else
+ notify_mount_result(ap, me->key, timeout, str_offset);
+ ops->close(ap->logopt, ioctlfd);
+
+- mnt = mnts_add_mount(ap, mountpoint, MNTS_OFFSET);
++ mnt = mnts_add_mount(ap, me->key, MNTS_OFFSET);
+ if (!mnt)
+ error(ap->logopt,
+ "failed to add offset mount %s to mounted list",
+- mountpoint);
++ me->key);
+
+- debug(ap->logopt, "mounted trigger %s at %s", me->key, mountpoint);
++ debug(ap->logopt, "mounted trigger %s", me->key);
+
+ return MOUNT_OFFSET_OK;
+
+ out_umount:
+- umount(mountpoint);
++ umount(me->key);
+ out_err:
+- if (stat(mountpoint, &st) == 0 && me->flags & MOUNT_FLAG_DIR_CREATED)
+- rmdir_path(ap, mountpoint, st.st_dev);
++ if (stat(me->key, &st) == 0 && me->flags & MOUNT_FLAG_DIR_CREATED)
++ rmdir_path(ap, me->key, st.st_dev);
+
+ return MOUNT_OFFSET_FAIL;
+ }
+diff --git a/include/automount.h b/include/automount.h
+index 730be19a..09d84f05 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -596,7 +596,7 @@ int expire_offsets_direct(struct autofs_point *ap, struct mapent *me, int now);
+ int mount_autofs_indirect(struct autofs_point *ap, const char *root);
+ int do_mount_autofs_direct(struct autofs_point *ap, struct mapent *me, time_t timeout);
+ int mount_autofs_direct(struct autofs_point *ap);
+-int mount_autofs_offset(struct autofs_point *ap, struct mapent *me, const char *root, const char *offset);
++int mount_autofs_offset(struct autofs_point *ap, struct mapent *me);
+ void submount_signal_parent(struct autofs_point *ap, unsigned int success);
+ void close_mount_fds(struct autofs_point *ap);
+ int umount_autofs_indirect(struct autofs_point *ap, const char *root);
+diff --git a/lib/mounts.c b/lib/mounts.c
+index fe931b20..12d22023 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2481,7 +2481,7 @@ static int do_mount_autofs_offset(struct autofs_point *ap,
+
+ debug(ap->logopt, "mount offset %s at %s", oe->key, root);
+
+- ret = mount_autofs_offset(ap, oe, root, offset);
++ ret = mount_autofs_offset(ap, oe);
+ if (ret >= MOUNT_OFFSET_OK)
+ mounted++;
+ else {
--- /dev/null
+autofs-5.1.7 - remove unused function master_submount_list_empty()
+
+From: Ian Kent <raven@themaw.net>
+
+This function is not used anywhere now, remove it.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/master.c | 12 ------------
+ include/master.h | 1 -
+ 3 files changed, 1 insertion(+), 13 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 1c9e2a2d..002da042 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -45,6 +45,7 @@
+ - remove redundant local var from sun_mount().
+ - use mount_fullpath() in one spot in parse_mount().
+ - pass root length to mount_fullpath().
++- remove unused function master_submount_list_empty().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/master.c b/daemon/master.c
+index 022fb9dd..af9cd79f 100644
+--- a/daemon/master.c
++++ b/daemon/master.c
+@@ -1119,18 +1119,6 @@ int master_read_master(struct master *master, time_t age)
+ return 1;
+ }
+
+-int master_submount_list_empty(struct autofs_point *ap)
+-{
+- int res = 0;
+-
+- mounts_mutex_lock(ap);
+- if (list_empty(&ap->submounts))
+- res = 1;
+- mounts_mutex_unlock(ap);
+-
+- return res;
+-}
+-
+ int master_notify_submount(struct autofs_point *ap, const char *path, enum states state)
+ {
+ struct mnt_list *this, *sbmnt;
+diff --git a/include/master.h b/include/master.h
+index 0806b372..2d727943 100644
+--- a/include/master.h
++++ b/include/master.h
+@@ -116,7 +116,6 @@ void master_free_mapent_sources(struct master_mapent *, unsigned int);
+ void master_free_mapent(struct master_mapent *);
+ struct master *master_new(const char *, unsigned int, unsigned int);
+ int master_read_master(struct master *, time_t);
+-int master_submount_list_empty(struct autofs_point *ap);
+ int master_notify_submount(struct autofs_point *, const char *path, enum states);
+ void master_notify_state_change(struct master *, int);
+ int master_mount_mounts(struct master *, time_t);
--- /dev/null
+autofs-5.1.7 - remove unused functions cache_dump_multi() and cache_dump_cache()
+
+From: Ian Kent <raven@themaw.net>
+
+Remove debugging functions cache_dump_multi() and cache_dump_cache()
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/cache.c | 28 ----------------------------
+ 2 files changed, 1 insertion(+), 28 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 3ba748d7..60924b3f 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -29,6 +29,7 @@
+ - don't pass root to do_mount_autofs_offset().
+ - rename tree implementation functions.
+ - add some multi-mount macros.
++- remove unused functions cache_dump_multi() and cache_dump_cache().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/lib/cache.c b/lib/cache.c
+index 1d9f5cc7..629c4d0a 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -24,34 +24,6 @@
+
+ #include "automount.h"
+
+-void cache_dump_multi(struct list_head *list)
+-{
+- struct list_head *p;
+- struct mapent *me;
+-
+- list_for_each(p, list) {
+- me = list_entry(p, struct mapent, multi_list);
+- logmsg("key=%s", me->key);
+- }
+-}
+-
+-void cache_dump_cache(struct mapent_cache *mc)
+-{
+- struct mapent *me;
+- unsigned int i;
+-
+- for (i = 0; i < mc->size; i++) {
+- me = mc->hash[i];
+- if (me == NULL)
+- continue;
+- while (me) {
+- logmsg("me->key=%s me->multi=%p dev=%ld ino=%ld",
+- me->key, me->multi, me->dev, me->ino);
+- me = me->next;
+- }
+- }
+-}
+-
+ void cache_readlock(struct mapent_cache *mc)
+ {
+ int status;
--- /dev/null
+autofs-5.1.7 - remove unused mount offset list lock functions
+
+From: Ian Kent <raven@themaw.net>
+
+When fixing the locking in parse_mount() it was evident that there was
+no real benefit of having an additional lock for the offset list so its
+use was eliminated.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/automount.h | 4 ---
+ lib/cache.c | 70 +--------------------------------------------------
+ 3 files changed, 3 insertions(+), 72 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index d25b19c8..c5619d2e 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -19,6 +19,7 @@
+ - fix return from umount_subtree_mounts() on offset list delete.
+ - pass mapent_cache to update_offset_entry().
+ - fix inconsistent locking in parse_mount().
++- remove unused mount offset list lock functions.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/automount.h b/include/automount.h
+index 09d84f05..69445b92 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -162,7 +162,6 @@ struct stack {
+ struct mapent {
+ struct mapent *next;
+ struct list_head ino_index;
+- pthread_rwlock_t multi_rwlock;
+ struct list_head multi_list;
+ struct mapent_cache *mc;
+ struct map_source *source;
+@@ -212,9 +211,6 @@ int cache_set_offset_parent(struct mapent_cache *mc, const char *offset);
+ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age);
+ int cache_delete(struct mapent_cache *mc, const char *key);
+ int cache_delete_offset(struct mapent_cache *mc, const char *key);
+-void cache_multi_readlock(struct mapent *me);
+-void cache_multi_writelock(struct mapent *me);
+-void cache_multi_unlock(struct mapent *me);
+ int cache_delete_offset_list(struct mapent_cache *mc, const char *key);
+ void cache_release(struct map_source *map);
+ void cache_clean_null_cache(struct mapent_cache *mc);
+diff --git a/lib/cache.c b/lib/cache.c
+index ce9e9bd2..03d0499a 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -108,58 +108,6 @@ void cache_lock_cleanup(void *arg)
+ return;
+ }
+
+-void cache_multi_readlock(struct mapent *me)
+-{
+- int status;
+-
+- if (!me)
+- return;
+-
+- status = pthread_rwlock_rdlock(&me->multi_rwlock);
+- if (status) {
+- logmsg("mapent cache multi mutex lock failed");
+- fatal(status);
+- }
+- return;
+-}
+-
+-void cache_multi_writelock(struct mapent *me)
+-{
+- int status;
+-
+- if (!me)
+- return;
+-
+- status = pthread_rwlock_wrlock(&me->multi_rwlock);
+- if (status) {
+- logmsg("mapent cache multi mutex lock failed");
+- fatal(status);
+- }
+- return;
+-}
+-
+-void cache_multi_unlock(struct mapent *me)
+-{
+- int status;
+-
+- if (!me)
+- return;
+-
+- status = pthread_rwlock_unlock(&me->multi_rwlock);
+- if (status) {
+- logmsg("mapent cache multi mutex unlock failed");
+- fatal(status);
+- }
+- return;
+-}
+-
+-void cache_multi_lock_cleanup(void *arg)
+-{
+- struct mapent *me = (struct mapent *) arg;
+- cache_multi_unlock(me);
+- return;
+-}
+-
+ static inline void ino_index_lock(struct mapent_cache *mc)
+ {
+ int status = pthread_mutex_lock(&mc->ino_index_mutex);
+@@ -626,7 +574,6 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
+ struct mapent *me, *existing = NULL;
+ char *pkey, *pent;
+ u_int32_t hashval = hash(key, mc->size);
+- int status;
+
+ me = (struct mapent *) malloc(sizeof(struct mapent));
+ if (!me)
+@@ -665,10 +612,6 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
+ me->ino = (ino_t) -1;
+ me->flags = 0;
+
+- status = pthread_rwlock_init(&me->multi_rwlock, NULL);
+- if (status)
+- fatal(status);
+-
+ /*
+ * We need to add to the end if values exist in order to
+ * preserve the order in which the map was read on lookup.
+@@ -924,7 +867,7 @@ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key
+ return ret;
+ }
+
+-/* cache_multi_lock of the multi mount owner must be held by caller */
++/* cache write lock of the multi mount owner must be held by caller */
+ int cache_delete_offset(struct mapent_cache *mc, const char *key)
+ {
+ u_int32_t hashval = hash(key, mc->size);
+@@ -956,9 +899,6 @@ int cache_delete_offset(struct mapent_cache *mc, const char *key)
+ return CHE_FAIL;
+
+ delete:
+- status = pthread_rwlock_destroy(&me->multi_rwlock);
+- if (status)
+- fatal(status);
+ list_del(&me->multi_list);
+ ino_index_lock(mc);
+ list_del(&me->ino_index);
+@@ -976,7 +916,7 @@ int cache_delete(struct mapent_cache *mc, const char *key)
+ {
+ struct mapent *me = NULL, *pred;
+ u_int32_t hashval = hash(key, mc->size);
+- int status, ret = CHE_OK;
++ int ret = CHE_OK;
+ char this[PATH_MAX];
+
+ strcpy(this, key);
+@@ -997,9 +937,6 @@ int cache_delete(struct mapent_cache *mc, const char *key)
+ goto done;
+ }
+ pred->next = me->next;
+- status = pthread_rwlock_destroy(&me->multi_rwlock);
+- if (status)
+- fatal(status);
+ ino_index_lock(mc);
+ list_del(&me->ino_index);
+ ino_index_unlock(mc);
+@@ -1029,9 +966,6 @@ int cache_delete(struct mapent_cache *mc, const char *key)
+ goto done;
+ }
+ mc->hash[hashval] = me->next;
+- status = pthread_rwlock_destroy(&me->multi_rwlock);
+- if (status)
+- fatal(status);
+ ino_index_lock(mc);
+ list_del(&me->ino_index);
+ ino_index_unlock(mc);
--- /dev/null
+autofs-5.1.7 - remove unused parameter form do_mount_autofs_offset()
+
+From: Ian Kent <raven@themaw.net>
+
+The offset parameter of do_mount_autofs_offset() isn't used.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 10 ++++------
+ 2 files changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 45be4783..3eda995c 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -10,6 +10,7 @@
+ - simplify cache_get_parent().
+ - set offset parent in update_offset_entry().
+ - remove redundant variables from mount_autofs_offset().
++- remove unused parameter form do_mount_autofs_offset().
+
+ 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 12d22023..8e88182f 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2472,9 +2472,7 @@ out:
+ }
+
+ static int do_mount_autofs_offset(struct autofs_point *ap,
+- struct mapent *oe, const char *root,
+- char *offset)
+-
++ struct mapent *oe, const char *root)
+ {
+ int mounted = 0;
+ int ret;
+@@ -2529,7 +2527,7 @@ int mount_multi_triggers(struct autofs_point *ap, struct mapent *me,
+ if (!oe || !oe->mapent)
+ goto cont;
+
+- mounted += do_mount_autofs_offset(ap, oe, root, offset);
++ mounted += do_mount_autofs_offset(ap, oe, root);
+
+ /*
+ * If re-constructing a multi-mount it's necessary to walk
+@@ -2666,7 +2664,7 @@ int umount_multi_triggers(struct autofs_point *ap, struct mapent *me, char *root
+ */
+ ret = rmdir_path_offset(ap, oe);
+ if (ret == -1 && !stat(oe->key, &st)) {
+- ret = do_mount_autofs_offset(ap, oe, root, offset);
++ ret = do_mount_autofs_offset(ap, oe, root);
+ if (ret)
+ left++;
+ /* But we did origianlly create this */
+@@ -2847,7 +2845,7 @@ int clean_stale_multi_triggers(struct autofs_point *ap,
+ */
+ ret = rmdir_path_offset(ap, oe);
+ if (ret == -1 && !stat(oe->key, &st)) {
+- ret = do_mount_autofs_offset(ap, oe, root, offset);
++ ret = do_mount_autofs_offset(ap, oe, root);
+ if (ret) {
+ left++;
+ /* But we did origianlly create this */
--- /dev/null
+autofs-5.1.7 - remove unused variable from get_exports()
+
+From: Ian Kent <raven@themaw.net>
+
+Fix complier warning about unused variable entry in get_exports().
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/lookup_hosts.c | 1 -
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 9d0f4278..9c3ede45 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -49,6 +49,7 @@
+ - move amd mounts removal into lib/mounts.c.
+ - check for offset with no mount location.
+ - remove mounts_mutex.
++- remove unused variable from get_exports().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index 7e101ddb..24edf00c 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -87,7 +87,6 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ static char *get_exports(struct autofs_point *ap, const char *host)
+ {
+ char buf[MAX_ERR_BUF];
+- char entry[PATH_MAX + 1];
+ char *mapent;
+ struct exportinfo *exp, *this;
+ size_t hostlen = strlen(host);
--- /dev/null
+autofs-5.1.7 - rename path to m_offset in update_offset_entry()
+
+From: Ian Kent <raven@themaw.net>
+
+Rename local variable from path to m_offset in update_offset_entry() to
+make the meaning of this variable clear.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 46 +++++++++++++++++++++++-----------------------
+ 2 files changed, 24 insertions(+), 23 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index e822efec..0e9ca94f 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -25,6 +25,7 @@
+ - don't add offset mounts to mounted mounts table.
+ - reduce umount EBUSY check delay.
+ - cleanup cache_delete() a little.
++- rename path to m_offset in update_offset_entry().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index a6630a76..34d4441e 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -796,36 +796,36 @@ static int
+ update_offset_entry(struct autofs_point *ap,
+ struct mapent_cache *mc, const char *name,
+ const char *m_root, int m_root_len,
+- const char *path, const char *myoptions,
++ const char *m_offset, const char *myoptions,
+ const char *loc, time_t age)
+ {
+ char m_key[PATH_MAX + 1];
+ char m_mapent[MAPENT_MAX_LEN + 1];
+- int p_len, m_key_len, m_options_len, m_mapent_len;
++ int o_len, m_key_len, m_options_len, m_mapent_len;
+ int ret;
+
+ memset(m_mapent, 0, MAPENT_MAX_LEN + 1);
+
+ /* Internal hosts map may have loc == NULL */
+- if (!*path) {
++ if (!*m_offset) {
+ error(ap->logopt,
+- MODPREFIX "syntax error in offset %s -> %s", path, loc);
++ MODPREFIX "syntax error in offset %s -> %s", m_offset, loc);
+ return CHE_FAIL;
+ }
+
+- p_len = strlen(path);
++ o_len = strlen(m_offset);
+ /* Trailing '/' causes us pain */
+- if (p_len > 1) {
+- while (p_len > 1 && path[p_len - 1] == '/')
+- p_len--;
++ if (o_len > 1) {
++ while (o_len > 1 && m_offset[o_len - 1] == '/')
++ o_len--;
+ }
+- m_key_len = m_root_len + p_len;
++ m_key_len = m_root_len + o_len;
+ if (m_key_len > PATH_MAX) {
+ error(ap->logopt, MODPREFIX "multi mount key too long");
+ return CHE_FAIL;
+ }
+ strcpy(m_key, m_root);
+- strncat(m_key, path, p_len);
++ strncat(m_key, m_offset, o_len);
+ m_key[m_key_len] = '\0';
+
+ m_options_len = 0;
+@@ -860,15 +860,15 @@ update_offset_entry(struct autofs_point *ap,
+
+ if (ret == CHE_DUPLICATE) {
+ warn(ap->logopt, MODPREFIX
+- "syntax error or duplicate offset %s -> %s", path, loc);
++ "syntax error or duplicate offset %s -> %s", m_offset, loc);
+ ret = CHE_OK;
+ } else if (ret == CHE_FAIL)
+ debug(ap->logopt, MODPREFIX
+- "failed to update multi-mount offset %s -> %s", path, m_mapent);
++ "failed to update multi-mount offset %s -> %s", m_offset, m_mapent);
+ else {
+ ret = CHE_OK;
+ debug(ap->logopt, MODPREFIX
+- "updated multi-mount offset %s -> %s", path, m_mapent);
++ "updated multi-mount offset %s -> %s", m_offset, m_mapent);
+ }
+
+ return ret;
+@@ -1538,22 +1538,22 @@ dont_expand:
+
+ /* It's a multi-mount; deal with it */
+ do {
+- char *path, *myoptions, *loc;
++ char *m_offset, *myoptions, *loc;
+ int status;
+
+ if ((*p == '"' && *(p + 1) != '/') || (*p != '"' && *p != '/')) {
+ l = 0;
+- path = dequote("/", 1, ap->logopt);
++ m_offset = dequote("/", 1, ap->logopt);
+ debug(ap->logopt,
+- MODPREFIX "dequote(\"/\") -> %s", path);
++ MODPREFIX "dequote(\"/\") -> %s", m_offset);
+ } else {
+ l = span_space(p, mapent_len - (p - pmapent));
+- path = sanitize_path(p, l, LKP_MULTI, ap->logopt);
++ m_offset = sanitize_path(p, l, LKP_MULTI, ap->logopt);
+ debug(ap->logopt, MODPREFIX
+- "dequote(\"%.*s\") -> %s", l, p, path);
++ "dequote(\"%.*s\") -> %s", l, p, m_offset);
+ }
+
+- if (!path) {
++ if (!m_offset) {
+ warn(ap->logopt, MODPREFIX "null path or out of memory");
+ cache_writelock(mc);
+ cache_delete_offset_list(mc, name);
+@@ -1575,7 +1575,7 @@ dont_expand:
+ cache_writelock(mc);
+ cache_delete_offset_list(mc, name);
+ cache_unlock(mc);
+- free(path);
++ free(m_offset);
+ free(options);
+ free(pmapent);
+ pthread_setcancelstate(cur_state, NULL);
+@@ -1587,14 +1587,14 @@ dont_expand:
+
+ status = update_offset_entry(ap, mc,
+ name, m_root, m_root_len,
+- path, myoptions, loc, age);
++ m_offset, myoptions, loc, age);
+
+ if (status != CHE_OK) {
+ warn(ap->logopt, MODPREFIX "error adding multi-mount");
+ cache_writelock(mc);
+ cache_delete_offset_list(mc, name);
+ cache_unlock(mc);
+- free(path);
++ free(m_offset);
+ free(options);
+ free(pmapent);
+ free(myoptions);
+@@ -1606,7 +1606,7 @@ dont_expand:
+
+ if (loc)
+ free(loc);
+- free(path);
++ free(m_offset);
+ free(myoptions);
+ } while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
+
--- /dev/null
+autofs-5.1.7 - rename tree implementation functions
+
+From: Ian Kent <raven@themaw.net>
+
+Rename the tree struct and functions to make them consistent.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/mounts.c | 80 +++++++++++++++++++++++++++++-----------------------------
+ 2 files changed, 41 insertions(+), 40 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 2a07bd45..1bf20699 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -27,6 +27,7 @@
+ - cleanup cache_delete() a little.
+ - rename path to m_offset in update_offset_entry().
+ - don't pass root to do_mount_autofs_offset().
++- rename tree implementation functions.
+
+ 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 289500da..f5b905a6 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1225,30 +1225,30 @@ done:
+ return has_mounted_mounts;
+ }
+
+-struct node {
++struct tree_node {
+ struct mnt_list *mnt;
+- struct node *left;
+- struct node *right;
++ struct tree_node *left;
++ struct tree_node *right;
+ };
+
+-static struct node *new(struct mnt_list *mnt)
++static struct tree_node *tree_new(struct mnt_list *mnt)
+ {
+- struct node *n;
++ struct tree_node *n;
+
+- n = malloc(sizeof(struct node));
++ n = malloc(sizeof(struct tree_node));
+ if (!n)
+ return NULL;
+- memset(n, 0, sizeof(struct node));
++ memset(n, 0, sizeof(struct tree_node));
+ n->mnt = mnt;
+
+ return n;
+ }
+
+-static struct node *tree_root(struct mnt_list *mnt)
++static struct tree_node *tree_root(struct mnt_list *mnt)
+ {
+- struct node *n;
++ struct tree_node *n;
+
+- n = new(mnt);
++ n = tree_new(mnt);
+ if (!n) {
+ error(LOGOPT_ANY, "failed to allcate tree root");
+ return NULL;
+@@ -1257,37 +1257,37 @@ static struct node *tree_root(struct mnt_list *mnt)
+ return n;
+ }
+
+-static struct node *add_left(struct node *this, struct mnt_list *mnt)
++static struct tree_node *tree_add_left(struct tree_node *n, struct mnt_list *mnt)
+ {
+- struct node *n;
++ struct tree_node *new;
+
+- n = new(mnt);
+- if (!n) {
++ new = tree_new(mnt);
++ if (!new) {
+ error(LOGOPT_ANY, "failed to allcate tree node");
+ return NULL;
+ }
+- this->left = n;
++ n->left = new;
+
+ return n;
+ }
+
+-static struct node *add_right(struct node *this, struct mnt_list *mnt)
++static struct tree_node *tree_add_right(struct tree_node *n, struct mnt_list *mnt)
+ {
+- struct node *n;
++ struct tree_node *new;
+
+- n = new(mnt);
+- if (!n) {
++ new = tree_new(mnt);
++ if (!new) {
+ error(LOGOPT_ANY, "failed to allcate tree node");
+ return NULL;
+ }
+- this->right = n;
++ n->right = new;
+
+ return n;
+ }
+
+-static struct node *add_node(struct node *root, struct mnt_list *mnt)
++static struct tree_node *tree_add_node(struct tree_node *root, struct mnt_list *mnt)
+ {
+- struct node *p, *q;
++ struct tree_node *p, *q;
+ unsigned int mp_len;
+
+ mp_len = strlen(mnt->mp);
+@@ -1307,43 +1307,43 @@ static struct node *add_node(struct node *root, struct mnt_list *mnt)
+ error(LOGOPT_ANY, "duplicate entry in mounts list");
+ else {
+ if (mp_len < strlen(p->mnt->mp))
+- return add_left(p, mnt);
++ return tree_add_left(p, mnt);
+ else
+- return add_right(p, mnt);
++ return tree_add_right(p, mnt);
+ }
+
+ return NULL;
+ }
+
+-static void tree_free(struct node *tree)
++static void tree_free(struct tree_node *root)
+ {
+- if (tree->right)
+- tree_free(tree->right);
+- if (tree->left)
+- tree_free(tree->left);
+- free(tree);
++ if (root->right)
++ tree_free(root->right);
++ if (root->left)
++ tree_free(root->left);
++ free(root);
+ }
+
+-static void traverse(struct node *node, struct list_head *mnts)
++static void tree_traverse(struct tree_node *n, struct list_head *mnts)
+ {
+- if (node->right)
+- traverse(node->right, mnts);
+- list_add_tail(&node->mnt->expire, mnts);
+- if (node->left)
+- traverse(node->left, mnts);
++ if (n->right)
++ tree_traverse(n->right, mnts);
++ list_add_tail(&n->mnt->expire, mnts);
++ if (n->left)
++ tree_traverse(n->left, mnts);
+ }
+
+ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap)
+ {
+ struct mnt_list *mnt;
+- struct node *tree = NULL;
++ struct tree_node *tree = NULL;
+
+ mnts_hash_mutex_lock();
+ if (list_empty(&ap->mounts))
+ goto done;
+
+ list_for_each_entry(mnt, &ap->mounts, mount) {
+- struct node *n;
++ struct tree_node *n;
+
+ if (!(mnt->flags & MNTS_MOUNTED))
+ continue;
+@@ -1359,7 +1359,7 @@ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap)
+ continue;
+ }
+
+- n = add_node(tree, mnt);
++ n = tree_add_node(tree, mnt);
+ if (!n) {
+ error(LOGOPT_ANY, "failed to add expire tree node");
+ tree_free(tree);
+@@ -1367,7 +1367,7 @@ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap)
+ }
+ }
+
+- traverse(tree, mnts);
++ tree_traverse(tree, mnts);
+ tree_free(tree);
+ done:
+ mnts_hash_mutex_unlock();
--- /dev/null
+autofs-5.1.7 - set offset parent in update_offset_entry()
+
+From: Ian Kent <raven@themaw.net>
+
+Avoid the list traversal in cache_set_parents() by setting the
+offset parent when updating the offset.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/automount.h | 2 +-
+ lib/cache.c | 26 +++++++++++---------------
+ modules/parse_sun.c | 5 ++++-
+ 4 files changed, 17 insertions(+), 17 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index ee746277..c4ebb52f 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -8,6 +8,7 @@
+ - eliminate cache_lookup_offset() usage.
+ - fix is mounted check on non existent path.
+ - simplify cache_get_parent().
++- set offset parent in update_offset_entry().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/automount.h b/include/automount.h
+index 2f09e8e7..730be19a 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -208,7 +208,7 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
+ int cache_update_offset(struct mapent_cache *mc, const char *mkey, const char *key, const char *mapent, time_t age);
+ int cache_lookup_negative(struct mapent *me, const char *key);
+ void cache_update_negative(struct mapent_cache *mc, struct map_source *ms, const char *key, time_t timeout);
+-int cache_set_parents(struct mapent *mm);
++int cache_set_offset_parent(struct mapent_cache *mc, const char *offset);
+ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key, const char *mapent, time_t age);
+ int cache_delete(struct mapent_cache *mc, const char *key);
+ int cache_delete_offset(struct mapent_cache *mc, const char *key);
+diff --git a/lib/cache.c b/lib/cache.c
+index 53f290cd..ce9e9bd2 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -864,25 +864,21 @@ static struct mapent *get_offset_parent(struct mapent_cache *mc,
+ return NULL;
+ }
+
+-int cache_set_parents(struct mapent *mm)
++int cache_set_offset_parent(struct mapent_cache *mc, const char *offset)
+ {
+- struct list_head *multi_head, *p;
+- struct mapent *this;
++ struct mapent *this, *parent;
+
+- if (!mm->multi)
++ this = cache_lookup_distinct(mc, offset);
++ if (!this)
++ return 0;
++ if (!this->multi)
+ return 0;
+
+- multi_head = &mm->multi->multi_list;
+-
+- list_for_each(p, multi_head) {
+- struct mapent *parent;
+- this = list_entry(p, struct mapent, multi_list);
+- parent = get_offset_parent(mm->mc, this->key);
+- if (parent)
+- this->parent = parent;
+- else
+- this->parent = mm->multi;
+- }
++ parent = get_offset_parent(mc, offset);
++ if (parent)
++ this->parent = parent;
++ else
++ this->parent = this->multi;
+
+ return 1;
+ }
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 819d6adc..f42af7b7 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -859,6 +859,10 @@ update_offset_entry(struct autofs_point *ap, const char *name,
+ }
+
+ ret = cache_update_offset(mc, name, m_key, m_mapent, age);
++
++ if (!cache_set_offset_parent(mc, m_key))
++ error(ap->logopt, "failed to set offset parent");
++
+ if (ret == CHE_DUPLICATE) {
+ warn(ap->logopt, MODPREFIX
+ "syntax error or duplicate offset %s -> %s", path, loc);
+@@ -1613,7 +1617,6 @@ dont_expand:
+ */
+ if (me == me->multi)
+ clean_stale_multi_triggers(ap, me, NULL, NULL);
+- cache_set_parents(me);
+
+ rv = mount_subtree(ap, me, name, NULL, options, ctxt);
+
--- /dev/null
+autofs-5.1.7 - simplify cache_get_parent()
+
+From: Ian Kent <raven@themaw.net>
+
+Eliminate the list traversal from get_parent() and rename it to
+get_offset_parent() to better describe it's usage.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ lib/cache.c | 46 ++++++++++++++++++++++++++++------------------
+ 2 files changed, 29 insertions(+), 18 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index e55fd66a..ee746277 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -7,6 +7,7 @@
+ - Fix option for master read wait.
+ - eliminate cache_lookup_offset() usage.
+ - fix is mounted check on non existent path.
++- simplify cache_get_parent().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/lib/cache.c b/lib/cache.c
+index d3b6642b..53f290cd 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -827,47 +827,57 @@ void cache_update_negative(struct mapent_cache *mc,
+ }
+
+
+-static struct mapent *get_parent(const char *key, struct list_head *head, struct list_head **pos)
++static struct mapent *get_offset_parent(struct mapent_cache *mc,
++ const char *key)
+ {
+- struct list_head *next;
+- struct mapent *this, *last;
+- int eq;
++ struct mapent *me;
++ char *parent, *tail;
++ int key_len;
+
+- last = NULL;
+- next = *pos ? (*pos)->next : head->next;
++ key_len = strlen(key);
+
+- list_for_each(next, head) {
+- this = list_entry(next, struct mapent, multi_list);
++ /* Check if this is the root offset */
++ if (key[key_len - 1] == '/')
++ return NULL;
++
++ parent = strdup(key);
++ tail = &parent[key_len - 1];
+
+- if (!strcmp(this->key, key))
++ while (*tail) {
++ while (*tail != '/')
++ tail--;
++
++ *tail = 0;
++
++ tail--;
++ if (tail == parent)
+ break;
+
+- eq = strncmp(this->key, key, strlen(this->key));
+- if (eq == 0) {
+- *pos = next;
+- last = this;
+- continue;
++ me = cache_lookup_distinct(mc, parent);
++ if (me) {
++ free(parent);
++ return me;
+ }
+ }
++ free(parent);
+
+- return last;
++ return NULL;
+ }
+
+ int cache_set_parents(struct mapent *mm)
+ {
+- struct list_head *multi_head, *p, *pos;
++ struct list_head *multi_head, *p;
+ struct mapent *this;
+
+ if (!mm->multi)
+ return 0;
+
+- pos = NULL;
+ multi_head = &mm->multi->multi_list;
+
+ list_for_each(p, multi_head) {
+ struct mapent *parent;
+ this = list_entry(p, struct mapent, multi_list);
+- parent = get_parent(this->key, multi_head, &pos);
++ parent = get_offset_parent(mm->mc, this->key);
+ if (parent)
+ this->parent = parent;
+ else
--- /dev/null
+autofs-5.1.7 - simplify mount_subtree() mount check
+
+From: Ian Kent <raven@themaw.net>
+
+The check of the return from sun_mount() following the possible mount
+of the root offset in mount_subtree() can be simpler.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 10 +---------
+ 2 files changed, 2 insertions(+), 9 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index b1ce7b69..f5c5641a 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -13,6 +13,7 @@
+ - remove unused parameter form do_mount_autofs_offset().
+ - refactor umount_multi_triggers().
+ - eliminate clean_stale_multi_triggers().
++- simplify mount_subtree() mount check.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index f4d5125c..1142e8a3 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1203,15 +1203,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent *me,
+ free(ro_loc);
+ }
+
+- if (ro && rv == 0) {
+- 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, mm_root, start, mm_base);
+- return 1;
+- }
+- } else if (rv <= 0) {
++ if ((ro && rv == 0) || rv <= 0) {
+ ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
+ if (ret == -1) {
+ error(ap->logopt, MODPREFIX
--- /dev/null
+autofs-5.1.7 - switch to use tree implementation for offsets
+
+From: Ian Kent <raven@themaw.net>
+
+Change to use the tree mapent implementation for the handling
+of offset mounts.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1
+ daemon/automount.c | 25 ++----------
+ daemon/lookup.c | 2 -
+ include/automount.h | 8 ++--
+ lib/cache.c | 67 ---------------------------------
+ lib/mounts.c | 4 +-
+ modules/lookup_program.c | 2 -
+ modules/parse_sun.c | 94 ++++++++++++----------------------------------
+ 8 files changed, 39 insertions(+), 164 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 892f7581..5ac09f77 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -40,6 +40,7 @@
+ - add tree_mapent_cleanup_offsets().
+ - add set_offset_tree_catatonic().
+ - add mount and umount offsets functions.
++- switch to use tree implementation for offsets.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index f4608fc9..7833dfae 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -551,29 +551,15 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+ left = 0;
+
+ if (me && IS_MM(me)) {
+- char root[PATH_MAX + 1];
+ char key[PATH_MAX + 1];
+ struct mapent *tmp;
+- int status;
+- char *base;
+-
+- if (!strchr(MM_ROOT(me)->key, '/'))
+- /* Indirect multi-mount root */
+- /* sprintf okay - if it's mounted, it's
+- * PATH_MAX or less bytes */
+- sprintf(root, "%s/%s", ap->path, MM_ROOT(me)->key);
+- else
+- strcpy(root, MM_ROOT(me)->key);
+-
+- if (IS_MM_ROOT(me))
+- base = NULL;
+- else
+- base = me->key + strlen(root);
++ int ret;
+
+- left = umount_multi_triggers(ap, me, root, base);
+- if (left) {
++ ret = tree_mapent_umount_offsets(me, 1);
++ if (!ret) {
+ warn(ap->logopt,
+ "some offset mounts still present under %s", path);
++ left++;
+ }
+
+ strcpy(key, me->key);
+@@ -589,8 +575,7 @@ static int umount_subtree_mounts(struct autofs_point *ap, const char *path, unsi
+ }
+
+ if (!left && IS_MM_ROOT(me)) {
+- status = cache_delete_offset_list(mc, me->key);
+- if (status != CHE_OK) {
++ if (!tree_mapent_delete_offsets(mc, me->key)) {
+ warn(ap->logopt, "couldn't delete offset list");
+ left++;
+ }
+diff --git a/daemon/lookup.c b/daemon/lookup.c
+index 5116b927..32dbc24d 100644
+--- a/daemon/lookup.c
++++ b/daemon/lookup.c
+@@ -843,7 +843,7 @@ static int lookup_amd_instance(struct autofs_point *ap,
+ return NSS_STATUS_UNKNOWN;
+ }
+
+- m_key = malloc(ap->len + strlen(MM_ROOT(me)->key) + 2);
++ m_key = malloc(ap->len + MM_ROOT(me)->len + 2);
+ if (!m_key) {
+ error(ap->logopt,
+ "failed to allocate storage for search key");
+diff --git a/include/automount.h b/include/automount.h
+index f6023e27..a71b8674 100644
+--- a/include/automount.h
++++ b/include/automount.h
+@@ -187,10 +187,10 @@ struct mapent {
+ ino_t ino;
+ };
+
+-#define IS_MM(me) (me->multi)
+-#define IS_MM_ROOT(me) (me->multi == me)
+-#define MM_ROOT(me) (me->multi)
+-#define MM_PARENT(me) (me->parent)
++#define IS_MM(me) (me->mm_root)
++#define IS_MM_ROOT(me) (me->mm_root == &me->node)
++#define MM_ROOT(me) (MAPENT(me->mm_root))
++#define MM_PARENT(me) (MAPENT(me->mm_parent))
+
+ void cache_lock_cleanup(void *arg);
+ void cache_readlock(struct mapent_cache *mc);
+diff --git a/lib/cache.c b/lib/cache.c
+index 7c409a56..93b02daf 100644
+--- a/lib/cache.c
++++ b/lib/cache.c
+@@ -682,14 +682,6 @@ int cache_update_offset(struct mapent_cache *mc, const char *mkey, const char *k
+ return CHE_FAIL;
+ }
+
+- me = cache_lookup_distinct(mc, key);
+- if (me) {
+- cache_add_ordered_offset(me, &owner->multi_list);
+- MM_ROOT(me) = owner;
+- goto done;
+- }
+- ret = CHE_FAIL;
+-done:
+ return ret;
+ }
+
+@@ -958,65 +950,6 @@ done:
+ return ret;
+ }
+
+-/* cache must be write locked by caller */
+-int cache_delete_offset_list(struct mapent_cache *mc, const char *key)
+-{
+- unsigned logopt = mc->ap ? mc->ap->logopt : master_get_logopt();
+- struct mapent *me;
+- struct mapent *this;
+- struct list_head *head, *next;
+- int remain = 0;
+- int status;
+-
+- me = cache_lookup_distinct(mc, key);
+- if (!me)
+- return CHE_FAIL;
+-
+- /* Not offset list owner */
+- if (!IS_MM_ROOT(me))
+- return CHE_FAIL;
+-
+- head = &me->multi_list;
+- next = head->next;
+- while (next != head) {
+- this = list_entry(next, struct mapent, multi_list);
+- next = next->next;
+- if (this->ioctlfd != -1) {
+- error(logopt,
+- "active offset mount key %s", this->key);
+- return CHE_FAIL;
+- }
+- }
+-
+- head = &me->multi_list;
+- next = head->next;
+- while (next != head) {
+- this = list_entry(next, struct mapent, multi_list);
+- next = next->next;
+- list_del_init(&this->multi_list);
+- MM_ROOT(this) = NULL;
+- debug(logopt, "deleting offset key %s", this->key);
+- status = cache_delete(mc, this->key);
+- if (status == CHE_FAIL) {
+- warn(logopt,
+- "failed to delete offset %s", this->key);
+- MM_ROOT(this) = me;
+- /* TODO: add list back in */
+- remain++;
+- }
+- }
+-
+- if (!remain) {
+- list_del_init(&me->multi_list);
+- MM_ROOT(me) = NULL;
+- }
+-
+- if (remain)
+- return CHE_FAIL;
+-
+- return CHE_OK;
+-}
+-
+ void cache_release(struct map_source *map)
+ {
+ struct mapent_cache *mc;
+diff --git a/lib/mounts.c b/lib/mounts.c
+index f7c29475..6ca7eff1 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -2893,7 +2893,7 @@ void set_indirect_mount_tree_catatonic(struct autofs_point *ap)
+
+ /* Only need to set offset mounts catatonic */
+ if (IS_MM(me) && IS_MM_ROOT(me))
+- set_multi_mount_tree_catatonic(ap, me);
++ set_offset_tree_catatonic(ap, me);
+ next:
+ me = cache_enumerate(mc, me);
+ }
+@@ -2913,7 +2913,7 @@ void set_direct_mount_tree_catatonic(struct autofs_point *ap, struct mapent *me)
+ {
+ /* Set offset mounts catatonic for this mapent */
+ if (IS_MM(me) && IS_MM_ROOT(me))
+- set_multi_mount_tree_catatonic(ap, me);
++ set_offset_tree_catatonic(ap, me);
+ set_mount_catatonic(ap, me, me->ioctlfd);
+ }
+
+diff --git a/modules/lookup_program.c b/modules/lookup_program.c
+index 70f27545..6cab52c8 100644
+--- a/modules/lookup_program.c
++++ b/modules/lookup_program.c
+@@ -658,7 +658,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
+ me = cache_lookup_distinct(mc, name);
+ if (me) {
+ if (IS_MM(me))
+- cache_delete_offset_list(mc, name);
++ tree_mapent_delete_offsets(mc, name);
+ cache_delete(mc, name);
+ }
+ cache_unlock(mc);
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index b1f64ca0..d6ef48b8 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -854,8 +854,8 @@ update_offset_entry(struct autofs_point *ap,
+ cache_writelock(mc);
+ ret = cache_update_offset(mc, name, m_key, m_mapent, age);
+
+- if (!cache_set_offset_parent(mc, m_key))
+- error(ap->logopt, "failed to set offset parent");
++ if (!tree_mapent_add_node(mc, name, m_key))
++ error(ap->logopt, "failed to add offset %s to tree", m_key);
+ cache_unlock(mc);
+
+ if (ret == CHE_DUPLICATE) {
+@@ -1134,10 +1134,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ const char *name, char *loc, char *options, void *ctxt)
+ {
+ struct mapent *me;
+- struct mapent *ro;
+- char *mm_root, *mm_base, *mm_key;
+- unsigned int mm_root_len;
+- int start, ret = 0, rv;
++ int ret = 0, rv;
+
+ cache_readlock(mc);
+ me = cache_lookup_distinct(mc, name);
+@@ -1148,34 +1145,18 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+
+ rv = 0;
+
+- mm_key = MM_ROOT(me)->key;
+-
+- if (*mm_key == '/') {
+- mm_root = mm_key;
+- start = strlen(mm_key);
+- } else {
+- start = ap->len + strlen(mm_key) + 1;
+- mm_root = alloca(start + 3);
+- strcpy(mm_root, ap->path);
+- strcat(mm_root, "/");
+- strcat(mm_root, mm_key);
+- }
+- mm_root_len = strlen(mm_root);
+-
+ if (IS_MM_ROOT(me)) {
+ char key[PATH_MAX + 1];
++ struct mapent *ro;
++ size_t len;
+
+- if (mm_root_len + 1 > PATH_MAX) {
++ len = mount_fullpath(key, PATH_MAX, ap->path, me->key);
++ if (!len) {
+ warn(ap->logopt, "path loo long");
+ return 1;
+ }
+-
+- /* name = NULL */
+- /* destination = mm_root */
+- mm_base = "/";
+-
+- strcpy(key, mm_root);
+- strcat(key, mm_base);
++ key[len] = '/';
++ key[len + 1] = 0;
+
+ /* Mount root offset if it exists */
+ ro = cache_lookup_distinct(me->mc, key);
+@@ -1194,7 +1175,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ warn(ap->logopt,
+ MODPREFIX "failed to parse root offset");
+ cache_writelock(mc);
+- cache_delete_offset_list(mc, name);
++ tree_mapent_delete_offsets(mc, name);
+ cache_unlock(mc);
+ return 1;
+ }
+@@ -1209,10 +1190,10 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ free(ro_loc);
+ }
+
+- if ((ro && rv == 0) || rv <= 0) {
+- ret = mount_multi_triggers(ap, me, mm_root, start, mm_base);
+- if (ret == -1) {
+- cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
++ if (rv <= 0) {
++ ret = tree_mapent_mount_offsets(me, 1);
++ if (!ret) {
++ tree_mapent_cleanup_offsets(me);
+ cache_unlock(mc);
+ error(ap->logopt, MODPREFIX
+ "failed to mount offset triggers");
+@@ -1223,39 +1204,14 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ int loclen = strlen(loc);
+ int namelen = strlen(name);
+
+- /* name = mm_root + mm_base */
+- /* destination = mm_root + mm_base = name */
+- mm_base = &me->key[start];
+-
++ /* Mounts at nesting points must succeed for subtree
++ * offsets to be mounted.
++ */
+ rv = sun_mount(ap, name, name, namelen, loc, loclen, options, ctxt);
+ if (rv == 0) {
+- ret = mount_multi_triggers(ap, me->multi, name, start, mm_base);
+- if (ret == -1) {
+- cleanup_multi_triggers(ap, me, name, start, mm_base);
+- cache_unlock(mc);
+- error(ap->logopt, MODPREFIX
+- "failed to mount offset triggers");
+- return 1;
+- }
+- } else if (rv < 0) {
+- 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) {
+- cache_unlock(mc);
+- warn(ap->logopt, MODPREFIX "path too long");
+- cache_writelock(mc);
+- cache_delete_offset_list(mc, name);
+- cache_unlock(mc);
+- return 1;
+- }
+-
+- strcpy(mm_root_base, mm_root);
+- strcat(mm_root_base, mm_base);
+-
+- ret = mount_multi_triggers(ap, me->multi, mm_root_base, start, mm_base);
+- if (ret == -1) {
+- cleanup_multi_triggers(ap, me, mm_root, start, mm_base);
++ ret = tree_mapent_mount_offsets(me, 1);
++ if (!ret) {
++ tree_mapent_cleanup_offsets(me);
+ cache_unlock(mc);
+ error(ap->logopt, MODPREFIX
+ "failed to mount offset triggers");
+@@ -1265,7 +1221,7 @@ static int mount_subtree(struct autofs_point *ap, struct mapent_cache *mc,
+ }
+ cache_unlock(mc);
+
+- /* Mount for base of tree failed */
++ /* strict mount failed */
+ if (rv > 0)
+ return rv;
+
+@@ -1506,7 +1462,7 @@ dont_expand:
+
+ /* So we know we're the multi-mount root */
+ if (!IS_MM(me))
+- me->multi = me;
++ MAPENT_SET_ROOT(me, tree_mapent_root(me))
+ else {
+ /*
+ * The amd host mount type assumes the lookup name
+@@ -1556,7 +1512,7 @@ dont_expand:
+ if (!m_offset) {
+ warn(ap->logopt, MODPREFIX "null path or out of memory");
+ cache_writelock(mc);
+- cache_delete_offset_list(mc, name);
++ tree_mapent_delete_offsets(mc, name);
+ cache_unlock(mc);
+ free(options);
+ free(pmapent);
+@@ -1573,7 +1529,7 @@ dont_expand:
+ l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
+ if (!l) {
+ cache_writelock(mc);
+- cache_delete_offset_list(mc, name);
++ tree_mapent_delete_offsets(mc, name);
+ cache_unlock(mc);
+ free(m_offset);
+ free(options);
+@@ -1592,7 +1548,7 @@ dont_expand:
+ if (status != CHE_OK) {
+ warn(ap->logopt, MODPREFIX "error adding multi-mount");
+ cache_writelock(mc);
+- cache_delete_offset_list(mc, name);
++ tree_mapent_delete_offsets(mc, name);
+ cache_unlock(mc);
+ free(m_offset);
+ free(options);
--- /dev/null
+autofs-5.1.7 - use default stack size for threads
+
+From: Ian Kent <raven@themaw.net>
+
+autofs uses PTHREAD_STACK_MIN to set the stack size for threads it
+creates.
+
+In two cases it is used to reduce the stack size for long running
+service threads while it's used to allocate a larger stack for worker
+threads that can have larger memory requirements.
+
+In recent glibc releases PTHREAD_STACK_MIN is no longer a constant
+which can lead to unexpectedly different stack sizes on different
+architectures and the autofs assumption it's a constant causes a
+compile failure.
+
+The need to alter the stack size was due to observed stack overflow
+which was thought to be due the thread stack being too small for autofs
+and glibc alloca(3) usage.
+
+Quite a bit of that alloca(3) usage has been eliminated from autofs now,
+particularly those that might be allocating largish amounts of storage,
+and there has been a lot of change in glibc too so using the thread
+default stack should be ok.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ daemon/automount.c | 29 -----------------------------
+ daemon/state.c | 6 +-----
+ lib/alarm.c | 6 +-----
+ 4 files changed, 3 insertions(+), 39 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 2b7cfaa0..61f3547a 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -80,6 +80,7 @@
+ - fix nonstrict offset mount fail handling.
+ - fix concat_options() error handling.
+ - eliminate some more alloca usage.
++- use default stack size for threads.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/daemon/automount.c b/daemon/automount.c
+index 23235a7d..d7432350 100644
+--- a/daemon/automount.c
++++ b/daemon/automount.c
+@@ -84,7 +84,6 @@ static size_t kpkt_len;
+ /* Attributes for creating detached and joinable threads */
+ pthread_attr_t th_attr;
+ pthread_attr_t th_attr_detached;
+-size_t detached_thread_stack_size = PTHREAD_STACK_MIN * 144;
+
+ struct master_readmap_cond mrc = {
+ PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, NULL, 0, 0, 0, 0};
+@@ -2620,34 +2619,6 @@ int main(int argc, char *argv[])
+ exit(1);
+ }
+
+-#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+- if (pthread_attr_setstacksize(
+- &th_attr_detached, detached_thread_stack_size)) {
+- logerr("%s: failed to set stack size thread attribute!",
+- program);
+- if (start_pipefd[1] != -1) {
+- res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat));
+- close(start_pipefd[1]);
+- }
+- release_flag_file();
+- macro_free_global_table();
+- exit(1);
+- }
+-#endif
+-
+- if (pthread_attr_getstacksize(
+- &th_attr_detached, &detached_thread_stack_size)) {
+- logerr("%s: failed to get detached thread stack size!",
+- program);
+- if (start_pipefd[1] != -1) {
+- res = write(start_pipefd[1], pst_stat, sizeof(*pst_stat));
+- close(start_pipefd[1]);
+- }
+- release_flag_file();
+- macro_free_global_table();
+- exit(1);
+- }
+-
+ info(logging, "Starting automounter version %s, master map %s",
+ version, master_list->name);
+ info(logging, "using kernel protocol version %d.%02d",
+diff --git a/daemon/state.c b/daemon/state.c
+index 5156bb21..5df05619 100644
+--- a/daemon/state.c
++++ b/daemon/state.c
+@@ -1177,12 +1177,8 @@ int st_start_handler(void)
+ status = pthread_attr_init(pattrs);
+ if (status)
+ pattrs = NULL;
+- else {
++ else
+ pthread_attr_setdetachstate(pattrs, PTHREAD_CREATE_DETACHED);
+-#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+- pthread_attr_setstacksize(pattrs, PTHREAD_STACK_MIN*4);
+-#endif
+- }
+
+ status = pthread_create(&thid, pattrs, st_queue_handler, NULL);
+
+diff --git a/lib/alarm.c b/lib/alarm.c
+index f27e13c4..1631a9bc 100755
+--- a/lib/alarm.c
++++ b/lib/alarm.c
+@@ -270,12 +270,8 @@ int alarm_start_handler(void)
+ status = pthread_attr_init(pattrs);
+ if (status)
+ pattrs = NULL;
+- else {
++ else
+ pthread_attr_setdetachstate(pattrs, PTHREAD_CREATE_DETACHED);
+-#ifdef _POSIX_THREAD_ATTR_STACKSIZE
+- pthread_attr_setstacksize(pattrs, PTHREAD_STACK_MIN*4);
+-#endif
+- }
+
+ status = pthread_condattr_init(&condattrs);
+ if (status)
--- /dev/null
+autofs-5.1.7 - use mapent tree root for tree_mapent_add_node()
+
+From: Ian Kent <raven@themaw.net>
+
+Since we need to create the offset tree after adding the offset entries
+to the mapent cache lookup the root mapent once and use it when calling
+tree_mapent_add_node() instread of doing a cache lookup on every node
+addition.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ include/mounts.h | 2 +-
+ lib/mounts.c | 24 +++++-------------------
+ modules/parse_sun.c | 11 ++++++++++-
+ 4 files changed, 17 insertions(+), 21 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 7b360f52..5a767360 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -72,6 +72,7 @@
+ - fix lookup_prune_one_cache() refactoring change.
+ - fix amd hosts mount expire.
+ - fix offset entries order.
++- use mapent tree root for tree_mapent_add_node().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/include/mounts.h b/include/mounts.h
+index 1b376b3d..f7768ce5 100644
+--- a/include/mounts.h
++++ b/include/mounts.h
+@@ -170,7 +170,7 @@ void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap);
+ void mnts_put_expire_list(struct list_head *mnts);
+ void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned int flags);
+ struct tree_node *tree_mapent_root(struct mapent *me);
+-int tree_mapent_add_node(struct mapent_cache *mc, const char *base, const char *key);
++int tree_mapent_add_node(struct mapent_cache *mc, struct tree_node *root, const char *key);
+ int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key);
+ void tree_mapent_cleanup_offsets(struct mapent *oe);
+ int tree_mapent_mount_offsets(struct mapent *oe, int nonstrict);
+diff --git a/lib/mounts.c b/lib/mounts.c
+index c24d1a88..9ec547ea 100644
+--- a/lib/mounts.c
++++ b/lib/mounts.c
+@@ -1519,27 +1519,13 @@ static void tree_mapent_free(struct tree_node *n)
+ }
+
+ int tree_mapent_add_node(struct mapent_cache *mc,
+- const char *root, const char *key)
++ struct tree_node *root, const char *key)
+ {
+ unsigned int logopt = mc->ap->logopt;
+- struct tree_node *tree, *n;
+- struct mapent *base;
++ struct tree_node *n;
+ struct mapent *parent;
+ struct mapent *me;
+
+- base = cache_lookup_distinct(mc, root);
+- if (!base) {
+- error(logopt,
+- "failed to find multi-mount root for key %s", key);
+- return 0;
+- }
+-
+- if (MAPENT_ROOT(base) != MAPENT_NODE(base)) {
+- error(logopt, "key %s is not multi-mount root", root);
+- return 0;
+- }
+- tree = MAPENT_ROOT(base);
+-
+ me = cache_lookup_distinct(mc, key);
+ if (!me) {
+ error(logopt,
+@@ -1547,16 +1533,16 @@ int tree_mapent_add_node(struct mapent_cache *mc,
+ return 0;
+ }
+
+- n = tree_add_node(tree, me);
++ n = tree_add_node(root, me);
+ if (!n)
+ return 0;
+
+- MAPENT_SET_ROOT(me, tree)
++ MAPENT_SET_ROOT(me, root)
+
+ /* Set the subtree parent */
+ parent = cache_get_offset_parent(mc, key);
+ if (!parent)
+- MAPENT_SET_PARENT(me, tree)
++ MAPENT_SET_PARENT(me, root)
+ else
+ MAPENT_SET_PARENT(me, MAPENT_NODE(parent))
+
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index b206a326..c75bcc8e 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1536,8 +1536,17 @@ dont_expand:
+ } while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
+
+ cache_writelock(mc);
++ me = cache_lookup_distinct(mc, name);
++ if (!me) {
++ cache_unlock(mc);
++ free(options);
++ free(pmapent);
++ cleanup_offset_entries(ap, mc, &offsets);
++ pthread_setcancelstate(cur_state, NULL);
++ return 1;
++ }
+ list_for_each_entry_safe(oe, tmp, &offsets, work) {
+- if (!tree_mapent_add_node(mc, name, oe->key))
++ if (!tree_mapent_add_node(mc, MAPENT_ROOT(me), oe->key))
+ error(ap->logopt, "failed to add offset %s to tree", oe->key);
+ list_del_init(&oe->work);
+ }
--- /dev/null
+autofs-5.1.7 - use mount_fullpath() in one spot in parse_mount()
+
+From: Ian Kent <raven@themaw.net>
+
+mount_fullpath() is meant to be used for this type of path construction
+so use it.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/parse_sun.c | 34 ++++++++--------------------------
+ 2 files changed, 9 insertions(+), 26 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 444ade5b..8494f0dc 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -43,6 +43,7 @@
+ - switch to use tree implementation for offsets.
+ - remove obsolete functions.
+ - remove redundant local var from sun_mount().
++- use mount_fullpath() in one spot in parse_mount().
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/parse_sun.c b/modules/parse_sun.c
+index 437869b5..d3fc6c7f 100644
+--- a/modules/parse_sun.c
++++ b/modules/parse_sun.c
+@@ -1354,36 +1354,18 @@ dont_expand:
+ debug(ap->logopt, MODPREFIX "gathered options: %s", options);
+
+ if (check_is_multi(p)) {
+- char *m_root = NULL;
++ char m_root[PATH_MAX + 1];
+ int m_root_len;
+ time_t age;
+ int l;
+
+- /* If name starts with "/" it's a direct mount */
+- if (*name == '/') {
+- m_root_len = name_len;
+- m_root = alloca(m_root_len + 1);
+- if (!m_root) {
+- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- free(options);
+- free(pmapent);
+- logerr(MODPREFIX "alloca: %s", estr);
+- return 1;
+- }
+- strcpy(m_root, name);
+- } else {
+- m_root_len = ap->len + name_len + 1;
+- m_root = alloca(m_root_len + 1);
+- if (!m_root) {
+- char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
+- free(options);
+- free(pmapent);
+- logerr(MODPREFIX "alloca: %s", estr);
+- return 1;
+- }
+- strcpy(m_root, ap->path);
+- strcat(m_root, "/");
+- strcat(m_root, name);
++ m_root_len = mount_fullpath(m_root, PATH_MAX, ap->path, name);
++ if (!m_root_len) {
++ error(ap->logopt,
++ MODPREFIX "multi-mount root path too long");
++ free(options);
++ free(pmapent);
++ return 1;
+ }
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state);
--- /dev/null
+autofs-5.1.7 - use snprintf() when constructing hosts mapent
+
+From: Ian Kent <raven@themaw.net>
+
+Using multiple strcpy() and strcat() functions when constructing the
+hosts map offset for each export is much slower than using a single
+sprintf() for each.
+
+Signed-off-by: Ian Kent <raven@themaw.net>
+---
+ CHANGELOG | 1 +
+ modules/lookup_hosts.c | 26 +++++++++++++-------------
+ 2 files changed, 14 insertions(+), 13 deletions(-)
+
+diff --git a/CHANGELOG b/CHANGELOG
+index 1bd6ac7f..d613e5ca 100644
+--- a/CHANGELOG
++++ b/CHANGELOG
+@@ -2,6 +2,7 @@
+ - add xdr_exports().
+ - remove mount.x and rpcgen dependencies.
+ - dont use realloc in host exports list processing.
++- use sprintf() when constructing hosts mapent.
+
+ 25/01/2021 autofs-5.1.7
+ - make bind mounts propagation slave by default.
+diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
+index e3ee0ab8..c1ebb7f6 100644
+--- a/modules/lookup_hosts.c
++++ b/modules/lookup_hosts.c
+@@ -87,10 +87,12 @@ int lookup_read_master(struct master *master, time_t age, void *context)
+ static char *get_exports(struct autofs_point *ap, const char *host)
+ {
+ char buf[MAX_ERR_BUF];
++ char entry[PATH_MAX + 1];
+ char *mapent;
+ struct exportinfo *exp, *this;
+ size_t hostlen = strlen(host);
+ size_t mapent_len;
++ int len, pos;
+
+ debug(ap->logopt, MODPREFIX "fetchng export list for %s", host);
+
+@@ -114,21 +116,19 @@ static char *get_exports(struct autofs_point *ap, const char *host)
+ }
+ *mapent = 0;
+
++ pos = 0;
+ this = exp;
+- while (this) {
+- if (!*mapent)
+- strcpy(mapent, "\"");
+- else
+- strcat(mapent, " \"");
+- strcat(mapent, this->dir);
+- strcat(mapent, "\"");
+-
+- strcat(mapent, " \"");
+- strcat(mapent, host);
+- strcat(mapent, ":");
+- strcat(mapent, this->dir);
+- strcat(mapent, "\"");
++ if (this) {
++ len = sprintf(mapent, "\"%s\" \"%s:%s\"",
++ this->dir, host, this->dir);
++ pos += len;
++ this = this->next;
++ }
+
++ while (this) {
++ len = sprintf(mapent + pos, " \"%s\" \"%s:%s\"",
++ this->dir, host, this->dir);
++ pos += len;
+ this = this->next;
+ }
+ rpc_exports_free(exp);
--- /dev/null
+autofs5/autofs-5.1.7-add-xdr_exports.patch
+autofs5/autofs-5.1.7-remove-mount_x-and-rpcgen-dependencies.patch
+autofs5/autofs-5.1.7-dont-use-realloc-in-host-exports-list-processing.patch
+autofs5/autofs-5.1.7-use-sprintf-when-constructing-hosts-mapent.patch
+autofs5/autofs-5.1.7-fix-mnts_remove_amdmount-uses-wrong-list.patch
+autofs5/autofs-5.1.7-Fix-option-for-master_read_wait.patch
+autofs5/autofs-5.1.7-eliminate-cache_lookup_offset-usage.patch
+autofs5/autofs-5.1.7-fix-is-mounted-check-on-non-existent-path.patch
+autofs5/autofs-5.1.7-simplify-get_parent.patch
+autofs5/autofs-5.1.7-set-offset-parent-in-update_offset_entry.patch
+autofs5/autofs-5.1.7-remove-redundant-variables-from-mount_autofs_offset.patch
+autofs5/autofs-5.1.7-remove-unused-parameter-form-do_mount_autofs_offset.patch
+autofs5/autofs-5.1.7-refactor-umount_multi_triggers.patch
+autofs5/autofs-5.1.7-eliminate-clean_stale_multi_triggers.patch
+autofs5/autofs-5.1.7-simplify-mount_subtree-mount-check.patch
+autofs5/autofs-5.1.7-fix-mnts_get_expire_list-expire-list-construction.patch
+autofs5/autofs-5.1.7-fix-inconsistent-locking-in-umount_subtree_mounts.patch
+autofs5/autofs-5.1.7-fix-return-from-umount_subtree_mounts-on-offset-list-delete.patch
+autofs5/autofs-5.1.7-pass-mapent_cache-to-update_offset_entry.patch
+autofs5/autofs-5.1.7-fix-inconsistent-locking-in-parse_mount.patch
+autofs5/autofs-5.1.7-remove-unused-mount-offset-list-lock-functions.patch
+autofs5/autofs-5.1.7-eliminate-count_mounts-from-expire_proc_indirect.patch
+autofs5/autofs-5.1.7-eliminate-some-strlen-calls-in-offset-handling.patch
+autofs5/autofs-5.1.7-dont-add-offset-mounts-to-mounted-mounts-table.patch
+autofs5/autofs-5.1.7-reduce-umount-EBUSY-check-delay.patch
+autofs5/autofs-5.1.7-cleanup-cache_delete-a-little.patch
+autofs5/autofs-5.1.7-rename-path-to-m_offset-in-update_offset_entry.patch
+autofs5/autofs-5.1.7-dont-pass-root-to-do_mount_autofs_offset.patch
+autofs5/autofs-5.1.7-rename-tree-implementation-functions.patch
+autofs5/autofs-5.1.7-add-some-multi-mount-macros.patch
+autofs5/autofs-5.1.7-remove-unused-functions-cache_dump_multi-and-cache_dump_cache.patch
+autofs5/autofs-5.1.7-add-a-len-field-to-struct-autofs_point.patch
+autofs5/autofs-5.1.7-make-tree-implementation-data-independent.patch
+autofs5/autofs-5.1.7-add-mapent-tree-implementation.patch
+autofs5/autofs-5.1.7-add-tree_mapent_add_node.patch
+autofs5/autofs-5.1.7-add-tree_mapent_delete_offsets.patch
+autofs5/autofs-5.1.7-add-tree_mapent_traverse_subtree.patch
+autofs5/autofs-5.1.7-fix-mount_fullpath.patch
+autofs5/autofs-5.1.7-add-tree_mapent_cleanup_offsets.patch
+autofs5/autofs-5.1.7-add-set_offset_tree_catatonic.patch
+autofs5/autofs-5.1.7-add-mount-and-umount-offsets-functions.patch
+autofs5/autofs-5.1.7-switch-to-use-tree-implementation-for-offsets.patch
+autofs5/autofs-5.1.7-remove-obsolete-functions.patch
+autofs5/autofs-5.1.7-remove-redundant-local-var-from-sun_mount.patch
+autofs5/autofs-5.1.7-use-mount_fullpath-in-one-spot-in-parse_mount.patch
+autofs5/autofs-5.1.7-pass-root-length-to-mount_fullpath.patch
+autofs5/autofs-5.1.7-remove-unused-function-master_submount_list_empty.patch
+autofs5/autofs-5.1.7-move-amd-mounts-removal-into-lib_mounts_c.patch
+autofs5/autofs-5.1.7-check-for-offset-with-no-mount-location.patch
+autofs5/autofs-5.1.7-remove-mounts_mutex.patch
+autofs5/autofs-5.1.7-remove-unused-variable-from-get_exports.patch
+autofs5/autofs-5.1.7-add-missing-free-in-handle_mounts.patch
+autofs5/autofs-5.1.7-remove-redundant-if-check.patch
+autofs5/autofs-5.1.7-fix-possible-memory-leak-in-master_parse.patch
+autofs5/autofs-5.1.7-fix-possible-memory-leak-in-mnts_add_amdmount.patch
+autofs5/autofs-5.1.7-fix-double-unlock-in-parse_mount.patch
+autofs5/autofs-5.1.7-add-length-check-in-umount_subtree_mounts.patch
+autofs5/autofs-5.1.7-fix-flag-check-in-umount_multi.patch
+autofs5/autofs-5.1.7-dont-try-umount-after-stat-ENOENT-fail.patch
+autofs5/autofs-5.1.7-remove-redundant-assignment-in-master_add_amd_mount_section_mounts.patch
+autofs5/autofs-5.1.7-fix-dead-code-in-mnts_add_mount.patch
+autofs5/autofs-5.1.7-fix-arg-not-used-in-print.patch
+autofs5/autofs-5.1.7-fix-missing-lock-release-in-mount_subtree.patch
+autofs5/autofs-5.1.7-fix-double-free-in-parse_mapent.patch
+autofs5/autofs-5.1.7-refactor-lookup_prune_one_cache-a-bit.patch
+autofs5/autofs-5.1.7-cater-for-empty-mounts-list-in-mnts_get_expire_list.patch
+autofs5/autofs-5.1.7-add-ext_mount_hash_mutex-lock-helpers.patch
+autofs5/autofs-5.1.7-fix-amd-section-mounts-map-reload.patch
+autofs5/autofs-5.1.7-fix-dandling-symlink-creation-if-nis-support-is-not-available.patch
+autofs5/autofs-5.1.7-dont-use-AUTOFS_DEV_IOCTL_CLOSEMOUNT.patch
+autofs5/autofs-5.1.7-fix-lookup_prune_one_cache-refactoring-change.patch
+autofs5/autofs-5.1.7-fix-amd-hosts-mount-expire.patch
+autofs5/autofs-5.1.7-fix-offset-entries-order.patch
+autofs5/autofs-5.1.7-use-mapent-tree-root-for-tree_mapent_add_node.patch
+autofs5/autofs-5.1.7-eliminate-redundant-cache-lookup-in-tree_mapent_add_node.patch
+autofs5/autofs-5.1.7-fix-hosts-map-offset-order.patch
+autofs5/autofs-5.1.7-fix-direct-mount-deadlock.patch
+autofs5/autofs-5.1.7-add-missing-description-of-null-map-option.patch
+autofs5/autofs-5.1.7-fix-nonstrict-offset-mount-fail-handling.patch
+autofs5/autofs-5.1.7-fix-concat_options-error-handling.patch
+autofs5/autofs-5.1.7-eliminate-some-more-alloca-usage.patch
+autofs5/autofs-5.1.7-use-default-stack-size-for-threads.patch
$(REMOVE)/autofs-$(AUTOFS4_VER)
$(TOUCH)
-AUTOFS5_PATCH = autofs-include-linux-nfs.h-directly-in-rpc_sub.patch
-AUTOFS5_PATCH += autofs-force-STRIP-to-empty.patch
+# cd package/autofs/patches
+# wget -N https://mirrors.edge.kernel.org/pub/linux/daemons/autofs/v5/patches-5.1.8/patch_order_5.1.7
+# for p in $(cat patch_order_5.1.7); do test -f $p || wget https://mirrors.edge.kernel.org/pub/linux/daemons/autofs/v5/patches-5.1.8/$p; done
+
+AUTOFS5_PATCH = autofs-force-STRIP-to-empty.patch
+AUTOFS5_PATCH += $(shell cat $(PATCHES)/autofs5/patch_order_$(AUTOFS5_VER))
$(D)/autofs5: $(D)/libtirpc $(ARCHIVE)/autofs-$(AUTOFS5_VER).tar.gz | $(TARGETPREFIX)
$(START_BUILD)
$(UNTAR)/autofs-$(AUTOFS5_VER).tar.gz
set -e; cd $(BUILD_TMP)/autofs-$(AUTOFS5_VER); \
$(call apply_patches, $(AUTOFS5_PATCH)); \
- export ac_cv_linux_procfs=yes; \
+ export ac_cv_path_E2FSCK=/sbin/fsck; \
+ export ac_cv_path_E3FSCK=no; \
+ export ac_cv_path_E4FSCK=no; \
export ac_cv_path_KRB5_CONFIG=no; \
export ac_cv_path_MODPROBE=/sbin/modprobe; \
- export ac_cv_path_RANLIB=$(TARGET)-ranlib; \
+ export ac_cv_path_MOUNT=/bin/mount; \
+ export ac_cv_path_MOUNT_NFS=/sbin/mount.nfs; \
+ export ac_cv_path_UMOUNT=/bin/umount; \
+ export ac_cv_linux_procfs=yes; \
autoreconf -fi; \
$(CONFIGURE) \
- --prefix= \
--datarootdir=/.remove \
--disable-mount-locking \
+ --enable-ignore-busy \
--without-openldap \
--without-sasl \
- --with-path=$(PATH) \
- --with-libtirpc \
+ --with-path="$(PATH)" \
--with-hesiod=no \
+ --with-libtirpc \
--with-confdir=/var/etc \
--with-mapdir=/var/etc \
--with-fifodir=/var/run \
--with-flagdir=/var/run \
; \
- $(MAKE) SUBDIRS="lib daemon modules" DONTSTRIP=1; \
- $(MAKE) SUBDIRS="lib daemon modules" install DESTDIR=$(TARGETPREFIX)
+ $(MAKE) DONTSTRIP=1; \
+ $(MAKE) install DESTDIR=$(TARGETPREFIX)
$(REMOVE)/autofs-$(AUTOFS5_VER)
$(TOUCH)
AUTOFS5_MAJOR = 5
AUTOFS5_MINOR = 1
-AUTOFS5_MICRO = 6
+AUTOFS5_MICRO = 7
AUTOFS5_VER = $(AUTOFS5_MAJOR).$(AUTOFS5_MINOR).$(AUTOFS5_MICRO)
BUSYBOX_VER = 1.32.1