From 36b08021228905420c057f037c8cb668cabd5e98 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Mon, 14 Jun 2021 18:51:16 +0800 Subject: [PATCH] - add changes for bugs 1965870, 1965863 and 1966380. --- ...ssing-description-of-null-map-option.patch | 51 ++++ ...cache-lookup-in-tree_mapent_add_node.patch | 82 +++++ autofs-5.1.7-fix-direct-mount-deadlock.patch | 129 ++++++++ autofs-5.1.7-fix-hosts-map-offset-order.patch | 289 ++++++++++++++++++ ...p_prune_one_cache-refactoring-change.patch | 56 ++++ autofs-5.1.7-fix-offset-entries-order.patch | 199 ++++++++++++ ...t-tree-root-for-tree_mapent_add_node.patch | 111 +++++++ autofs.spec | 30 +- 8 files changed, 946 insertions(+), 1 deletion(-) create mode 100644 autofs-5.1.7-add-missing-description-of-null-map-option.patch create mode 100644 autofs-5.1.7-eliminate-redundant-cache-lookup-in-tree_mapent_add_node.patch create mode 100644 autofs-5.1.7-fix-direct-mount-deadlock.patch create mode 100644 autofs-5.1.7-fix-hosts-map-offset-order.patch create mode 100644 autofs-5.1.7-fix-lookup_prune_one_cache-refactoring-change.patch create mode 100644 autofs-5.1.7-fix-offset-entries-order.patch create mode 100644 autofs-5.1.7-use-mapent-tree-root-for-tree_mapent_add_node.patch diff --git a/autofs-5.1.7-add-missing-description-of-null-map-option.patch b/autofs-5.1.7-add-missing-description-of-null-map-option.patch new file mode 100644 index 0000000..52d1e78 --- /dev/null +++ b/autofs-5.1.7-add-missing-description-of-null-map-option.patch @@ -0,0 +1,51 @@ +autofs-5.1.7 - add missing desciption of null map option + +From: Ian Kent + +The description of how the -null master map option behaves is +mising from auto.master(5). + +Signed-off-by: Ian Kent +--- + CHANGELOG | 1 + + man/auto.master.5.in | 19 +++++++++++++++++++ + 2 files changed, 20 insertions(+) + +--- autofs-5.1.7.orig/CHANGELOG ++++ autofs-5.1.7/CHANGELOG +@@ -75,6 +75,7 @@ + - fix hosts map offset order. + - fix direct mount deadlock. + - fix lookup_prune_one_cache() refactoring change. ++- add missing description of null map option. + + 25/01/2021 autofs-5.1.7 + - make bind mounts propagation slave by default. +--- autofs-5.1.7.orig/man/auto.master.5.in ++++ autofs-5.1.7/man/auto.master.5.in +@@ -265,6 +265,25 @@ accessing /net/myserver will mount expor + 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 diff --git a/autofs-5.1.7-eliminate-redundant-cache-lookup-in-tree_mapent_add_node.patch b/autofs-5.1.7-eliminate-redundant-cache-lookup-in-tree_mapent_add_node.patch new file mode 100644 index 0000000..14ca019 --- /dev/null +++ b/autofs-5.1.7-eliminate-redundant-cache-lookup-in-tree_mapent_add_node.patch @@ -0,0 +1,82 @@ +autofs-5.1.7 - eliminate redundant cache lookup in tree_mapent_add_node() + +From: Ian Kent + +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 +--- + CHANGELOG | 1 + + include/mounts.h | 2 +- + lib/mounts.c | 13 ++----------- + modules/parse_sun.c | 2 +- + 4 files changed, 5 insertions(+), 13 deletions(-) + +--- autofs-5.1.7.orig/CHANGELOG ++++ autofs-5.1.7/CHANGELOG +@@ -71,6 +71,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. +--- autofs-5.1.7.orig/include/mounts.h ++++ autofs-5.1.7/include/mounts.h +@@ -170,7 +170,7 @@ void mnts_get_expire_list(struct list_he + 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); +--- autofs-5.1.7.orig/lib/mounts.c ++++ autofs-5.1.7/lib/mounts.c +@@ -1519,19 +1519,10 @@ static void tree_mapent_free(struct tree + } + + 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_c + 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 +--- autofs-5.1.7.orig/modules/parse_sun.c ++++ autofs-5.1.7/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); + } diff --git a/autofs-5.1.7-fix-direct-mount-deadlock.patch b/autofs-5.1.7-fix-direct-mount-deadlock.patch new file mode 100644 index 0000000..ee08d24 --- /dev/null +++ b/autofs-5.1.7-fix-direct-mount-deadlock.patch @@ -0,0 +1,129 @@ +autofs-5.1.7 - fix direct mount deadlock + +From: Ian Kent + +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 +--- + CHANGELOG | 1 + + daemon/direct.c | 22 +++++++++++++++++++++- + daemon/state.c | 14 +++++++++----- + 3 files changed, 31 insertions(+), 6 deletions(-) + +--- autofs-5.1.7.orig/CHANGELOG ++++ autofs-5.1.7/CHANGELOG +@@ -73,6 +73,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. +--- autofs-5.1.7.orig/daemon/direct.c ++++ autofs-5.1.7/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_p + 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_p + * failed umount. + */ + error = do_umount_autofs_direct(ap, me); ++ /* cache became invalid, restart */ ++ if (error == -1) ++ goto restart; + if (!error) + goto done; + +--- autofs-5.1.7.orig/daemon/state.c ++++ autofs-5.1.7/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 auto + 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 auto + 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); diff --git a/autofs-5.1.7-fix-hosts-map-offset-order.patch b/autofs-5.1.7-fix-hosts-map-offset-order.patch new file mode 100644 index 0000000..3fcf58f --- /dev/null +++ b/autofs-5.1.7-fix-hosts-map-offset-order.patch @@ -0,0 +1,289 @@ +autofs-5.1.7 - fix hosts map offset order + +From: Ian Kent + +Map entry offset paths 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 use to mount the offset during parsing since the +path length of exports can cary 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 +--- + CHANGELOG | 1 + include/automount.h | 2 - + include/mounts.h | 8 +++++ + include/rpc_subs.h | 3 ++ + lib/mounts.c | 57 +++++++++++++++++++++++++++++++++++++-- + modules/lookup_hosts.c | 71 ++++++++++++++++++++++++++++++++++++++----------- + 6 files changed, 124 insertions(+), 18 deletions(-) + +--- autofs-5.1.7.orig/CHANGELOG ++++ autofs-5.1.7/CHANGELOG +@@ -72,6 +72,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. +--- autofs-5.1.7.orig/include/automount.h ++++ autofs-5.1.7/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" + +--- autofs-5.1.7.orig/include/mounts.h ++++ autofs-5.1.7/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 a + 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); +--- autofs-5.1.7.orig/include/rpc_subs.h ++++ autofs-5.1.7/include/rpc_subs.h +@@ -23,6 +23,8 @@ + #include + #include + ++#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 { +--- autofs-5.1.7.orig/lib/mounts.c ++++ autofs-5.1.7/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(s + 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 * + 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_he + 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); +--- autofs-5.1.7.orig/modules/lookup_hosts.c ++++ autofs-5.1.7/modules/lookup_hosts.c +@@ -84,14 +84,38 @@ int lookup_read_master(struct master *ma + 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_p + 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_p + } + *mapent = 0; + +- pos = 0; +- this = exp; +- 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; ++ wi.mapent = mapent; ++ wi.host = host; ++ wi.pos = 0; ++ ++ if (!tree) { ++ free(mapent); ++ mapent = NULL; ++ } else { ++ tree_traverse_inorder(tree, tree_host_work, &wi); ++ tree_free(tree); + } + rpc_exports_free(exp); + diff --git a/autofs-5.1.7-fix-lookup_prune_one_cache-refactoring-change.patch b/autofs-5.1.7-fix-lookup_prune_one_cache-refactoring-change.patch new file mode 100644 index 0000000..8f81881 --- /dev/null +++ b/autofs-5.1.7-fix-lookup_prune_one_cache-refactoring-change.patch @@ -0,0 +1,56 @@ +autofs-5.1.7 - fix lookup_prune_one_cache() refactoring change + +From: Ian Kent + +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 +--- + CHANGELOG | 1 + + daemon/lookup.c | 5 ++++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +--- autofs-5.1.7.orig/CHANGELOG ++++ autofs-5.1.7/CHANGELOG +@@ -74,6 +74,7 @@ + - eliminate redundant cache lookup in tree_mapent_add_node(). + - fix hosts map offset order. + - fix direct mount deadlock. ++- fix lookup_prune_one_cache() refactoring change. + + 25/01/2021 autofs-5.1.7 + - make bind mounts propagation slave by default. +--- autofs-5.1.7.orig/daemon/lookup.c ++++ autofs-5.1.7/daemon/lookup.c +@@ -1379,6 +1379,7 @@ void lookup_prune_one_cache(struct autof + if (!key || strchr(key, '*')) { + if (key) + free(key); ++ me = cache_enumerate(mc, me); + continue; + } + +@@ -1386,6 +1387,7 @@ void lookup_prune_one_cache(struct autof + 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 autof + } + 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) diff --git a/autofs-5.1.7-fix-offset-entries-order.patch b/autofs-5.1.7-fix-offset-entries-order.patch new file mode 100644 index 0000000..8843d2c --- /dev/null +++ b/autofs-5.1.7-fix-offset-entries-order.patch @@ -0,0 +1,199 @@ +autofs-5.1.7 - fix offset entries order + +From: Ian Kent + +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 +--- + CHANGELOG | 1 + include/automount.h | 1 + lib/cache.c | 1 + modules/parse_sun.c | 74 +++++++++++++++++++++++++++++++++++++++++----------- + 4 files changed, 62 insertions(+), 15 deletions(-) + +--- autofs-5.1.7.orig/CHANGELOG ++++ autofs-5.1.7/CHANGELOG +@@ -69,6 +69,7 @@ + - fix dangling symlink creation if nis support is not available. + - fix amd section mounts map reload. + - fix amd hosts mount expire. ++- fix offset entries order. + + 25/01/2021 autofs-5.1.7 + - make bind mounts propagation slave by default. +--- autofs-5.1.7.orig/include/automount.h ++++ autofs-5.1.7/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; +--- autofs-5.1.7.orig/lib/cache.c ++++ autofs-5.1.7/lib/cache.c +@@ -559,6 +559,7 @@ int cache_add(struct mapent_cache *mc, s + 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; +--- autofs-5.1.7.orig/modules/parse_sun.c ++++ autofs-5.1.7/modules/parse_sun.c +@@ -789,14 +789,15 @@ static int check_is_multi(const char *ma + + 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 + 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 + 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, + 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); diff --git a/autofs-5.1.7-use-mapent-tree-root-for-tree_mapent_add_node.patch b/autofs-5.1.7-use-mapent-tree-root-for-tree_mapent_add_node.patch new file mode 100644 index 0000000..33cba78 --- /dev/null +++ b/autofs-5.1.7-use-mapent-tree-root-for-tree_mapent_add_node.patch @@ -0,0 +1,111 @@ +autofs-5.1.7 - use mapent tree root for tree_mapent_add_node() + +From: Ian Kent + +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 +--- + CHANGELOG | 1 + + include/mounts.h | 2 +- + lib/mounts.c | 24 +++++------------------- + modules/parse_sun.c | 11 ++++++++++- + 4 files changed, 17 insertions(+), 21 deletions(-) + +--- autofs-5.1.7.orig/CHANGELOG ++++ autofs-5.1.7/CHANGELOG +@@ -70,6 +70,7 @@ + - fix amd section mounts map reload. + - 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. +--- autofs-5.1.7.orig/include/mounts.h ++++ autofs-5.1.7/include/mounts.h +@@ -170,7 +170,7 @@ void mnts_get_expire_list(struct list_he + 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); +--- autofs-5.1.7.orig/lib/mounts.c ++++ autofs-5.1.7/lib/mounts.c +@@ -1519,27 +1519,13 @@ static void tree_mapent_free(struct tree + } + + 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_c + 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)) + +--- autofs-5.1.7.orig/modules/parse_sun.c ++++ autofs-5.1.7/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); + } diff --git a/autofs.spec b/autofs.spec index 2fceadf..65a2b0a 100644 --- a/autofs.spec +++ b/autofs.spec @@ -12,7 +12,7 @@ Summary: A tool for automatically mounting and unmounting filesystems Name: autofs Version: 5.1.7 -Release: 15%{?dist} +Release: 16%{?dist} Epoch: 1 License: GPLv2+ Source: https://www.kernel.org/pub/linux/daemons/autofs/v5/autofs-%{version}-2.tar.gz @@ -90,6 +90,14 @@ Patch68: autofs-5.1.7-fix-dangling-symlink-creation-if-nis-support-is-not-availa Patch69: autofs-5.1.7-fix-amd-section-mounts-map-reload.patch Patch70: autofs-5.1.7-fix-amd-hosts-mount-expire.patch +Patch71: autofs-5.1.7-fix-offset-entries-order.patch +Patch72: autofs-5.1.7-use-mapent-tree-root-for-tree_mapent_add_node.patch +Patch73: autofs-5.1.7-eliminate-redundant-cache-lookup-in-tree_mapent_add_node.patch +Patch74: autofs-5.1.7-fix-hosts-map-offset-order.patch +Patch75: autofs-5.1.7-fix-direct-mount-deadlock.patch +Patch76: autofs-5.1.7-fix-lookup_prune_one_cache-refactoring-change.patch +Patch77: autofs-5.1.7-add-missing-description-of-null-map-option.patch + %if %{with_systemd} BuildRequires: systemd-units BuildRequires: systemd-devel @@ -225,6 +233,13 @@ echo %{version}-%{release} > .version %patch68 -p1 %patch69 -p1 %patch70 -p1 +%patch71 -p1 +%patch72 -p1 +%patch73 -p1 +%patch74 -p1 +%patch75 -p1 +%patch76 -p1 +%patch77 -p1 %build LDFLAGS=-Wl,-z,now @@ -333,6 +348,19 @@ fi %dir /etc/auto.master.d %changelog +* Mon Jun 14 2021 Ian Kent - 1:5.1.7-16 +- bz1965870 - autofs: regression in offset ordering + - 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. + - fix direct mount deadlock. +- bz1965863 - A recent Coverity change can cause an infinit loop on map reload + - fix lookup_prune_one_cache() refactoring change. +- bz1966380 - auto.master manpage doesn't mention -null or other built-in maps + - add missing desciption of null map option. +- Resolves: rhbz#1965870 rhbz#1965863 rhbz#1966380 + * Tue May 11 2021 Ian Kent - 1:5.1.7-15 - bz1942371 - Drop nis support from autofs - fix dangling symlink creation if nis support is not available