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

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