Blame SOURCES/autofs-5.1.7-fix-offset-entries-order.patch

96dc52
autofs-5.1.7 - fix offset entries order
96dc52
96dc52
From: Ian Kent <raven@themaw.net>
96dc52
96dc52
While it's rare it's possible that a mapent entry might not have
96dc52
it's offsets in shortest to longest path order.
96dc52
96dc52
If this happens adding an entry to the mapent tree can result in
96dc52
an incorrect tree topology that doesn't work. That's because adding
96dc52
tree entries ensures that nodes in a sub-tree are placed below the
96dc52
containing node so the containing node must be present for that to
96dc52
work. This topology is critical to the performance of map entries
96dc52
that have a very large number of offsets such as an NFS server with
96dc52
many exports.
96dc52
96dc52
There's no other choice but make a traversal after the offset entries
96dc52
have all been added to create the mapent tree.
96dc52
96dc52
Signed-off-by: Ian Kent <raven@themaw.net>
96dc52
---
96dc52
 CHANGELOG           |    1 
96dc52
 include/automount.h |    1 
96dc52
 lib/cache.c         |    1 
96dc52
 modules/parse_sun.c |   74 +++++++++++++++++++++++++++++++++++++++++-----------
96dc52
 4 files changed, 62 insertions(+), 15 deletions(-)
96dc52
96dc52
--- autofs-5.1.7.orig/CHANGELOG
96dc52
+++ autofs-5.1.7/CHANGELOG
96dc52
@@ -69,6 +69,7 @@
96dc52
 - fix dangling symlink creation if nis support is not available.
96dc52
 - fix amd section mounts map reload.
96dc52
 - fix amd hosts mount expire.
96dc52
+- fix offset entries order.
96dc52
 
96dc52
 25/01/2021 autofs-5.1.7
96dc52
 - make bind mounts propagation slave by default.
96dc52
--- autofs-5.1.7.orig/include/automount.h
96dc52
+++ autofs-5.1.7/include/automount.h
96dc52
@@ -169,6 +169,7 @@ struct mapent {
96dc52
 	/* Parent nesting point within multi-mount */
96dc52
 	struct tree_node *mm_parent;
96dc52
 	struct tree_node node;
96dc52
+	struct list_head work;
96dc52
 	char *key;
96dc52
 	size_t len;
96dc52
 	char *mapent;
96dc52
--- autofs-5.1.7.orig/lib/cache.c
96dc52
+++ autofs-5.1.7/lib/cache.c
96dc52
@@ -559,6 +559,7 @@ int cache_add(struct mapent_cache *mc, s
96dc52
 	me->mm_parent = NULL;
96dc52
 	INIT_TREE_NODE(&me->node);
96dc52
 	INIT_LIST_HEAD(&me->ino_index);
96dc52
+	INIT_LIST_HEAD(&me->work);
96dc52
 	me->ioctlfd = -1;
96dc52
 	me->dev = (dev_t) -1;
96dc52
 	me->ino = (ino_t) -1;
96dc52
--- autofs-5.1.7.orig/modules/parse_sun.c
96dc52
+++ autofs-5.1.7/modules/parse_sun.c
96dc52
@@ -789,14 +789,15 @@ static int check_is_multi(const char *ma
96dc52
 
96dc52
 static int
96dc52
 update_offset_entry(struct autofs_point *ap,
96dc52
-		    struct mapent_cache *mc, const char *name,
96dc52
-		    const char *m_root, int m_root_len,
96dc52
+		    struct mapent_cache *mc, struct list_head *offsets,
96dc52
+		    const char *name, const char *m_root, int m_root_len,
96dc52
 		    const char *m_offset, const char *myoptions,
96dc52
 		    const char *loc, time_t age)
96dc52
 {
96dc52
 	char m_key[PATH_MAX + 1];
96dc52
 	char m_mapent[MAPENT_MAX_LEN + 1];
96dc52
 	int o_len, m_key_len, m_options_len, m_mapent_len;
96dc52
+	struct mapent *me;
96dc52
 	int ret;
96dc52
 
96dc52
 	memset(m_mapent, 0, MAPENT_MAX_LEN + 1);
96dc52
@@ -862,8 +863,29 @@ update_offset_entry(struct autofs_point
96dc52
 	cache_writelock(mc);
96dc52
 	ret = cache_update_offset(mc, name, m_key, m_mapent, age);
96dc52
 
96dc52
-	if (!tree_mapent_add_node(mc, name, m_key))
96dc52
-		error(ap->logopt, "failed to add offset %s to tree", m_key);
96dc52
+	me = cache_lookup_distinct(mc, m_key);
96dc52
+	if (me && list_empty(&me->work)) {
96dc52
+		struct list_head *last;
96dc52
+
96dc52
+		/* Offset entries really need to be in shortest to
96dc52
+		 * longest path order. If not and the list of offsets
96dc52
+		 * is large there will be a performace hit.
96dc52
+		 */
96dc52
+		list_for_each_prev(last, offsets) {
96dc52
+			struct mapent *this;
96dc52
+
96dc52
+			this = list_entry(last, struct mapent, work);
96dc52
+			if (me->len >= this->len) {
96dc52
+				if (last->next == offsets)
96dc52
+					list_add_tail(&me->work, offsets);
96dc52
+				else
96dc52
+					list_add_tail(&me->work, last);
96dc52
+				break;
96dc52
+			}
96dc52
+		}
96dc52
+		if (list_empty(&me->work))
96dc52
+			list_add(&me->work, offsets);
96dc52
+	}
96dc52
 	cache_unlock(mc);
96dc52
 
96dc52
 	if (ret == CHE_DUPLICATE) {
96dc52
@@ -1209,6 +1231,25 @@ static char *do_expandsunent(const char
96dc52
 	return mapent;
96dc52
 }
96dc52
 
96dc52
+static void cleanup_offset_entries(struct autofs_point *ap,
96dc52
+				   struct mapent_cache *mc,
96dc52
+				   struct list_head *offsets)
96dc52
+{
96dc52
+	struct mapent *me, *tmp;
96dc52
+	int ret;
96dc52
+
96dc52
+	if (list_empty(offsets))
96dc52
+		return;
96dc52
+	cache_writelock(mc);
96dc52
+	list_for_each_entry_safe(me, tmp, offsets, work) {
96dc52
+		list_del(&me->work);
96dc52
+		ret = cache_delete(mc, me->key);
96dc52
+		if (ret != CHE_OK)
96dc52
+			crit(ap->logopt, "failed to delete offset %s", me->key);
96dc52
+	}
96dc52
+	cache_unlock(mc);
96dc52
+}
96dc52
+
96dc52
 /*
96dc52
  * syntax is:
96dc52
  *	[-options] location [location] ...
96dc52
@@ -1228,7 +1269,8 @@ int parse_mount(struct autofs_point *ap,
96dc52
 	char buf[MAX_ERR_BUF];
96dc52
 	struct map_source *source;
96dc52
 	struct mapent_cache *mc;
96dc52
-	struct mapent *me;
96dc52
+	struct mapent *me, *oe, *tmp;
96dc52
+	LIST_HEAD(offsets);
96dc52
 	char *pmapent, *options;
96dc52
 	const char *p;
96dc52
 	int mapent_len, rv = 0;
96dc52
@@ -1444,9 +1486,7 @@ dont_expand:
96dc52
 
96dc52
 			if (!m_offset) {
96dc52
 				warn(ap->logopt, MODPREFIX "null path or out of memory");
96dc52
-				cache_writelock(mc);
96dc52
-				tree_mapent_delete_offsets(mc, name);
96dc52
-				cache_unlock(mc);
96dc52
+				cleanup_offset_entries(ap, mc, &offsets);
96dc52
 				free(options);
96dc52
 				free(pmapent);
96dc52
 				pthread_setcancelstate(cur_state, NULL);
96dc52
@@ -1461,9 +1501,7 @@ dont_expand:
96dc52
 
96dc52
 			l = parse_mapent(p, options, &myoptions, &loc, ap->logopt);
96dc52
 			if (!l) {
96dc52
-				cache_writelock(mc);
96dc52
-				tree_mapent_delete_offsets(mc, name);
96dc52
-				cache_unlock(mc);
96dc52
+				cleanup_offset_entries(ap, mc, &offsets);
96dc52
 				free(m_offset);
96dc52
 				free(options);
96dc52
 				free(pmapent);
96dc52
@@ -1474,15 +1512,13 @@ dont_expand:
96dc52
 			p += l;
96dc52
 			p = skipspace(p);
96dc52
 
96dc52
-			status = update_offset_entry(ap, mc,
96dc52
+			status = update_offset_entry(ap, mc, &offsets,
96dc52
 						     name, m_root, m_root_len,
96dc52
 						     m_offset, myoptions, loc, age);
96dc52
 
96dc52
 			if (status != CHE_OK) {
96dc52
 				warn(ap->logopt, MODPREFIX "error adding multi-mount");
96dc52
-				cache_writelock(mc);
96dc52
-				tree_mapent_delete_offsets(mc, name);
96dc52
-				cache_unlock(mc);
96dc52
+				cleanup_offset_entries(ap, mc, &offsets);
96dc52
 				free(m_offset);
96dc52
 				free(options);
96dc52
 				free(pmapent);
96dc52
@@ -1499,6 +1535,14 @@ dont_expand:
96dc52
 			free(myoptions);
96dc52
 		} while (*p == '/' || (*p == '"' && *(p + 1) == '/'));
96dc52
 
96dc52
+		cache_writelock(mc);
96dc52
+		list_for_each_entry_safe(oe, tmp, &offsets, work) {
96dc52
+			if (!tree_mapent_add_node(mc, name, oe->key))
96dc52
+				error(ap->logopt, "failed to add offset %s to tree", oe->key);
96dc52
+			list_del_init(&oe->work);
96dc52
+		}
96dc52
+		cache_unlock(mc);
96dc52
+
96dc52
 		rv = mount_subtree(ap, mc, name, NULL, options, ctxt);
96dc52
 
96dc52
 		free(options);