Blob Blame History Raw
autofs-5.1.7 - fix hosts map offset order

From: Ian Kent <raven@themaw.net>

Map entry offset paths to be in shortest to longest order but exports
from a server could come in any order. If there are a large number of
exports this can result in a lot of overhead when adding the offset
to the ordered list use to mount the offset during parsing since the
path length of exports can cary a lot.

So leverage the tree implemention to sort the export offsets into
shortest to longest order as we go when constructing the mapent from
the exports list.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG              |    1 
 include/automount.h    |    2 -
 include/mounts.h       |    8 +++++
 include/rpc_subs.h     |    3 ++
 lib/mounts.c           |   57 +++++++++++++++++++++++++++++++++++++--
 modules/lookup_hosts.c |   71 ++++++++++++++++++++++++++++++++++++++-----------
 6 files changed, 124 insertions(+), 18 deletions(-)

--- autofs-5.1.7.orig/CHANGELOG
+++ autofs-5.1.7/CHANGELOG
@@ -72,6 +72,7 @@
 - fix offset entries order.
 - use mapent tree root for tree_mapent_add_node().
 - eliminate redundant cache lookup in tree_mapent_add_node().
+- fix hosts map offset order.
 
 25/01/2021 autofs-5.1.7
 - make bind mounts propagation slave by default.
--- autofs-5.1.7.orig/include/automount.h
+++ autofs-5.1.7/include/automount.h
@@ -31,9 +31,9 @@
 #include "master.h"
 #include "macros.h"
 #include "log.h"
+#include "mounts.h"
 #include "rpc_subs.h"
 #include "parse_subs.h"
-#include "mounts.h"
 #include "dev-ioctl-lib.h"
 #include "parse_amd.h"
 
--- autofs-5.1.7.orig/include/mounts.h
+++ autofs-5.1.7/include/mounts.h
@@ -52,6 +52,7 @@ extern const unsigned int t_direct;
 extern const unsigned int t_offset;
 
 struct mnt_list;
+struct exportinfo;
 struct mapent;
 
 struct tree_ops;
@@ -66,6 +67,9 @@ struct tree_node {
 #define MNT_LIST(n)		(container_of(n, struct mnt_list, node))
 #define MNT_LIST_NODE(ptr)	((struct tree_node *) &((struct mnt_list *) ptr)->node)
 
+#define EXPORTINFO(n)		(container_of(n, struct exportinfo, node))
+#define EXPORT_NODE(ptr)	((struct tree_node *) &((struct exportinfo *) ptr)->node)
+
 #define MAPENT(n)		(container_of(n, struct mapent, node))
 #define MAPENT_NODE(p)		((struct tree_node *) &((struct mapent *) p)->node)
 #define MAPENT_ROOT(p)		((struct tree_node *) ((struct mapent *) p)->mm_root)
@@ -166,9 +170,13 @@ struct mnt_list *mnts_add_mount(struct a
 void mnts_remove_mount(const char *mp, unsigned int flags);
 struct mnt_list *get_mnt_list(const char *path, int include);
 unsigned int mnts_has_mounted_mounts(struct autofs_point *ap);
+int tree_traverse_inorder(struct tree_node *n, tree_work_fn_t work, void *ptr);
+void tree_free(struct tree_node *root);
 void mnts_get_expire_list(struct list_head *mnts, struct autofs_point *ap);
 void mnts_put_expire_list(struct list_head *mnts);
 void mnts_set_mounted_mount(struct autofs_point *ap, const char *name, unsigned int flags);
+struct tree_node *tree_host_root(struct exportinfo *exp);
+struct tree_node *tree_host_add_node(struct tree_node *root, struct exportinfo *exp);
 struct tree_node *tree_mapent_root(struct mapent *me);
 int tree_mapent_add_node(struct mapent_cache *mc, struct tree_node *root, struct mapent *me);
 int tree_mapent_delete_offsets(struct mapent_cache *mc, const char *key);
--- autofs-5.1.7.orig/include/rpc_subs.h
+++ autofs-5.1.7/include/rpc_subs.h
@@ -23,6 +23,8 @@
 #include <linux/nfs2.h>
 #include <linux/nfs3.h>
 
+#include "automount.h"
+
 #define NFS4_VERSION		4
 
 /* rpc helper subs */
@@ -57,6 +59,7 @@ struct exportinfo {
 	char *dir;
 	struct hostinfo *hosts;
 	struct exportinfo *next;
+	struct tree_node node;
 };
 
 struct conn_info {
--- autofs-5.1.7.orig/lib/mounts.c
+++ autofs-5.1.7/lib/mounts.c
@@ -79,6 +79,17 @@ static struct tree_ops mnt_ops = {
 };
 static struct tree_ops *tree_mnt_ops = &mnt_ops;
 
+static struct tree_node *tree_host_new(void *ptr);
+static int tree_host_cmp(struct tree_node *n, void *ptr);
+static void tree_host_free(struct tree_node *n);
+
+static struct tree_ops host_ops = {
+	.new = tree_host_new,
+	.cmp = tree_host_cmp,
+	.free = tree_host_free,
+};
+static struct tree_ops *tree_host_ops = &host_ops;
+
 static struct tree_node *tree_mapent_new(void *ptr);
 static int tree_mapent_cmp(struct tree_node *n, void *ptr);
 static void tree_mapent_free(struct tree_node *n);
@@ -1341,7 +1352,7 @@ static struct tree_node *tree_add_node(s
 	return NULL;
 }
 
-static void tree_free(struct tree_node *root)
+void tree_free(struct tree_node *root)
 {
 	struct tree_ops *ops = root->ops;
 
@@ -1352,7 +1363,7 @@ static void tree_free(struct tree_node *
 	ops->free(root);
 }
 
-static int tree_traverse_inorder(struct tree_node *n, tree_work_fn_t work, void *ptr)
+int tree_traverse_inorder(struct tree_node *n, tree_work_fn_t work, void *ptr)
 {
 	int ret;
 
@@ -1479,6 +1490,48 @@ void mnts_put_expire_list(struct list_he
 	mnts_hash_mutex_unlock();
 }
 
+struct tree_node *tree_host_root(struct exportinfo *exp)
+{
+	return tree_root(tree_host_ops, exp);
+}
+
+static struct tree_node *tree_host_new(void *ptr)
+{
+	struct tree_node *n = EXPORT_NODE(ptr);
+
+	n->ops = tree_host_ops;
+	n->left = NULL;
+	n->right = NULL;
+
+	return n;
+}
+
+static int tree_host_cmp(struct tree_node *n, void *ptr)
+{
+	struct exportinfo *n_exp = EXPORTINFO(n);
+	size_t n_exp_len = strlen(n_exp->dir);
+	struct exportinfo *exp = ptr;
+	size_t exp_len = strlen(exp->dir);
+	int eq;
+
+	eq = strcmp(exp->dir, n_exp->dir);
+	if (!eq)
+		return 0;
+	return (exp_len < n_exp_len) ? -1 : 1;
+}
+
+static void tree_host_free(struct tree_node *n)
+{
+	n->ops = NULL;
+	n->left = NULL;
+	n->right = NULL;
+}
+
+struct tree_node *tree_host_add_node(struct tree_node *root, struct exportinfo *exp)
+{
+	return tree_add_node(root, exp);
+}
+
 struct tree_node *tree_mapent_root(struct mapent *me)
 {
 	return tree_root(tree_mapent_ops, me);
--- autofs-5.1.7.orig/modules/lookup_hosts.c
+++ autofs-5.1.7/modules/lookup_hosts.c
@@ -84,14 +84,38 @@ int lookup_read_master(struct master *ma
 	return NSS_STATUS_UNKNOWN;
 }
 
+struct work_info {
+	char *mapent;
+	const char *host;
+	int pos;
+};
+
+static int tree_host_work(struct tree_node *n, void *ptr)
+{
+	struct exportinfo *exp = EXPORTINFO(n);
+	struct work_info *wi = ptr;
+	int len;
+
+	if (!wi->pos)
+		len = sprintf(wi->mapent, "\"%s\" \"%s:%s\"",
+				exp->dir, wi->host, exp->dir);
+	else
+		len = sprintf(wi->mapent + wi->pos, " \"%s\" \"%s:%s\"",
+				exp->dir, wi->host, exp->dir);
+	wi->pos += len;
+
+	return 1;
+}
+
 static char *get_exports(struct autofs_point *ap, const char *host)
 {
 	char buf[MAX_ERR_BUF];
 	char *mapent;
 	struct exportinfo *exp, *this;
+	struct tree_node *tree = NULL;
+	struct work_info wi;
 	size_t hostlen = strlen(host);
 	size_t mapent_len;
-	int len, pos;
 
 	debug(ap->logopt, MODPREFIX "fetchng export list for %s", host);
 
@@ -100,7 +124,28 @@ static char *get_exports(struct autofs_p
 	this = exp;
 	mapent_len = 0;
 	while (this) {
+		struct tree_node *n;
+
 		mapent_len += hostlen + 2*(strlen(this->dir) + 2) + 3;
+
+		if (!tree) {
+			tree = tree_host_root(this);
+			if (!tree) {
+				error(ap->logopt, "failed to create exports tree root");
+				rpc_exports_free(exp);
+				return NULL;
+			}
+			goto next;
+		}
+
+		n = tree_host_add_node(tree, this);
+		if (!n) {
+			error(ap->logopt, "failed to add exports tree node");
+			tree_free(tree);
+			rpc_exports_free(exp);
+			return NULL;
+		}
+next:
 		this = this->next;
 	}
 
@@ -115,20 +160,16 @@ static char *get_exports(struct autofs_p
 	}
 	*mapent = 0;
 
-	pos = 0;
-	this = exp;
-	if (this) {
-		len = sprintf(mapent, "\"%s\" \"%s:%s\"",
-				this->dir, host, this->dir);
-		pos += len;
-		this = this->next;
-	}
-
-	while (this) {
-		len = sprintf(mapent + pos, " \"%s\" \"%s:%s\"",
-				this->dir, host, this->dir);
-		pos += len;
-		this = this->next;
+	wi.mapent = mapent;
+	wi.host = host;
+	wi.pos = 0;
+
+	if (!tree) {
+		free(mapent);
+		mapent = NULL;
+	} else {
+		tree_traverse_inorder(tree, tree_host_work, &wi);
+		tree_free(tree);
 	}
 	rpc_exports_free(exp);