Skip to content

libkmod: tools: Introduce 'module alternative' directory (was: module fallback) #261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
aa594f1
meson: add option MODULE_ALTERNATIVE_DIRECTORY
esposem Nov 27, 2024
f3aeade
meson: add ENABLE_ALTERNATIVE_DIR
esposem Jan 31, 2025
c7c0cc0
tools/log.h: add macros to catch logs and print them later
esposem Feb 3, 2025
977c13e
tools: improve error logs to specify in which dirname is the module m…
esposem Nov 27, 2024
32e21dc
tools/kmod: use log.h log functions instead of fprintf
esposem Feb 3, 2025
93e9285
tools/static-nodes: move main logic into helpers
esposem Nov 27, 2024
544ec40
tools/static-nodes: add logic for MODULE_ALTERNATIVE_DIRECTORY
esposem Nov 27, 2024
86c5677
tools/static-nodes: perform alternative directory lookup only if e
esposem Feb 3, 2025
311d169
tools/modinfo: move main logic into helpers
esposem Nov 27, 2024
a16a5ba
tools/modinfo: add logic for MODULE_ALTERNATIVE_DIRECTORY
esposem Nov 27, 2024
b4653cf
tools/modinfo: perform alternative directory lookup only if enabled --
esposem Feb 3, 2025
7609ec9
tools/modinfo: avoid redundant log messages -- can be squashed
esposem Feb 3, 2025
ba3b642
testsuite/modinfo: test MODULE_ALTERNATIVE_DIRECTORY
esposem Jan 28, 2025
668277a
tools/modprobe: reduce LOG level otherwise it exits failure immediately
esposem Nov 27, 2024
ace85d1
tools/modprobe: move main logic into helpers
esposem Nov 27, 2024
288d0ca
tools/modprobe: add logic for MODULE_ALTERNATIVE_DIRECTORY
esposem Nov 27, 2024
0ab9b31
tools/modprobe: perform alternative directory lookup only if enabled …
esposem Feb 3, 2025
26f18bf
tools/modprobe: avoid redundant log messages -- can be squashed
esposem Jan 27, 2025
54d28d0
tools/insmod: move main logic into helpers
esposem Nov 27, 2024
7524a89
tools/insmod: add logic for MODULE_ALTERNATIVE_DIRECTORY
esposem Nov 27, 2024
34fb2d3
tools/insmod: perform alternative directory lookup only if enabled --…
esposem Feb 3, 2025
7647358
tools/insmod: avoid redundant log messages -- can be squashed
esposem Feb 3, 2025
ae64071
tools/lsmod: move main logic into helpers
esposem Nov 27, 2024
8ebaf6e
tools/lsmod: add logic for MODULE_ALTERNATIVE_DIRECTORY
esposem Nov 27, 2024
19430f9
tools/lsmod: perform alternative directory lookup only if enabled -- …
esposem Feb 3, 2025
0ad9d9a
tools/lsmod: avoid redundant log messages -- can be squashed
esposem Feb 3, 2025
7ef5c7b
tools/rmmod: move main logic into helpers
esposem Nov 27, 2024
3cb11b6
tools/rmmod: add logic for MODULE_ALTERNATIVE_DIRECTORY
esposem Nov 27, 2024
dd781c1
tools/rmmod: perform alternative directory lookup only if enabled -- …
esposem Feb 3, 2025
cdb9e3e
tools/rmmod: avoid redundant log messages -- can be squashed
esposem Feb 3, 2025
d870129
man: add MODULE_ALTERNATIVE_DIRECTORY documentation
esposem Jan 27, 2025
c0bbebf
man: mention enable-alternative-dir flag at compile time -- can be
esposem Feb 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ AM_CPPFLAGS = \
-DSYSCONFDIR=\""$(sysconfdir)"\" \
-DDISTCONFDIR=\""$(distconfdir)"\" \
-DMODULE_DIRECTORY=\""$(module_directory)"\" \
-DENABLE_ALTERNATIVE_DIR=\""$(enable_alternative_dir)
-DMODULE_ALTERNATIVE_DIRECTORY=\""$(module_alternative_directory)"\" \
${zlib_CFLAGS}

AM_CFLAGS = $(OUR_CFLAGS)
Expand Down Expand Up @@ -198,7 +200,7 @@ MODULE_PLAYGROUND = testsuite/module-playground
BUILD_MODULES = $(AM_V_GEN) $(top_srcdir)/scripts/setup-modules.sh $(top_srcdir) $(top_builddir) $(MODULE_PLAYGROUND)
ROOTFS = testsuite/rootfs
ROOTFS_PRISTINE = $(top_srcdir)/testsuite/rootfs-pristine
CREATE_ROOTFS = $(AM_V_GEN) $(top_srcdir)/scripts/setup-rootfs.sh $(ROOTFS_PRISTINE) $(ROOTFS) $(MODULE_PLAYGROUND) $(top_builddir)/config.h $(sysconfdir) $(module_directory)
CREATE_ROOTFS = $(AM_V_GEN) $(top_srcdir)/scripts/setup-rootfs.sh $(ROOTFS_PRISTINE) $(ROOTFS) $(MODULE_PLAYGROUND) $(top_builddir)/config.h $(sysconfdir) $(module_directory) $(module_alternative_directory)

build-module-playground:
$(BUILD_MODULES)
Expand Down
56 changes: 33 additions & 23 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,16 @@ AC_ARG_WITH([module_directory],
[], [with_module_directory=/lib/modules])
AC_SUBST([module_directory], [$with_module_directory])

AC_ARG_ENABLE([enable_alternative_dir],
AS_HELP_STRING([--enable-alternative-dir], [enable alternative module directory @<:@default=disabled@:>@]),
[], [enable_alternative_dir=no])
AC_ARG_WITH([module_alternative_directory],
AS_HELP_STRING([--with-module-alternative_directory=DIR], [alternative directory in which to look for kernel modules @<:@default=/run/modules@:>@]),
[], [with_module_alternative_directory=/run/modules])
AC_SUBST([module_alternative_directory], [$with_module_alternative_directory])

# Check all directory arguments for consistency.
for ac_var in distconfdir module_directory
for ac_var in distconfdir module_directory module_alternative_directory
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
Expand Down Expand Up @@ -335,26 +343,28 @@ AC_MSG_RESULT([
$PACKAGE $VERSION
=======

module_directory: ${module_directory}
prefix: ${prefix}
sysconfdir: ${sysconfdir}
distconfdir: ${distconfdir}
libdir: ${libdir}
includedir: ${includedir}
bindir: ${bindir}
Bash completions dir: ${with_bashcompletiondir}

compiler: ${CC}
cflags: ${with_cflags} ${CFLAGS}
ldflags: ${with_ldflags} ${LDFLAGS}

tools: ${enable_tools}
logging: ${enable_logging}
compression: zstd=${with_zstd} xz=${with_xz} zlib=${with_zlib}
debug: ${enable_debug}
coverage: ${enable_coverage}
doc: ${enable_gtk_doc}
man: ${enable_manpages}

features: ${with_features}
module_directory: ${module_directory}
enable_alternative_dir: ${enable_alternative_dir}
module_alternative_directory: ${module_alternative_directory}
prefix: ${prefix}
sysconfdir: ${sysconfdir}
distconfdir: ${distconfdir}
libdir: ${libdir}
includedir: ${includedir}
bindir: ${bindir}
Bash completions dir: ${with_bashcompletiondir}

compiler: ${CC}
cflags: ${with_cflags} ${CFLAGS}
ldflags: ${with_ldflags} ${LDFLAGS}

tools: ${enable_tools}
logging: ${enable_logging}
compression: zstd=${with_zstd} xz=${with_xz} zlib=${with_zlib}
debug: ${enable_debug}
coverage: ${enable_coverage}
doc: ${enable_gtk_doc}
man: ${enable_manpages}

features: ${with_features}
])
1 change: 1 addition & 0 deletions man/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ define generate_manpage
sed -e 's|@SYSCONFDIR@|$(sysconfdir)|g' | \
sed -e 's|@DISTCONFDIR@|$(distconfdir)|g' | \
sed -e 's|@MODULE_DIRECTORY@|$(module_directory)|g' | \
sed -e 's|@MODULE_ALTERNATIVE_DIRECTORY@|$(module_alternative_directory)|g' | \
$(SCDOC) > $@
endef

Expand Down
7 changes: 7 additions & 0 deletions man/insmod.8.scd
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ Only the most general of error messages are reported: as the work of trying to
link the module is now done inside the kernel, the *dmesg*(1) usually gives more
information about errors.

*insmod* will look by default at modules stored in @MODULE_DIRECTORY@, but if
the folder is missing or the module is not found and kmod is compiled with
@enable-alternative-dir=true@, it will automatically look at the fallback
directory @MODULE_ALTERNATIVE_DIRECTORY@.
In that case, this program will only fail if the provided module is not found in
both directories.

# OPTIONS

*-f*, *--force*
Expand Down
3 changes: 3 additions & 0 deletions man/lsmod.8.scd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ lsmod - Show the status of modules in the Linux Kernel
*lsmod* is a trivial program which nicely formats the contents of the
_/proc/modules_, showing what kernel modules are currently loaded.

*lsmod* will look by default at modules stored in @MODULE_DIRECTORY@, but if
the folder is missing , it will automatically look at the fallback directory @MODULE_ALTERNATIVE_DIRECTORY@.

# OPTIONS

*-s*, *--syslog*
Expand Down
16 changes: 13 additions & 3 deletions man/modinfo.8.scd
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,19 @@ modinfo - Show information about a Linux Kernel module
# DESCRIPTION

*modinfo* extracts information from the Linux Kernel modules given on the
command line. If the module name is not a filename, then the @MODULE_DIRECTORY@/
_version_ directory is searched, as is also done by *modprobe*(8) when loading
kernel modules.
command line.

*modinfo* will search by default for modules stored in @MODULE_DIRECTORY@, but
if the folder is missing or the module is not found and kmod is compiled with
@enable-alternative-dir=true@, it will automatically look at the fallback
directory @MODULE_ALTERNATIVE_DIRECTORY@.
In that case, this program will only fail if the provided module is not found in
both directories.

If the module name is not a filename, then the @MODULE_DIRECTORY@/
_version_ directory is searched first, and then if enabled
@MODULE_ALTERNATIVE_DIRECTORY@/_version_, as is also done by *modprobe*(8) when
loading kernel modules.

*modinfo* by default lists each attribute of the module in form _fieldname_ :
_value_, for easy reading. The filename is listed the same way (although it's
Expand Down
24 changes: 24 additions & 0 deletions man/modprobe.8.scd
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,30 @@ is relative, it must explicitly start with "./". Note that this may fail when
using a path to a module with dependencies not matching the installed *depmod*
database.

*modprobe* will search by default for modules stored in @MODULE_DIRECTORY@, but
if the folder is missing or the module is not found and kmod is compiled with
@enable-alternative-dir=true@, it will automatically look at the fallback
directory @MODULE_ALTERNATIVE_DIRECTORY@.
In that case, this program will only fail if the provided module is not found in
both directories.

The rationale for @MODULE_ALTERNATIVE_DIRECTORY@ is that this folder could be
used to reference pre-build or distro-provided default modules, and leave
@MODULE_DIRECTORY@ to point custom locally generated modules. In this way, the
first lookup always happens in @MODULE_DIRECTORY@ and will always reference the
local modules, but if for some reason some module is missing,
@MODULE_ALTERNATIVE_DIRECTORY@ could be used as fallback as source of default
standard modules.

Another specific use case for this is with UKIs (Unified Kernel Image).
In this scenario, there is the possibility of not keeping two copies of the
kernel modules (one for initramfs and not for rootfs), but instead copy the ones
in initramfs to tmpfs, e.g. in /run/modules. Note that modules are not directly
copied in rootfs because it might also be read-only mounted.
This copy is feasible because an UKI ships kernel and initramfs together, so
there is no need to locally build anything, avoiding kernel-initramfs version
mismatches.

# OPTIONS

*-a*, *--all*
Expand Down
7 changes: 7 additions & 0 deletions man/rmmod.8.scd
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ kernel (when module unloading support is provided). Most users will want to use
*modprobe*(8) with the *-r* option instead since it removes unused dependent
modules as well.

*rmmod* will look by default at modules stored in @MODULE_DIRECTORY@, but if
the folder is missing or the module is not found and kmod is compiled with
@enable-alternative-dir=true@, it will automatically look at the fallback
directory @MODULE_ALTERNATIVE_DIRECTORY@.
In that case, this program will only fail if the provided module is not found in
both directories.

When a list of modules is provided, the program will process them one at a time.
If a module is not found, *rmmod* will immediately exit with an error code.
Should the module removal fail, the program will log an error AND continue with
Expand Down
21 changes: 14 additions & 7 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ datadir = prefixdir / get_option('datadir')

distconfdir = get_option('distconfdir')
moduledir = get_option('moduledir')
enablealternativedir = get_option('enable-alternative-dir')
modulealternativedir = get_option('modulealternativedir')
cdata.set10('ENABLE_ALTERNATIVE_DIR', enablealternativedir)

bashcompletiondir = get_option('bashcompletiondir')
fishcompletiondir = get_option('fishcompletiondir')
Expand All @@ -204,6 +207,7 @@ _customdirs = [
# The defaults are hard-coded due to historical reasons
['distconfdir', prefixdir / 'lib', 'DISTCONFDIR'],
['moduledir', '/lib/modules', 'MODULE_DIRECTORY'],
['modulealternativedir', '/run/modules', 'MODULE_ALTERNATIVE_DIRECTORY'],
]

foreach tuple : _customdirs
Expand Down Expand Up @@ -472,6 +476,7 @@ _kmod_variables = [
'sysconfdir=' + sysconfdir,
'distconfdir=' + distconfdir,
'module_directory=' + moduledir,
'module_alternative_directory=' + modulealternativedir,
]

# Don't (space) escape variables with space-separated lists, for consistency
Expand Down Expand Up @@ -565,6 +570,7 @@ summary({
summary({
'distconfdir' : distconfdir,
'moduledir' : moduledir,
'modulealternativedir' : modulealternativedir,
}, section : 'Kmod specific')

summary({
Expand All @@ -574,13 +580,14 @@ summary({
}, section : 'Shell completions')

summary({
'tools' : get_option('tools'),
'logging' : get_option('logging'),
'debug-messages' : get_option('debug-messages'),
'build-tests' : get_option('build-tests'),
'manpages' : get_option('manpages'),
'docs' : get_option('docs'),
'dlopen' : get_option('dlopen'),
'tools' : get_option('tools'),
'logging' : get_option('logging'),
'debug-messages' : get_option('debug-messages'),
'build-tests' : get_option('build-tests'),
'enable-alternative-dir' : get_option('enable-alternative-dir'),
'manpages' : get_option('manpages'),
'docs' : get_option('docs'),
'dlopen' : get_option('dlopen'),
}, section : 'Options')

summary({
Expand Down
13 changes: 13 additions & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ option(
description : 'Directory to look for kernel modules. Default: /lib/modules',
)

option(
'enable-alternative-dir',
type : 'boolean',
value : false,
description : 'Always use a fallback alternative directory to look for kernel modules. Default: false',
)

option(
'modulealternativedir',
type : 'string',
description : 'Alternative directory to look for kernel modules, if enable-alternative-dir is true. Otherwise unused. Default: /run/modules',
)

option(
'bashcompletiondir',
type : 'string',
Expand Down
1 change: 1 addition & 0 deletions scripts/setup-rootfs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ MODULE_PLAYGROUND=$3
CONFIG_H=$4
SYSCONFDIR=$5
MODULE_DIRECTORY=$6
MODULE_ALTERNATIVE_DIRECTORY=$7

# create rootfs from rootfs-pristine

Expand Down
1 change: 1 addition & 0 deletions testsuite/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ create_rootfs = custom_target(
meson.project_build_root() / 'config.h',
sysconfdir,
moduledir,
modulealternativedir,
],
output : 'stamp-rootfs',
console : true,
Expand Down
45 changes: 45 additions & 0 deletions testsuite/test-modinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,4 +124,49 @@ DEFINE_TEST(test_modinfo_builtin,
.out = TESTSUITE_ROOTFS "test-modinfo/correct-builtin.txt",
});

static noreturn int test_modinfo_alternative(const struct test *t)
{
const char *const args[] = {
// clang-format off
progname,
"-F", "filename",
"mod-simple",
NULL,
// clang-format on
};
test_spawn_prog(progname, args);
exit(EXIT_FAILURE);
}
DEFINE_TEST(test_modinfo_alternative,
.description = "check if modinfo finds module in alternative directory",
.config = {
[TC_ROOTFS] = TESTSUITE_ROOTFS "test-modinfo/builtin",
[TC_UNAME_R] = "6.11.0",
},
.output = {
.out = TESTSUITE_ROOTFS "test-modinfo/correct-external.txt",
});

static noreturn int test_modinfo_alternative_inv(const struct test *t)
{
const char *const args[] = {
// clang-format off
progname,
"intel_uncore",
NULL,
// clang-format on
};
test_spawn_prog(progname, args);
exit(EXIT_FAILURE);
}
DEFINE_TEST(test_modinfo_alternative_inv,
.description = "check if modinfo finds module in alternative directory",
.config = {
[TC_ROOTFS] = TESTSUITE_ROOTFS "test-modinfo/external",
[TC_UNAME_R] = "4.4.4",
},
.output = {
.out = TESTSUITE_ROOTFS "test-modinfo/correct-builtin.txt",
});

TESTSUITE_MAIN();
Loading