Repository: systemd/mkosi

Issue:
`--incremental` with `KernelModules*` changes lead to extra/missing modules
Distribution: Arch Linux
Kernel: Linux 6.7.8-arch1-1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux
`mkosi` version: 20.2

# Description

The `Applying kernel module filters` step is cached when using `mkosi --incremental`, however, the cache isn't invalidated if you change the kernel module related options in `mkosi`'s configs. Any changes to the options will be silently ignored until something like `mkosi -ffi` is ran to reset the incremental cache.

Ideally, instead of invalidating the cache on every change to the kernel module options, the step would be ran a second time (only when options change) so users can quickly add or remove kernel modules without needing to go through the prepare steps again, however, I understand if this idea is possibly too difficult to implement in practice and cache invalidation is the only solution.


Discussion:

Resolving patch:
diff --git a/mkosi/__init__.py b/mkosi/__init__.py
--- a/mkosi/__init__.py
+++ b/mkosi/__init__.py
@@ -2494,7 +2494,7 @@ def configure_clock(context: Context) -> None:
         (context.root / "usr/lib/clock-epoch").touch()
 
 
-def run_depmod(context: Context, *, force: bool = False) -> None:
+def run_depmod(context: Context, *, cache: bool = False) -> None:
     if context.config.overlay or context.config.output_format.is_extension_image():
         return
 
@@ -2509,7 +2509,7 @@ def run_depmod(context: Context, *, force: bool = False) -> None:
         modulesd = context.root / "usr/lib/modules" / kver
 
         if (
-            not force and
+            not cache and
             not context.config.kernel_modules_exclude and
             all((modulesd / o).exists() for o in outputs)
         ):
@@ -2517,13 +2517,14 @@ def run_depmod(context: Context, *, force: bool = False) -> None:
             if all(m.stat().st_mtime <= mtime for m in modulesd.rglob("*.ko*")):
                 continue
 
-        process_kernel_modules(
-            context.root, kver,
-            include=context.config.kernel_modules_include,
-            exclude=context.config.kernel_modules_exclude,
-            host=context.config.kernel_modules_include_host,
-            sandbox=context.sandbox,
-        )
+        if not cache:
+            process_kernel_modules(
+                context.root, kver,
+                include=context.config.kernel_modules_include,
+                exclude=context.config.kernel_modules_exclude,
+                host=context.config.kernel_modules_include_host,
+                sandbox=context.sandbox,
+            )
 
         with complete_step(f"Running depmod for {kver}"):
             run(["depmod", "--all", "--basedir", context.root, kver],
@@ -3167,7 +3168,7 @@ def build_image(context: Context) -> None:
                 run_prepare_scripts(context, build=False)
                 install_build_packages(context)
                 run_prepare_scripts(context, build=True)
-                run_depmod(context, force=True)
+                run_depmod(context, cache=True)
 
             save_cache(context)
             reuse_cache(context)
diff --git a/mkosi/kmod.py b/mkosi/kmod.py
--- a/mkosi/kmod.py
+++ b/mkosi/kmod.py
@@ -199,7 +199,7 @@ def process_kernel_modules(
     host: bool,
     sandbox: SandboxProtocol = nosandbox,
 ) -> None:
-    if not include and not exclude:
+    if not exclude:
         return
 
     with complete_step("Applying kernel module filters"):


Test patch: