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

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