Skip to content

Commit 3de4c73

Browse files
athierry1johannbg
authored andcommitted
feat(dracut-install): add fw_devlink suppliers as module dependencies
Dracut currently finds kernel module dependencies using two methods: depmod and softdeps. However, these are often insufficient on embedded systems where a lot of driver dependencies are only described in the device tree. This is often the case for low-level devices such as clocks, regulators, pinctrls, etc. This patch allows dracut to find those device tree dependencies, by parsing the sysfs supplier nodes populated by fw_devlink. Signed-off-by: Adrien Thierry <[email protected]>
1 parent f0c3b68 commit 3de4c73

File tree

1 file changed

+156
-14
lines changed

1 file changed

+156
-14
lines changed

src/install/dracut-install.c

Lines changed: 156 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ FILE *logfile_f = NULL;
8282
static Hashmap *items = NULL;
8383
static Hashmap *items_failed = NULL;
8484
static Hashmap *modules_loaded = NULL;
85+
static Hashmap *modules_suppliers = NULL;
8586
static regex_t mod_filter_path;
8687
static regex_t mod_filter_nopath;
8788
static regex_t mod_filter_symbol;
@@ -94,7 +95,7 @@ static bool arg_mod_filter_nosymbol = false;
9495
static bool arg_mod_filter_noname = false;
9596

9697
static int dracut_install(const char *src, const char *dst, bool isdir, bool resolvedeps, bool hashdst);
97-
static int install_dependent_modules(struct kmod_list *modlist);
98+
static int install_dependent_modules(struct kmod_ctx *ctx, struct kmod_list *modlist, Hashmap *suppliers_paths);
9899

99100
static void item_free(char *i)
100101
{
@@ -1499,7 +1500,111 @@ static bool check_module_path(const char *path)
14991500
return true;
15001501
}
15011502

1502-
static int install_dependent_module(struct kmod_module *mod, int *err)
1503+
static int find_kmod_module_from_sysfs_node(struct kmod_ctx *ctx, const char *sysfs_node, int sysfs_node_len,
1504+
struct kmod_list **modules)
1505+
{
1506+
char modalias_path[PATH_MAX];
1507+
if (snprintf(modalias_path, sizeof(modalias_path), "%.*s/modalias", sysfs_node_len,
1508+
sysfs_node) >= sizeof(modalias_path))
1509+
return -1;
1510+
1511+
_cleanup_close_ int modalias_file = -1;
1512+
if ((modalias_file = open(modalias_path, O_RDONLY | O_CLOEXEC)) == -1)
1513+
return 0;
1514+
1515+
char alias[page_size()];
1516+
ssize_t len = read(modalias_file, alias, sizeof(alias));
1517+
alias[len - 1] = '\0';
1518+
1519+
return kmod_module_new_from_lookup(ctx, alias, modules);
1520+
}
1521+
1522+
static int find_modules_from_sysfs_node(struct kmod_ctx *ctx, const char *sysfs_node, Hashmap *modules)
1523+
{
1524+
_cleanup_kmod_module_unref_list_ struct kmod_list *list = NULL;
1525+
struct kmod_list *l = NULL;
1526+
1527+
if (find_kmod_module_from_sysfs_node(ctx, sysfs_node, strlen(sysfs_node), &list) >= 0) {
1528+
kmod_list_foreach(l, list) {
1529+
struct kmod_module *mod = kmod_module_get_module(l);
1530+
char *module = strdup(kmod_module_get_name(mod));
1531+
kmod_module_unref(mod);
1532+
1533+
if (hashmap_put(modules, module, module) < 0)
1534+
free(module);
1535+
}
1536+
}
1537+
1538+
return 0;
1539+
}
1540+
1541+
static void find_suppliers_for_sys_node(struct kmod_ctx *ctx, Hashmap *suppliers, const char *node_path_raw,
1542+
size_t node_path_len)
1543+
{
1544+
char node_path[PATH_MAX];
1545+
char real_path[PATH_MAX];
1546+
1547+
memcpy(node_path, node_path_raw, node_path_len);
1548+
node_path[node_path_len] = '\0';
1549+
1550+
DIR *d;
1551+
struct dirent *dir;
1552+
while (realpath(node_path, real_path) != NULL && strcmp(real_path, "/sys/devices")) {
1553+
d = opendir(node_path);
1554+
if (d) {
1555+
size_t real_path_len = strlen(real_path);
1556+
while ((dir = readdir(d)) != NULL) {
1557+
if (strstr(dir->d_name, "supplier:platform") != NULL) {
1558+
if (snprintf(real_path + real_path_len, sizeof(real_path) - real_path_len, "/%s/supplier",
1559+
dir->d_name) < sizeof(real_path) - real_path_len) {
1560+
char *real_supplier_path = realpath(real_path, NULL);
1561+
if (real_supplier_path != NULL)
1562+
if (hashmap_put(suppliers, real_supplier_path, real_supplier_path) < 0)
1563+
free(real_supplier_path);
1564+
}
1565+
}
1566+
}
1567+
closedir(d);
1568+
}
1569+
strncat(node_path, "/..", 3); // Also find suppliers of parents
1570+
}
1571+
}
1572+
1573+
static void find_suppliers(struct kmod_ctx *ctx)
1574+
{
1575+
_cleanup_fts_close_ FTS *fts;
1576+
char *paths[] = { "/sys/devices/platform", NULL };
1577+
fts = fts_open(paths, FTS_NOSTAT | FTS_PHYSICAL, NULL);
1578+
1579+
for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1580+
if (strcmp(ftsent->fts_name, "modalias") == 0) {
1581+
_cleanup_kmod_module_unref_list_ struct kmod_list *list = NULL;
1582+
struct kmod_list *l;
1583+
1584+
if (find_kmod_module_from_sysfs_node(ctx, ftsent->fts_parent->fts_path, ftsent->fts_parent->fts_pathlen, &list) < 0)
1585+
continue;
1586+
1587+
kmod_list_foreach(l, list) {
1588+
_cleanup_kmod_module_unref_ struct kmod_module *mod = kmod_module_get_module(l);
1589+
const char *name = kmod_module_get_name(mod);
1590+
Hashmap *suppliers = hashmap_get(modules_suppliers, name);
1591+
if (suppliers == NULL) {
1592+
suppliers = hashmap_new(string_hash_func, string_compare_func);
1593+
hashmap_put(modules_suppliers, strdup(name), suppliers);
1594+
}
1595+
1596+
find_suppliers_for_sys_node(ctx, suppliers, ftsent->fts_parent->fts_path, ftsent->fts_parent->fts_pathlen);
1597+
}
1598+
}
1599+
}
1600+
}
1601+
1602+
static Hashmap *find_suppliers_paths_for_module(const char *module)
1603+
{
1604+
return hashmap_get(modules_suppliers, module);
1605+
}
1606+
1607+
static int install_dependent_module(struct kmod_ctx *ctx, struct kmod_module *mod, Hashmap *suppliers_paths, int *err)
15031608
{
15041609
const char *path = NULL;
15051610
const char *name = NULL;
@@ -1530,13 +1635,13 @@ static int install_dependent_module(struct kmod_module *mod, int *err)
15301635
log_debug("dracut_install '%s' '%s' OK", path, &path[kerneldirlen]);
15311636
install_firmware(mod);
15321637
modlist = kmod_module_get_dependencies(mod);
1533-
*err = install_dependent_modules(modlist);
1638+
*err = install_dependent_modules(ctx, modlist, suppliers_paths);
15341639
if (*err == 0) {
15351640
*err = kmod_module_get_softdeps(mod, &modpre, &modpost);
15361641
if (*err == 0) {
15371642
int r;
1538-
*err = install_dependent_modules(modpre);
1539-
r = install_dependent_modules(modpost);
1643+
*err = install_dependent_modules(ctx, modpre, NULL);
1644+
r = install_dependent_modules(ctx, modpost, NULL);
15401645
*err = *err ? : r;
15411646
}
15421647
}
@@ -1547,22 +1652,46 @@ static int install_dependent_module(struct kmod_module *mod, int *err)
15471652
return 0;
15481653
}
15491654

1550-
static int install_dependent_modules(struct kmod_list *modlist)
1655+
static int install_dependent_modules(struct kmod_ctx *ctx, struct kmod_list *modlist, Hashmap *suppliers_paths)
15511656
{
15521657
struct kmod_list *itr = NULL;
15531658
int ret = 0;
15541659

15551660
kmod_list_foreach(itr, modlist) {
15561661
_cleanup_kmod_module_unref_ struct kmod_module *mod = NULL;
15571662
mod = kmod_module_get_module(itr);
1558-
if (install_dependent_module(mod, &ret))
1663+
if (install_dependent_module(ctx, mod, find_suppliers_paths_for_module(kmod_module_get_name(mod)), &ret))
15591664
return -1;
15601665
}
15611666

1667+
const char *supplier_path;
1668+
Iterator i;
1669+
HASHMAP_FOREACH(supplier_path, suppliers_paths, i) {
1670+
_cleanup_destroy_hashmap_ Hashmap *modules = hashmap_new(string_hash_func, string_compare_func);
1671+
find_modules_from_sysfs_node(ctx, supplier_path, modules);
1672+
1673+
_cleanup_destroy_hashmap_ Hashmap *suppliers = hashmap_new(string_hash_func, string_compare_func);
1674+
find_suppliers_for_sys_node(ctx, suppliers, supplier_path, strlen(supplier_path));
1675+
1676+
if (!hashmap_isempty(modules)) { // Supplier is a module
1677+
const char *module;
1678+
Iterator j;
1679+
HASHMAP_FOREACH(module, modules, j) {
1680+
_cleanup_kmod_module_unref_ struct kmod_module *mod = NULL;
1681+
if (!kmod_module_new_from_name(ctx, module, &mod)) {
1682+
if (install_dependent_module(ctx, mod, suppliers, &ret))
1683+
return -1;
1684+
}
1685+
}
1686+
} else { // Supplier is builtin
1687+
install_dependent_modules(ctx, NULL, suppliers);
1688+
}
1689+
}
1690+
15621691
return ret;
15631692
}
15641693

1565-
static int install_module(struct kmod_module *mod)
1694+
static int install_module(struct kmod_ctx *ctx, struct kmod_module *mod)
15661695
{
15671696
int ret = 0;
15681697
_cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
@@ -1612,15 +1741,16 @@ static int install_module(struct kmod_module *mod)
16121741
}
16131742
install_firmware(mod);
16141743

1744+
Hashmap *suppliers = find_suppliers_paths_for_module(name);
16151745
modlist = kmod_module_get_dependencies(mod);
1616-
ret = install_dependent_modules(modlist);
1746+
ret = install_dependent_modules(ctx, modlist, suppliers);
16171747

16181748
if (ret == 0) {
16191749
ret = kmod_module_get_softdeps(mod, &modpre, &modpost);
16201750
if (ret == 0) {
16211751
int r;
1622-
ret = install_dependent_modules(modpre);
1623-
r = install_dependent_modules(modpost);
1752+
ret = install_dependent_modules(ctx, modpre, NULL);
1753+
r = install_dependent_modules(ctx, modpost, NULL);
16241754
ret = ret ? : r;
16251755
}
16261756
}
@@ -1731,6 +1861,9 @@ static int install_modules(int argc, char **argv)
17311861
if (p != NULL)
17321862
kerneldirlen = p - abskpath;
17331863

1864+
modules_suppliers = hashmap_new(string_hash_func, string_compare_func);
1865+
find_suppliers(ctx);
1866+
17341867
if (arg_hostonly) {
17351868
char *modalias_file;
17361869
modalias_file = getenv("DRACUT_KERNEL_MODALIASES");
@@ -1818,7 +1951,7 @@ static int install_modules(int argc, char **argv)
18181951
}
18191952
kmod_list_foreach(itr, modlist) {
18201953
mod = kmod_module_get_module(itr);
1821-
r = install_module(mod);
1954+
r = install_module(ctx, mod);
18221955
kmod_module_unref(mod);
18231956
if ((r < 0) && !arg_optional) {
18241957
if (!arg_silent)
@@ -1897,7 +2030,7 @@ static int install_modules(int argc, char **argv)
18972030
}
18982031
kmod_list_foreach(itr, modlist) {
18992032
mod = kmod_module_get_module(itr);
1900-
r = install_module(mod);
2033+
r = install_module(ctx, mod);
19012034
kmod_module_unref(mod);
19022035
if ((r < 0) && !arg_optional) {
19032036
if (!arg_silent)
@@ -1948,7 +2081,7 @@ static int install_modules(int argc, char **argv)
19482081
}
19492082
kmod_list_foreach(itr, modlist) {
19502083
mod = kmod_module_get_module(itr);
1951-
r = install_module(mod);
2084+
r = install_module(ctx, mod);
19522085
kmod_module_unref(mod);
19532086
if ((r < 0) && !arg_optional) {
19542087
if (!arg_silent)
@@ -2111,9 +2244,18 @@ int main(int argc, char **argv)
21112244
while ((i = hashmap_steal_first(items_failed)))
21122245
item_free(i);
21132246

2247+
Hashmap *h;
2248+
while ((h = hashmap_steal_first(modules_suppliers))) {
2249+
while ((i = hashmap_steal_first(h))) {
2250+
item_free(i);
2251+
}
2252+
hashmap_free(h);
2253+
}
2254+
21142255
hashmap_free(items);
21152256
hashmap_free(items_failed);
21162257
hashmap_free(modules_loaded);
2258+
hashmap_free(modules_suppliers);
21172259

21182260
strv_free(firmwaredirs);
21192261
strv_free(pathdirs);

0 commit comments

Comments
 (0)