[dm-devel] [PATCH v2 2/3] libmultipath: check_alias_settings(): pre-sort mptable by alias

mwilck at suse.com mwilck at suse.com
Wed Aug 24 08:11:46 UTC 2022


From: Martin Wilck <mwilck at suse.com>

add_binding() contains an optimization; it assumes that the list of
bindings is alphabetically sorted by alias, and tries to maintain
this order.

But conf->mptable is sorted by wwid. Therefore check_alias_settings() may take
a long time if the mptable is large.

Create a copy of the mptable, sorted by alias, and use it for add_bindings().
This speeds up check_alias_settings by roughly a factor of 10 (0.1s vs. 1s)
for my test setup with 10000 entries in the mptable.

Signed-off-by: Martin Wilck <mwilck at suse.com>
---
 libmultipath/alias.c | 44 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 41 insertions(+), 3 deletions(-)

diff --git a/libmultipath/alias.c b/libmultipath/alias.c
index 548a118..284092b 100644
--- a/libmultipath/alias.c
+++ b/libmultipath/alias.c
@@ -672,6 +672,31 @@ static void cleanup_fclose(void *p)
 	fclose(p);
 }
 
+static int alias_compar(const void *p1, const void *p2)
+{
+	const char *alias1 = (*(struct mpentry * const *)p1)->alias;
+	const char *alias2 = (*(struct mpentry * const *)p2)->alias;
+	int cmp;
+
+	if (alias1 && alias2)
+		cmp = strcmp(alias1, alias2);
+	else
+		/* Move NULL alias to the end */
+		cmp = alias1 ? -1 : alias2 ? 1 : 0;
+
+	if (cmp)
+		return cmp;
+
+	/* Ensure stable sort, see wwid_compar() in config.c */
+	return  p1 < p2 ? -1 : p1 > p2 ? 1 : 0;
+}
+
+static void cleanup_vector_free(void *arg)
+{
+	if  (arg)
+		vector_free((vector)arg);
+}
+
 /*
  * check_alias_settings(): test for inconsistent alias configuration
  *
@@ -693,12 +718,24 @@ int check_alias_settings(const struct config *conf)
 	int can_write;
 	int rc = 0, i, fd;
 	Bindings bindings = {.allocated = 0, };
+	vector mptable = NULL;
 	struct mpentry *mpe;
 
+	mptable = vector_convert(NULL, conf->mptable, struct mpentry *, identity);
+	if (!mptable)
+		return -1;
+
 	pthread_cleanup_push_cast(free_bindings, &bindings);
-	vector_foreach_slot(conf->mptable, mpe, i) {
-		if (!mpe->wwid || !mpe->alias)
-			continue;
+	pthread_cleanup_push(cleanup_vector_free, mptable);
+
+	vector_sort(mptable, alias_compar);
+	vector_foreach_slot(mptable, mpe, i) {
+		if (!mpe->alias)
+			/*
+			 * alias_compar() sorts NULL alias at the end,
+			 * so we can stop if we encounter this.
+			 */
+			break;
 		if (add_binding(&bindings, mpe->alias, mpe->wwid) ==
 		    BINDING_CONFLICT) {
 			condlog(0, "ERROR: alias \"%s\" bound to multiple wwids in multipath.conf, "
@@ -710,6 +747,7 @@ int check_alias_settings(const struct config *conf)
 	}
 	/* This clears the bindings */
 	pthread_cleanup_pop(1);
+	pthread_cleanup_pop(1);
 
 	pthread_cleanup_push_cast(free_bindings, &bindings);
 	fd = open_file(conf->bindings_file, &can_write, BINDINGS_FILE_HEADER);
-- 
2.37.1



More information about the dm-devel mailing list