Linux-Modules Archive mirror
 help / color / mirror / Atom feed
From: Valerii Chernous <vchernou@cisco.com>
To: linux-modules@vger.kernel.org
Cc: xe-linux-external@cisco.com, Nicolas Schier <n.schier@avm.de>,
	Lucas De Marchi <lucas.de.marchi@gmail.com>
Subject: [MODALTS v0.1 3/4] kmod: add modules.alternatives to modprobe
Date: Fri, 10 May 2024 04:21:27 -0700	[thread overview]
Message-ID: <20240510112128.2417494-3-vchernou@cisco.com> (raw)

Cc: xe-linux-external@cisco.com
Cc: Valerii Chernous <vchernou@cisco.com>
Signed-off-by: Valerii Chernous <vchernou@cisco.com>
---
 libkmod/libkmod-internal.h |   2 +
 libkmod/libkmod-module.c   |  74 ++++++++++++++++++++++-
 libkmod/libkmod.c          | 118 ++++++++++++++++++++++++++++++++++++-
 libkmod/libkmod.h          |   6 ++
 4 files changed, 196 insertions(+), 4 deletions(-)

diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
index 0a274e7..44acfb1 100644
--- a/libkmod/libkmod-internal.h
+++ b/libkmod/libkmod-internal.h
@@ -107,6 +107,8 @@ int kmod_lookup_alias_from_kernel_builtin_file(struct kmod_ctx *ctx, const char
 int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
 bool kmod_lookup_alias_is_builtin(struct kmod_ctx *ctx, const char *name) __attribute__((nonnull(1, 2)));
 int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
+int kmod_lookup_alternatives_from_modalt_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
+char *kmod_search_modalternatives(struct kmod_ctx *ctx, const char *name) __attribute__((nonnull(1, 2)));
 void kmod_set_modules_visited(struct kmod_ctx *ctx, bool visited) __attribute__((nonnull((1))));
 void kmod_set_modules_required(struct kmod_ctx *ctx, bool required) __attribute__((nonnull((1))));
 
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index 2cdec34..5f4a877 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -107,7 +107,7 @@ struct kmod_module {
 	bool required : 1;
 };
 
-static inline const char *path_join(const char *path, size_t prefixlen,
+const char *path_join(const char *path, size_t prefixlen,
 							char buf[PATH_MAX])
 {
 	size_t pathlen;
@@ -700,11 +700,83 @@ static const struct kmod_list *module_get_dependencies_noref(const struct kmod_m
 
 		if (!mod->init.dep)
 			return NULL;
+
+		update_mod_deps_correspond_to_alternatives((struct kmod_module *)mod);
 	}
 
 	return mod->dep;
 }
 
+int update_mod_deps_correspond_to_alternatives(struct kmod_module *mod)
+{
+	if (is_index_available(mod->ctx, KMOD_INDEX_MODULES_ALTERNATIVES)) {
+		struct kmod_list *l;
+		struct kmod_list *preferred_l = NULL;
+		struct kmod_list *final_l = NULL;
+		int n;
+
+		DBG(mod->ctx, "Update deps alternatives for mod: %s\n",
+		    mod->name != NULL ? mod->name : "undef");
+		kmod_list_foreach(l, mod->dep) {
+			struct kmod_list *l_alt;
+			char buf[PATH_MAX*2];
+			struct kmod_module *dep = (struct kmod_module *)l->data;
+			struct kmod_module *preferred;
+
+			snprintf(buf, sizeof(buf), "%s#_#%s", mod->name, dep->name);
+			preferred = NULL;
+			n = kmod_lookup_alternatives_from_modalt_file(mod->ctx, buf, &l_alt);
+			if (n == 0 || n == -ENOENT) {
+				preferred = dep;
+				kmod_module_ref(preferred);
+			} else if ( n < 0) {
+				kmod_module_unref_list(preferred_l);
+				return n;
+			} else {
+				struct kmod_list *l2;
+				kmod_list_foreach(l2, l_alt) {
+					struct stat st;
+					struct kmod_module *alt = (struct kmod_module *)l2->data;
+					// if no preferrable alternative use first as preferred //
+					if (preferred == NULL)
+						preferred = alt;
+					snprintf(buf, sizeof(buf), "/sys/module/%s", alt->name);
+					if (stat(buf, &st) == 0 && S_ISDIR(st.st_mode)) {
+						// if one from alternative providers loaded use it as alternative //
+						preferred = alt;
+						break;
+					}
+				}
+				kmod_module_ref(preferred);
+				kmod_module_unref_list(l_alt);
+			}
+			preferred_l = kmod_list_append(preferred_l, preferred);
+		}
+		kmod_list_foreach_reverse(l, preferred_l) {
+			struct kmod_list *l2 = NULL;
+			struct kmod_module *dep = (struct kmod_module *)l->data;
+			final_l = kmod_list_insert_before(final_l, dep);
+			if (dep->dep == NULL) {
+				n = kmod_lookup_alias_from_moddep_file(mod->ctx, dep->name, &l2);
+				if (n < 0) {
+					DBG(mod->ctx, "Loading subdeps for %s failed\n", dep->name);
+					kmod_module_unref_list(preferred_l);
+					return n;
+				}
+			}
+			// remove duplicates from final dependencies and add all sub deps to current deps
+			kmod_list_foreach_reverse(l2, dep->dep) {
+				final_l = kmod_list_remove_data(final_l, l2->data);
+				final_l = kmod_list_insert_before(final_l, l2->data);
+			}
+		}
+		kmod_module_unref_list(mod->dep);
+		mod->dep = final_l;
+	} else
+		DBG(mod->ctx, "Alternatives indexes[%d]) didn't load\n", (int)KMOD_INDEX_MODULES_ALTERNATIVES);
+	return 0;
+}
+
 /**
  * kmod_module_get_dependencies:
  * @mod: kmod module
diff --git a/libkmod/libkmod.c b/libkmod/libkmod.c
index 213b424..e5646b2 100644
--- a/libkmod/libkmod.c
+++ b/libkmod/libkmod.c
@@ -40,7 +40,7 @@
 
 #define KMOD_HASH_SIZE (256)
 #define KMOD_LRU_MAX (128)
-#define _KMOD_INDEX_MODULES_SIZE KMOD_INDEX_MODULES_BUILTIN + 1
+#define _KMOD_INDEX_MODULES_SIZE KMOD_INDEX_MODULES_ALTERNATIVES + 1
 
 /**
  * SECTION:libkmod
@@ -59,6 +59,7 @@ static const struct {
 	[KMOD_INDEX_MODULES_SYMBOL] = { .fn = "modules.symbols", .prefix = "alias "},
 	[KMOD_INDEX_MODULES_BUILTIN_ALIAS] = { .fn = "modules.builtin.alias", .prefix = "" },
 	[KMOD_INDEX_MODULES_BUILTIN] = { .fn = "modules.builtin", .prefix = ""},
+	[KMOD_INDEX_MODULES_ALTERNATIVES] = { .fn = "modules.alternatives", .prefix = ""},
 };
 
 static const char *const default_config_paths[] = {
@@ -655,6 +656,105 @@ char *kmod_search_moddep(struct kmod_ctx *ctx, const char *name)
 	return line;
 }
 
+char *kmod_search_modalternatives(struct kmod_ctx *ctx, const char *name)
+{
+	struct index_file *idx;
+	char fn[PATH_MAX];
+	char *line;
+
+	if (ctx->indexes[KMOD_INDEX_MODULES_ALTERNATIVES]) {
+		DBG(ctx, "use mmaped index '%s' mod alternative=%s\n",
+				index_files[KMOD_INDEX_MODULES_ALTERNATIVES].fn, name);
+		return index_mm_search(ctx->indexes[KMOD_INDEX_MODULES_ALTERNATIVES],
+									name);
+	}
+
+	snprintf(fn, sizeof(fn), "%s/%s.bin", ctx->dirname,
+					index_files[KMOD_INDEX_MODULES_ALTERNATIVES].fn);
+
+	DBG(ctx, "file=%s mod alternative name=%s\n", fn, name);
+
+	idx = index_file_open(fn);
+	if (idx == NULL) {
+		DBG(ctx, "could not open mod alternatives file '%s'\n", fn);
+		return NULL;
+	}
+
+	line = index_search(idx, name);
+	index_file_close(idx);
+
+	return line;
+}
+
+int kmod_lookup_alternatives_from_modalt_file(struct kmod_ctx *ctx, const char *name,
+						struct kmod_list **list)
+{
+	char *line;
+	int n = 0, err = 0;
+	const char *dirname;
+	size_t dirnamelen;
+	char buf[PATH_MAX];
+	char *p, *saveptr;
+
+	*list = NULL;
+	/*
+	 * Module alternatives names do not contain ':'. Return early if we know it will
+	 * not be found.
+	 */
+	if (strchr(name, ':'))
+		return 0;
+
+	line = kmod_search_modalternatives(ctx, name);
+	if (line == NULL)
+		return 0;
+
+	p = strchr(line, ':');
+	if (p == NULL) {
+		err = -ENOENT;
+		goto fail;
+	}
+	*p = '\0';
+	p++;
+
+	dirname = kmod_get_dirname(ctx);
+	dirnamelen = strlen(dirname);
+	if (dirnamelen + 2 >= PATH_MAX)
+		return 0;
+	memcpy(buf, dirname, dirnamelen);
+	buf[dirnamelen] = '/';
+	dirnamelen++;
+	buf[dirnamelen] = '\0';
+
+	for (p = strtok_r(p, " \t", &saveptr); p != NULL;
+                                p = strtok_r(NULL, " \t", &saveptr)) {
+		struct kmod_module *mod;
+		const char *path;
+		path = path_join(p, dirnamelen, buf);
+		if (path == NULL) {
+			ERR(ctx, "could not join path '%s' and '%s'.\n", dirname, p);
+			err = -ENOENT;
+			goto fail;
+		}
+		err = kmod_module_new_from_path(ctx, path, &mod);
+		if (err < 0) {
+			ERR(ctx, "ctx=%p path=%s error=%s\n", ctx, path, strerror(-err));
+			goto fail;
+		}
+		*list = kmod_list_append(*list, mod);
+		n++;
+	}
+
+	free(line);
+	return n;
+
+fail:
+	kmod_module_unref_list(*list);
+	*list = NULL;
+	free(line);
+	return err;
+}
+
+
 int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
 						struct kmod_list **list)
 {
@@ -681,6 +781,7 @@ int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
 
 		*list = kmod_list_append(*list, mod);
 		kmod_module_parse_depline(mod, line);
+		update_mod_deps_correspond_to_alternatives(mod);
 	}
 
 finish:
@@ -916,12 +1017,12 @@ KMOD_EXPORT int kmod_load_resources(struct kmod_ctx *ctx)
 				    &ctx->indexes[i]);
 
 		/*
-		 * modules.builtin.alias are considered optional since it's
+		 * modules.builtin.alias and modules.alternatives are considered optional since it's
 		 * recently added and older installations may not have it;
 		 * we allow failing for any reason
 		 */
 		if (ret) {
-			if (i != KMOD_INDEX_MODULES_BUILTIN_ALIAS)
+			if (i != KMOD_INDEX_MODULES_BUILTIN_ALIAS && i != KMOD_INDEX_MODULES_ALTERNATIVES)
 				break;
 			ret = 0;
 		}
@@ -1022,3 +1123,14 @@ enum kmod_file_compression_type kmod_get_kernel_compression(const struct kmod_ct
 {
 	return ctx->kernel_compression;
 }
+
+bool is_index_available(const struct kmod_ctx *ctx, enum kmod_index index)
+{
+	if (ctx == NULL)
+		return false;
+	if (index >= _KMOD_INDEX_MODULES_SIZE)
+		return false;
+	if (ctx->indexes[index] == NULL)
+		return false;
+	return true;
+}
diff --git a/libkmod/libkmod.h b/libkmod/libkmod.h
index 7251aa7..f3bd3d7 100644
--- a/libkmod/libkmod.h
+++ b/libkmod/libkmod.h
@@ -25,6 +25,7 @@
 #include <stdarg.h>
 #include <stdbool.h>
 #include <inttypes.h>
+#include <limits.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -72,6 +73,7 @@ enum kmod_index {
 	KMOD_INDEX_MODULES_SYMBOL,
 	KMOD_INDEX_MODULES_BUILTIN_ALIAS,
 	KMOD_INDEX_MODULES_BUILTIN,
+	KMOD_INDEX_MODULES_ALTERNATIVES,
 	/* Padding to make sure enum is not mapped to char */
 	_KMOD_INDEX_PAD = 1U << 31,
 };
@@ -264,6 +266,10 @@ int kmod_module_dependency_symbol_get_bind(const struct kmod_list *entry);
 uint64_t kmod_module_dependency_symbol_get_crc(const struct kmod_list *entry);
 void kmod_module_dependency_symbols_free_list(struct kmod_list *list);
 
+bool is_index_available(const struct kmod_ctx *ctx, enum kmod_index index);
+int update_mod_deps_correspond_to_alternatives(struct kmod_module *mod);
+const char *path_join(const char *path, size_t prefixlen, char buf[PATH_MAX]);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
-- 
2.35.6


                 reply	other threads:[~2024-05-10 11:21 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240510112128.2417494-3-vchernou@cisco.com \
    --to=vchernou@cisco.com \
    --cc=linux-modules@vger.kernel.org \
    --cc=lucas.de.marchi@gmail.com \
    --cc=n.schier@avm.de \
    --cc=xe-linux-external@cisco.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).