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

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