From 31aa4c8bd1d24bef1cb65681d192ad349bdd0f74 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 12 Feb 2026 14:14:16 +0000 Subject: [PATCH 1/4] tools/depmod: return error on array_append failure Currently, in the (unlikely) case of array_append failing, we'll return success and thus partial output. Fixes: 823849a0 ("tools/depmod: use separate arrays for alias,xxxdep values") Signed-off-by: Emil Velikov --- tools/depmod.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/depmod.c b/tools/depmod.c index c3d876404..2e3128084 100644 --- a/tools/depmod.c +++ b/tools/depmod.c @@ -1623,22 +1623,25 @@ static int depmod_load_modules(struct depmod *depmod) if (streq(key, "alias")) { const char *value = kmod_module_info_get_value(l); - if (array_append(&mod->alias_values, value) < 0) - return 0; + err = array_append(&mod->alias_values, value); + if (err < 0) + return err; continue; } if (streq(key, "softdep")) { const char *value = kmod_module_info_get_value(l); - if (array_append(&mod->softdep_values, value) < 0) - return 0; + err = array_append(&mod->softdep_values, value); + if (err < 0) + return err; continue; } if (streq(key, "weakdep")) { const char *value = kmod_module_info_get_value(l); - if (array_append(&mod->weakdep_values, value) < 0) - return 0; + err = array_append(&mod->weakdep_values, value); + if (err < 0) + return err; continue; } } From 42c6708efc707eb3615575c05b59c0fd6c33908a Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 12 Feb 2026 23:19:03 +0000 Subject: [PATCH 2/4] tools/depmod: split depmod_symbol_{create,add} With a later commit, we'll need to create symbols outside of the depmod_symbol_add function, so split the function in two. Aside: depmod_symbol_add should really get some error checking, that we're not helping with here... Also we should consider using hash_add_unique() since currently a duplicate symbol will override the previous one. But all of that can happen at a later date. Signed-off-by: Emil Velikov --- tools/depmod.c | 58 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/tools/depmod.c b/tools/depmod.c index 2e3128084..8a6535eca 100644 --- a/tools/depmod.c +++ b/tools/depmod.c @@ -1548,11 +1548,11 @@ static void depmod_modules_sort(struct depmod *depmod) fclose(fp); } -static int depmod_symbol_add(struct depmod *depmod, const char *name, bool prefix_skipped, - uint64_t crc, const struct mod *owner) +static struct symbol *depmod_symbol_create(struct depmod *depmod, const char *name, + bool prefix_skipped, uint64_t crc, + const struct mod *owner) { size_t namelen; - int err; struct symbol *sym; if (!prefix_skipped && (name[0] == depmod->cfg->sym_prefix)) @@ -1561,20 +1561,22 @@ static int depmod_symbol_add(struct depmod *depmod, const char *name, bool prefi namelen = strlen(name) + 1; sym = malloc(sizeof(struct symbol) + namelen); if (sym == NULL) - return -ENOMEM; + return NULL; sym->owner = (struct mod *)owner; sym->crc = crc; memcpy(sym->name, name, namelen); + return sym; +} - err = hash_add(depmod->symbols, sym->name, sym); - if (err < 0) { - free(sym); +static int depmod_symbol_add(struct depmod *depmod, struct symbol *sym) +{ + int err = hash_add(depmod->symbols, sym->name, sym); + if (err < 0) return err; - } - DBG("add %p sym=%s, owner=%p %s\n", sym, sym->name, owner, - owner != NULL ? owner->path : ""); + DBG("add %p sym=%s, owner=%p %s\n", sym, sym->name, sym->owner, + sym->owner != NULL ? sym->owner->path : ""); return 0; } @@ -1611,7 +1613,11 @@ static int depmod_load_modules(struct depmod *depmod) kmod_list_foreach(l, list) { const char *name = kmod_module_symbol_get_symbol(l); uint64_t crc = kmod_module_symbol_get_crc(l); - depmod_symbol_add(depmod, name, false, crc, mod); + struct symbol *sym; + + sym = depmod_symbol_create(depmod, name, false, crc, mod); + if (sym) + depmod_symbol_add(depmod, sym); } kmod_module_symbols_free_list(list); @@ -2645,13 +2651,24 @@ static int depmod_output(struct depmod *depmod, FILE *out) static void depmod_add_fake_syms(struct depmod *depmod) { + struct symbol *sym; + /* __this_module is magically inserted by kernel loader. */ - depmod_symbol_add(depmod, "__this_module", true, 0, NULL); + sym = depmod_symbol_create(depmod, "__this_module", true, 0, NULL); + if (sym) + depmod_symbol_add(depmod, sym); + /* On S390, this is faked up too */ - depmod_symbol_add(depmod, "_GLOBAL_OFFSET_TABLE_", true, 0, NULL); + sym = depmod_symbol_create(depmod, "_GLOBAL_OFFSET_TABLE_", true, 0, NULL); + if (sym) + depmod_symbol_add(depmod, sym); + /* On PowerPC64 ABIv2, .TOC. is more or less _GLOBAL_OFFSET_TABLE_ */ - if (!depmod_symbol_find(depmod, "TOC.")) - depmod_symbol_add(depmod, "TOC.", true, 0, NULL); + if (!depmod_symbol_find(depmod, "TOC.")) { + sym = depmod_symbol_create(depmod, "TOC.", true, 0, NULL); + if (sym) + depmod_symbol_add(depmod, sym); + } } static int depmod_load_symvers(struct depmod *depmod, const char *filename) @@ -2670,6 +2687,7 @@ static int depmod_load_symvers(struct depmod *depmod, const char *filename) /* eg. "0xb352177e\tfind_first_bit\tvmlinux\tEXPORT_SYMBOL" */ while (fgets(line, sizeof(line), fp) != NULL) { + struct symbol *symbol; const char *ver, *sym, *where; char *verend; uint64_t crc; @@ -2693,7 +2711,9 @@ static int depmod_load_symvers(struct depmod *depmod, const char *filename) continue; } - depmod_symbol_add(depmod, sym, false, crc, NULL); + symbol = depmod_symbol_create(depmod, sym, false, crc, NULL); + if (symbol) + depmod_symbol_add(depmod, symbol); } depmod_add_fake_syms(depmod); @@ -2721,6 +2741,7 @@ static int depmod_load_system_map(struct depmod *depmod, const char *filename) /* eg. c0294200 R __ksymtab_devfs_alloc_devnum */ while (fgets(line, sizeof(line), fp) != NULL) { + struct symbol *sym; char *p, *end; linenum++; @@ -2746,7 +2767,10 @@ static int depmod_load_system_map(struct depmod *depmod, const char *filename) if (end != NULL) *end = '\0'; - depmod_symbol_add(depmod, p + ksymstr_len, true, 0, NULL); + sym = depmod_symbol_create(depmod, p + ksymstr_len, true, 0, NULL); + if (sym) + depmod_symbol_add(depmod, sym); + continue; invalid_syntax: From 179b6c022ea89d005796583aebb8ed76cfce83e1 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Thu, 12 Feb 2026 14:59:15 +0000 Subject: [PATCH 3/4] tools/depmod: factor out module symbol resolution Split out the module symbol resolution - effectively, the initial decompression of the module and elf parsing - from adding the data into the depmod hashmap. This will come in handy with the next commit, which will delegate the symbol resolution (and thus the slowest part, decompression) to threads. Signed-off-by: Emil Velikov --- tools/depmod.c | 59 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/tools/depmod.c b/tools/depmod.c index 8a6535eca..22dcd5d08 100644 --- a/tools/depmod.c +++ b/tools/depmod.c @@ -1590,16 +1590,19 @@ static struct symbol *depmod_symbol_find(const struct depmod *depmod, const char return hash_find(depmod->symbols, name); } -static int depmod_load_modules(struct depmod *depmod) -{ - struct mod **itr, **itr_end; +struct module_symbols { + struct depmod *depmod; + struct mod **modules; + size_t modules_count; + struct array symbols; /* struct symbol */ +}; - DBG("load symbols (%zu modules)\n", depmod->modules.count); +static int resolve_module_symbols(struct module_symbols *mod_syms) +{ + array_init(&mod_syms->symbols, 128); - itr = (struct mod **)depmod->modules.array; - itr_end = itr + depmod->modules.count; - for (; itr < itr_end; itr++) { - struct mod *mod = *itr; + for (size_t i = 0; i < mod_syms->modules_count; i++) { + struct mod *mod = mod_syms->modules[i]; struct kmod_list *l, *list = NULL; int err = kmod_module_get_symbols(mod->kmod, &list); if (err < 0) { @@ -1615,9 +1618,19 @@ static int depmod_load_modules(struct depmod *depmod) uint64_t crc = kmod_module_symbol_get_crc(l); struct symbol *sym; - sym = depmod_symbol_create(depmod, name, false, crc, mod); - if (sym) - depmod_symbol_add(depmod, sym); + sym = depmod_symbol_create(mod_syms->depmod, name, false, crc, + mod); + if (sym == NULL) { + kmod_module_symbols_free_list(list); + return -ENOMEM; + } + + err = array_append(&mod_syms->symbols, sym); + if (err < 0) { + free(sym); + kmod_module_symbols_free_list(list); + return -ENOMEM; + } } kmod_module_symbols_free_list(list); @@ -1655,6 +1668,30 @@ static int depmod_load_modules(struct depmod *depmod) kmod_module_unref(mod->kmod); mod->kmod = NULL; } + return 0; +} + +static int depmod_load_modules(struct depmod *depmod) +{ + struct module_symbols mod_syms = { + .depmod = depmod, + .modules = (struct mod **)depmod->modules.array, + .modules_count = depmod->modules.count, + }; + int err; + + DBG("load symbols (%zu modules)\n", depmod->modules.count); + + err = resolve_module_symbols(&mod_syms); + if (err < 0) + return err; + + for (size_t i = 0; i < mod_syms.symbols.count; i++) { + struct symbol *sym = mod_syms.symbols.array[i]; + + depmod_symbol_add(depmod, sym); + } + array_free_array(&mod_syms.symbols); DBG("loaded symbols (%zu modules, %u symbols)\n", depmod->modules.count, hash_get_count(depmod->symbols)); From f65443f2a269955d0a5591c709ed76a226075739 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Fri, 13 Feb 2026 14:33:58 +0000 Subject: [PATCH 4/4] tools/depmod: Parallelize module loading Add pthread-based parallelization to depmod to improve performance on multi-core systems. The changes parallelize: - Module symbol loading Co-authored-by: jared mauch Signed-off-by: Emil Velikov --- meson.build | 3 ++ tools/depmod.c | 102 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 87 insertions(+), 18 deletions(-) diff --git a/meson.build b/meson.build index 5b914b74a..bf36d4435 100644 --- a/meson.build +++ b/meson.build @@ -444,10 +444,13 @@ if get_option('tools') 'tools/static-nodes.c', ) + pthread_dep = dependency('threads', required : true) + kmod = executable( 'kmod', kmod_sources, link_with : [libshared, libkmod_internal], + dependencies : pthread_dep, gnu_symbol_visibility : 'hidden', install : true, ) diff --git a/tools/depmod.c b/tools/depmod.c index 22dcd5d08..70f100d74 100644 --- a/tools/depmod.c +++ b/tools/depmod.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1597,8 +1598,10 @@ struct module_symbols { struct array symbols; /* struct symbol */ }; -static int resolve_module_symbols(struct module_symbols *mod_syms) +static void *resolve_module_symbols(void *arg) { + struct module_symbols *mod_syms = arg; + array_init(&mod_syms->symbols, 128); for (size_t i = 0; i < mod_syms->modules_count; i++) { @@ -1622,14 +1625,14 @@ static int resolve_module_symbols(struct module_symbols *mod_syms) mod); if (sym == NULL) { kmod_module_symbols_free_list(list); - return -ENOMEM; + return (void *)(intptr_t)-ENOMEM; } err = array_append(&mod_syms->symbols, sym); if (err < 0) { free(sym); kmod_module_symbols_free_list(list); - return -ENOMEM; + return (void *)(intptr_t)-ENOMEM; } } kmod_module_symbols_free_list(list); @@ -1644,7 +1647,7 @@ static int resolve_module_symbols(struct module_symbols *mod_syms) err = array_append(&mod->alias_values, value); if (err < 0) - return err; + return (void *)(intptr_t)err; continue; } if (streq(key, "softdep")) { @@ -1652,7 +1655,7 @@ static int resolve_module_symbols(struct module_symbols *mod_syms) err = array_append(&mod->softdep_values, value); if (err < 0) - return err; + return (void *)(intptr_t)err; continue; } if (streq(key, "weakdep")) { @@ -1660,7 +1663,7 @@ static int resolve_module_symbols(struct module_symbols *mod_syms) err = array_append(&mod->weakdep_values, value); if (err < 0) - return err; + return (void *)(intptr_t)err; continue; } } @@ -1668,30 +1671,93 @@ static int resolve_module_symbols(struct module_symbols *mod_syms) kmod_module_unref(mod->kmod); mod->kmod = NULL; } - return 0; + return (void *)(intptr_t)0; +} + +static unsigned int get_cpu_count(void) +{ + long nproc = sysconf(_SC_NPROCESSORS_ONLN); + return nproc > 0 ? (unsigned int)nproc : 1; } static int depmod_load_modules(struct depmod *depmod) { - struct module_symbols mod_syms = { - .depmod = depmod, - .modules = (struct mod **)depmod->modules.array, - .modules_count = depmod->modules.count, - }; + struct thread_info { + pthread_t tid; + struct module_symbols mod_syms; + } *tinfo; + unsigned int n_threads; + size_t modules_per_thread, last_modules_per_thread; int err; DBG("load symbols (%zu modules)\n", depmod->modules.count); - err = resolve_module_symbols(&mod_syms); - if (err < 0) + n_threads = get_cpu_count(); + if (n_threads > depmod->modules.count) + n_threads = depmod->modules.count; + + tinfo = calloc(n_threads, sizeof(*tinfo)); + if (tinfo == NULL) + return -ENOMEM; + + modules_per_thread = (depmod->modules.count + n_threads - 1) / n_threads; + last_modules_per_thread = + modules_per_thread - (depmod->modules.count % n_threads); + + for (unsigned int i = 0; i < n_threads; i++) { + struct module_symbols *mod_syms = &tinfo[i].mod_syms; + + mod_syms->depmod = depmod; + mod_syms->modules = + (struct mod **)depmod->modules.array + (i * modules_per_thread); + mod_syms->modules_count = modules_per_thread; + if (i + 1 == n_threads) + mod_syms->modules_count = last_modules_per_thread; + + err = pthread_create(&tinfo[i].tid, NULL, &resolve_module_symbols, + mod_syms); + if (err != 0) { + err = -err; // Most/all pthread API returns positive error + n_threads = i; + break; + } + } + + for (unsigned int i = 0; i < n_threads; i++) { + int local_err; + void *res; + + local_err = pthread_join(tinfo[i].tid, &res); + if (err == 0) { + if (local_err != 0) + err = -local_err; + if ((int)(intptr_t)res != 0) + err = (int)(intptr_t)res; + } + } + + if (err != 0) { + for (unsigned int i = 0; i < n_threads; i++) { + struct module_symbols *mod_syms = &tinfo[i].mod_syms; + + for (size_t j = 0; j < mod_syms->symbols.count; j++) + free(mod_syms->symbols.array[j]); + + array_free_array(&mod_syms->symbols); + } + free(tinfo); return err; + } - for (size_t i = 0; i < mod_syms.symbols.count; i++) { - struct symbol *sym = mod_syms.symbols.array[i]; + for (unsigned int i = 0; i < n_threads; i++) { + struct module_symbols *mod_syms = &tinfo[i].mod_syms; - depmod_symbol_add(depmod, sym); + for (size_t j = 0; j < mod_syms->symbols.count; j++) + depmod_symbol_add(depmod, mod_syms->symbols.array[j]); + + array_free_array(&mod_syms->symbols); } - array_free_array(&mod_syms.symbols); + free(tinfo); DBG("loaded symbols (%zu modules, %u symbols)\n", depmod->modules.count, hash_get_count(depmod->symbols));