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

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