aboutsummaryrefslogtreecommitdiffstats
path: root/main/busybox/2002-modutils-merge-module_entry-and-module_info-to-commo.patch
diff options
context:
space:
mode:
Diffstat (limited to 'main/busybox/2002-modutils-merge-module_entry-and-module_info-to-commo.patch')
-rw-r--r--main/busybox/2002-modutils-merge-module_entry-and-module_info-to-commo.patch445
1 files changed, 445 insertions, 0 deletions
diff --git a/main/busybox/2002-modutils-merge-module_entry-and-module_info-to-commo.patch b/main/busybox/2002-modutils-merge-module_entry-and-module_info-to-commo.patch
new file mode 100644
index 0000000000..f7dc826750
--- /dev/null
+++ b/main/busybox/2002-modutils-merge-module_entry-and-module_info-to-commo.patch
@@ -0,0 +1,445 @@
+From 2fedbe5b8bd40933a35606d5478396dbc212ddf1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Timo=20Ter=C3=A4s?= <timo.teras@iki.fi>
+Date: Wed, 22 Jul 2015 15:15:15 +0300
+Subject: [PATCH 2002/2003] modutils: merge module_entry and module_info to
+ common code
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This merges the in-memory module info structures of modprobe
+and depmod. This allows sharing hashing by modulename code
+improving depmod runtime with almost factor of 2x.
+
+Signed-off-by: Timo Teräs <timo.teras@iki.fi>
+---
+ modutils/depmod.c | 99 +++++++++++++++++++----------------------------------
+ modutils/modprobe.c | 66 ++++-------------------------------
+ modutils/modutils.c | 43 +++++++++++++++++++++++
+ modutils/modutils.h | 29 ++++++++++++++++
+ 4 files changed, 114 insertions(+), 123 deletions(-)
+
+diff --git a/modutils/depmod.c b/modutils/depmod.c
+index 37a8482..4d83429 100644
+--- a/modutils/depmod.c
++++ b/modutils/depmod.c
+@@ -14,6 +14,14 @@
+ #include "modutils.h"
+ #include <sys/utsname.h> /* uname() */
+
++struct globals {
++ module_db db;
++} FIX_ALIASING;
++#define G (*ptr_to_globals)
++#define INIT_G() do { \
++ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
++} while (0)
++
+ /*
+ * Theory of operation:
+ * - iterate over all modules and record their full path
+@@ -21,21 +29,12 @@
+ * for each depends, look through our list of full paths and emit if found
+ */
+
+-typedef struct module_info {
+- struct module_info *next;
+- char *name, *modname;
+- llist_t *dependencies;
+- llist_t *aliases;
+- llist_t *symbols;
+- struct module_info *dnext, *dprev;
+-} module_info;
+-
+ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM,
+- void *data, int depth UNUSED_PARAM)
++ void *data UNUSED_PARAM, int depth UNUSED_PARAM)
+ {
+- module_info **first = (module_info **) data;
+ char *image, *ptr;
+- module_info *info;
++ module_entry *e;
++
+ /* Arbitrary. Was sb->st_size, but that breaks .gz etc */
+ size_t len = (64*1024*1024 - 4096);
+
+@@ -43,17 +42,10 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA
+ return TRUE;
+
+ image = xmalloc_open_zipped_read_close(fname, &len);
+- info = xzalloc(sizeof(*info));
+
+- info->next = *first;
+- *first = info;
++ e = moddb_get(&G.db, bb_get_last_path_component_nostrip(fname), 1);
++ e->name = xstrdup(fname + 2); /* skip "./" */
+
+- info->dnext = info->dprev = info;
+- info->name = xstrdup(fname + 2); /* skip "./" */
+- info->modname = filename2modname(
+- bb_get_last_path_component_nostrip(fname),
+- NULL
+- );
+ for (ptr = image; ptr < image + len - 10; ptr++) {
+ if (strncmp(ptr, "depends=", 8) == 0) {
+ char *u;
+@@ -62,11 +54,11 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA
+ for (u = ptr; *u; u++)
+ if (*u == '-')
+ *u = '_';
+- ptr += string_to_llist(ptr, &info->dependencies, ",");
++ ptr += string_to_llist(ptr, &e->deps, ",");
+ } else if (ENABLE_FEATURE_MODUTILS_ALIAS
+ && strncmp(ptr, "alias=", 6) == 0
+ ) {
+- llist_add_to(&info->aliases, xstrdup(ptr + 6));
++ llist_add_to(&e->aliases, xstrdup(ptr + 6));
+ ptr += strlen(ptr);
+ } else if (ENABLE_FEATURE_MODUTILS_SYMBOLS
+ && strncmp(ptr, "__ksymtab_", 10) == 0
+@@ -77,7 +69,7 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA
+ ) {
+ continue;
+ }
+- llist_add_to(&info->symbols, xstrdup(ptr));
++ llist_add_to(&e->symbols, xstrdup(ptr));
+ ptr += strlen(ptr);
+ }
+ }
+@@ -86,24 +78,13 @@ static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARA
+ return TRUE;
+ }
+
+-static module_info *find_module(module_info *modules, const char *modname)
+-{
+- module_info *m;
+-
+- for (m = modules; m != NULL; m = m->next)
+- if (strcmp(m->modname, modname) == 0)
+- return m;
+- return NULL;
+-}
+-
+-static void order_dep_list(module_info *modules, module_info *start,
+- llist_t *add)
++static void order_dep_list(module_entry *start, llist_t *add)
+ {
+- module_info *m;
++ module_entry *m;
+ llist_t *n;
+
+ for (n = add; n != NULL; n = n->link) {
+- m = find_module(modules, n->data);
++ m = moddb_get(&G.db, n->data, 0);
+ if (m == NULL)
+ continue;
+
+@@ -118,7 +99,7 @@ static void order_dep_list(module_info *modules, module_info *start,
+ start->dprev = m;
+
+ /* recurse */
+- order_dep_list(modules, start, m->dependencies);
++ order_dep_list(start, m->deps);
+ }
+ }
+
+@@ -184,12 +165,15 @@ enum {
+ int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+ int depmod_main(int argc UNUSED_PARAM, char **argv)
+ {
+- module_info *modules, *m, *dep;
++ module_entry *m, *dep;
+ const char *moddir_base = "/";
+ char *moddir, *version;
+ struct utsname uts;
++ unsigned i;
+ int tmp;
+
++ INIT_G();
++
+ getopt32(argv, "aAb:eF:nruqC:", &moddir_base, NULL, NULL);
+ argv += optind;
+
+@@ -211,23 +195,23 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
+ free(moddir);
+
+ /* Scan modules */
+- modules = NULL;
+ if (*argv) {
+ do {
+- parse_module(*argv, /*sb (unused):*/ NULL, &modules, 0);
++ parse_module(*argv, /*sb (unused):*/ NULL, NULL, 0);
+ } while (*++argv);
+ } else {
+ recursive_action(".", ACTION_RECURSE,
+- parse_module, NULL, &modules, 0);
++ parse_module, NULL, NULL, 0);
+ }
+
+ /* Generate dependency and alias files */
+ if (!(option_mask32 & OPT_n))
+ xfreopen_write(CONFIG_DEFAULT_DEPMOD_FILE, stdout);
+- for (m = modules; m != NULL; m = m->next) {
++
++ moddb_foreach_module(&G.db, m, i) {
+ printf("%s:", m->name);
+
+- order_dep_list(modules, m, m->dependencies);
++ order_dep_list(m, m->deps);
+ while (m->dnext != m) {
+ dep = m->dnext;
+ printf(" %s", dep->name);
+@@ -243,10 +227,7 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
+ #if ENABLE_FEATURE_MODUTILS_ALIAS
+ if (!(option_mask32 & OPT_n))
+ xfreopen_write("modules.alias", stdout);
+- for (m = modules; m != NULL; m = m->next) {
+- char modname[MODULE_NAME_LEN];
+- const char *fname = bb_basename(m->name);
+- filename2modname(fname, modname);
++ moddb_foreach_module(&G.db, m, i) {
+ while (m->aliases) {
+ /*
+ * Last word used to be a basename
+@@ -256,34 +237,24 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
+ */
+ printf("alias %s %s\n",
+ (char*)llist_pop(&m->aliases),
+- modname);
++ m->modname);
+ }
+ }
+ #endif
+ #if ENABLE_FEATURE_MODUTILS_SYMBOLS
+ if (!(option_mask32 & OPT_n))
+ xfreopen_write("modules.symbols", stdout);
+- for (m = modules; m != NULL; m = m->next) {
+- char modname[MODULE_NAME_LEN];
+- const char *fname = bb_basename(m->name);
+- filename2modname(fname, modname);
++ moddb_foreach_module(&G.db, m, i) {
+ while (m->symbols) {
+ printf("alias symbol:%s %s\n",
+ (char*)llist_pop(&m->symbols),
+- modname);
++ m->modname);
+ }
+ }
+ #endif
+
+- if (ENABLE_FEATURE_CLEAN_UP) {
+- while (modules) {
+- module_info *old = modules;
+- modules = modules->next;
+- free(old->name);
+- free(old->modname);
+- free(old);
+- }
+- }
++ if (ENABLE_FEATURE_CLEAN_UP)
++ moddb_free(&G.db);
+
+ return EXIT_SUCCESS;
+ }
+diff --git a/modutils/modprobe.c b/modutils/modprobe.c
+index aedde5c..1e67807 100644
+--- a/modutils/modprobe.c
++++ b/modutils/modprobe.c
+@@ -147,19 +147,6 @@ static const char modprobe_longopts[] ALIGN1 =
+ #define MODULE_FLAG_FOUND_IN_MODDEP 0x0004
+ #define MODULE_FLAG_BLACKLISTED 0x0008
+
+-struct module_entry { /* I'll call it ME. */
+- unsigned flags;
+- char *modname; /* stripped of /path/, .ext and s/-/_/g */
+- const char *probed_name; /* verbatim as seen on cmdline */
+- char *options; /* options from config files */
+- llist_t *realnames; /* strings. if this module is an alias, */
+- /* real module name is one of these. */
+-//Can there really be more than one? Example from real kernel?
+- llist_t *deps; /* strings. modules we depend on */
+-};
+-
+-#define DB_HASH_SIZE 256
+-
+ struct globals {
+ llist_t *probes; /* MEs of module(s) requested on cmdline */
+ char *cmdline_mopts; /* module options from cmdline */
+@@ -167,7 +154,7 @@ struct globals {
+ /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */
+ smallint need_symbols;
+ struct utsname uts;
+- llist_t *db[DB_HASH_SIZE]; /* MEs of all modules ever seen (caching for speed) */
++ module_db db;
+ } FIX_ALIASING;
+ #define G (*ptr_to_globals)
+ #define INIT_G() do { \
+@@ -192,51 +179,9 @@ static char *gather_options_str(char *opts, const char *append)
+ return opts;
+ }
+
+-/* These three functions called many times, optimizing for speed.
+- * Users reported minute-long delays when they runn iptables repeatedly
+- * (iptables use modprobe to install needed kernel modules).
+- */
+-static struct module_entry *helper_get_module(const char *module, int create)
++static struct module_entry *get_or_add_modentry(const char *module)
+ {
+- char modname[MODULE_NAME_LEN];
+- struct module_entry *e;
+- llist_t *l;
+- unsigned i;
+- unsigned hash;
+-
+- filename2modname(module, modname);
+-
+- hash = 0;
+- for (i = 0; modname[i]; i++)
+- hash = ((hash << 5) + hash) + modname[i];
+- hash %= DB_HASH_SIZE;
+-
+- for (l = G.db[hash]; l; l = l->link) {
+- e = (struct module_entry *) l->data;
+- if (strcmp(e->modname, modname) == 0)
+- return e;
+- }
+- if (!create)
+- return NULL;
+-
+- e = xzalloc(sizeof(*e));
+- e->modname = xstrdup(modname);
+- llist_add_to(&G.db[hash], e);
+-
+- return e;
+-}
+-static ALWAYS_INLINE struct module_entry *get_or_add_modentry(const char *module)
+-{
+- return helper_get_module(module, 1);
+-}
+-/* So far this function always gets a module pathname, never an alias name.
+- * The crucial difference is that pathname needs dirname stripping,
+- * while alias name must NOT do it!
+- * Testcase where dirname stripping is likely to go wrong: "modprobe devname:snd/timer"
+- */
+-static ALWAYS_INLINE struct module_entry *get_modentry(const char *pathname)
+-{
+- return helper_get_module(bb_get_last_path_component_nostrip(pathname), 0);
++ return moddb_get(&G.db, module, 1);
+ }
+
+ static void add_probe(const char *name)
+@@ -506,7 +451,7 @@ static void load_modules_dep(void)
+ continue;
+ *colon = '\0';
+
+- m = get_modentry(tokens[0]);
++ m = moddb_get(&G.db, bb_get_last_path_component_nostrip(tokens[0]), 0);
+ if (m == NULL)
+ continue;
+
+@@ -667,5 +612,8 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
+ } while (me->realnames != NULL);
+ }
+
++ if (ENABLE_FEATURE_CLEAN_UP)
++ moddb_free(&G.db);
++
+ return (rc != 0);
+ }
+diff --git a/modutils/modutils.c b/modutils/modutils.c
+index 84300d9..ed26697 100644
+--- a/modutils/modutils.c
++++ b/modutils/modutils.c
+@@ -16,6 +16,49 @@ extern int delete_module(const char *module, unsigned int flags);
+ # define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags)
+ #endif
+
++module_entry * FAST_FUNC moddb_get(module_db *db, const char *module, int create)
++{
++ char modname[MODULE_NAME_LEN];
++ struct module_entry *e;
++ unsigned i, hash;
++
++ filename2modname(module, modname);
++
++ hash = 0;
++ for (i = 0; modname[i]; i++)
++ hash = ((hash << 5) + hash) + modname[i];
++ hash %= MODULE_HASH_SIZE;
++
++ for (e = db->buckets[hash]; e; e = e->next)
++ if (strcmp(e->modname, modname) == 0)
++ return e;
++ if (!create)
++ return NULL;
++
++ e = xzalloc(sizeof(*e));
++ e->modname = xstrdup(modname);
++ e->next = db->buckets[hash];
++ db->buckets[hash] = e;
++ e->dnext = e->dprev = e;
++
++ return e;
++}
++
++void FAST_FUNC moddb_free(module_db *db)
++{
++ module_entry *e, *n;
++ unsigned i;
++
++ for (i = 0; i < MODULE_HASH_SIZE; i++) {
++ for (e = db->buckets[i]; e; e = n) {
++ n = e->next;
++ free(e->name);
++ free(e->modname);
++ free(e);
++ }
++ }
++}
++
+ void FAST_FUNC replace(char *s, char what, char with)
+ {
+ while (*s) {
+diff --git a/modutils/modutils.h b/modutils/modutils.h
+index 5f059c7..0c0cb46 100644
+--- a/modutils/modutils.h
++++ b/modutils/modutils.h
+@@ -16,6 +16,35 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
+ /* linux/include/linux/module.h has 64, but this is also used
+ * internally for the maximum alias name length, which can be quite long */
+ #define MODULE_NAME_LEN 256
++#define MODULE_HASH_SIZE 256
++
++typedef struct module_entry {
++ struct module_entry *next;
++ char *name, *modname;
++ llist_t *deps;
++ IF_MODPROBE(
++ llist_t *realnames;
++ unsigned flags;
++ const char *probed_name; /* verbatim as seen on cmdline */
++ char *options; /* options from config files */
++ )
++ IF_DEPMOD(
++ llist_t *aliases;
++ llist_t *symbols;
++ struct module_entry *dnext, *dprev;
++ )
++} module_entry;
++
++typedef struct module_db {
++ module_entry *buckets[MODULE_HASH_SIZE];
++} module_db;
++
++#define moddb_foreach_module(db, module, index) \
++ for ((index) = 0; (index) < MODULE_HASH_SIZE; (index)++) \
++ for (module = (db)->buckets[index]; module; module = module->next)
++
++module_entry *moddb_get(module_db *db, const char *s, int create) FAST_FUNC;
++void moddb_free(module_db *db) FAST_FUNC;
+
+ void replace(char *s, char what, char with) FAST_FUNC;
+ char *replace_underscores(char *s) FAST_FUNC;
+--
+2.5.0
+