[RESEND PATCH] modutils: merge module_entry and module_info to common code
Denys Vlasenko
vda.linux at googlemail.com
Thu Nov 5 17:58:09 UTC 2015
Applied with some editing. Thanks.
On Wed, Oct 28, 2015 at 7:35 PM, Timo Teräs <timo.teras at iki.fi> wrote:
> 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 at 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 9713aef..b8699ba 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 (is_prefixed_with(ptr, "depends=")) {
> 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
> && is_prefixed_with(ptr, "alias=")
> ) {
> - 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
> && is_prefixed_with(ptr, "__ksymtab_")
> @@ -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 05bf02c..2f55ad2 100644
> --- a/modutils/modprobe.c
> +++ b/modutils/modprobe.c
> @@ -150,19 +150,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 */
> @@ -170,7 +157,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 { \
> @@ -195,51 +182,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)
> -{
> - 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)
> +static 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)
> @@ -536,7 +481,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;
>
> @@ -697,5 +642,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 ef4134a..05e0777 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.6.1
>
> _______________________________________________
> busybox mailing list
> busybox at busybox.net
> http://lists.busybox.net/mailman/listinfo/busybox
More information about the busybox
mailing list