]> git.ipfire.org Git - thirdparty/dracut-ng.git/commitdiff
feat(kernel-modules-export): make kernel modules from initramfs available
authorJo Zzsi <jozzsicsataban@gmail.com>
Fri, 10 Oct 2025 12:45:07 +0000 (08:45 -0400)
committerBenjamin Drung <bdrung@ubuntu.com>
Fri, 31 Oct 2025 16:56:17 +0000 (17:56 +0100)
Although the kernel module for the filesystem is in the initramfs,
it might not loaded in the initramfs, because it is not needed to mount
the root filesystem.

This feature arranges for the kernel modules in the initramfs to be
placed into /lib/modules.

When booting with an external-to-rootfs kernel you need to ensure that
/lib/modules contains any necessary modules not already loaded.

.github/labeler.yml
.github/workflows/integration.yml
doc_site/modules/ROOT/pages/modules/core.adoc
man/dracut.cmdline.7.adoc
modules.d/70kernel-modules-export/module-setup.sh [new file with mode: 0755]
modules.d/70kernel-modules-export/modules-export.sh [new file with mode: 0755]
test/TEST-44-DRIVERS/Makefile [new file with mode: 0644]
test/TEST-44-DRIVERS/create-root.sh [new file with mode: 0755]
test/TEST-44-DRIVERS/test.sh [new file with mode: 0755]

index ae8d05d1eba73069a270c0319dadde73080c4a31..583e9b2c4c16252672078e12ae09fea539fdc128 100644 (file)
@@ -323,6 +323,10 @@ kernel-modules:
   - changed-files:
       - any-glob-to-any-file: 'modules.d/[0-9][0-9]kernel-modules/*'
 
+kernel-modules-export:
+  - changed-files:
+      - any-glob-to-any-file: 'modules.d/[0-9][0-9]kernel-modules-export/*'
+
 kernel-modules-extra:
   - changed-files:
       - any-glob-to-any-file: 'modules.d/[0-9][0-9]kernel-modules-extra/*'
index 88c70bb2a2ced8b7dcd2b5edaede10892f480085..240d1d29f6bdfc79eecbc77f5e0fb2de11de6933 100644 (file)
@@ -121,6 +121,7 @@ jobs:
                     - "41"
                     - "42"
                     - "43"
+                    - "44"
                 exclude:
                     # https://github.com/dracut-ng/dracut-ng/issues/1677
                     - container: arch:latest
index 4b5c35886b682cf3370db394f52ce77e30075215..d4785c7bf8291f46554f8dce7fa21c4624631dbf 100644 (file)
@@ -205,6 +205,10 @@ code, there are no specific types or categories for dracut modules.
 | mount block fallback device as rootfs
 | device
 
+| kernel-modules-export
+| make kernel modules from initramfs available to rootfs
+| kernel
+
 | securityfs
 | mount securityfs early
 | filesystem
index 5277e2d2dd6f8b6d956d763a2eb4fba21e0de4ee..2ded723f25587488149b5470830f2b593cb964df 100644 (file)
@@ -149,6 +149,10 @@ Misc
     force loading kernel module <drivername> after all automatic loading modules
     have been loaded. This parameter can be specified multiple times.
 
+**rd.driver.export**::
+    making all drivers from initramfs available to rootfs after switch_root.
+    This parameter can be set to 'force' for exporting over existing modules.
+
 **rd.retry=**__<seconds>__::
     specify how long dracut should retry the initqueue to configure devices.
     The default is 180 seconds. After 2/3 of the time, degraded raids are force
diff --git a/modules.d/70kernel-modules-export/module-setup.sh b/modules.d/70kernel-modules-export/module-setup.sh
new file mode 100755 (executable)
index 0000000..da5259a
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+check() {
+    return 255
+}
+
+depends() {
+    echo base
+}
+
+install() {
+    inst_hook pre-pivot 90 "$moddir/modules-export.sh"
+}
diff --git a/modules.d/70kernel-modules-export/modules-export.sh b/modules.d/70kernel-modules-export/modules-export.sh
new file mode 100755 (executable)
index 0000000..71494a3
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+command -v getarg > /dev/null || . /lib/dracut-lib.sh
+
+if ! getargbool 0 rd.driver.export; then
+    exit 0
+fi
+
+driver_export=$(getarg rd.driver.export=)
+
+KVERSION="$(uname -r)"
+
+if [ ! -d "/lib/modules/$KVERSION" ]; then
+    warn "Something odd, no /lib/modules/$KVERSION in initramfs."
+    exit 0
+fi
+
+[ -d "$NEWROOT/lib/modules" ] || mkdir -p "$NEWROOT/lib/modules" \
+    || {
+        warn "No /lib/modules in target. cannot help."
+        exit 0
+    }
+
+if [ -d "$NEWROOT/lib/modules/$KVERSION" ]; then
+    if [ "${driver_export#*force}" = "$driver_export" ]; then
+        warn "/lib/modules/$KVERSION exists. To export modules set rd.driver.export=force!"
+        exit 0
+    else
+        info "Due to rd.driver.export=force exporting over existing modules!"
+    fi
+fi
+
+mount -t tmpfs driver_export "$NEWROOT/lib/modules" \
+    || {
+        warn "Failed mount of tmpfs."
+        exit 0
+    }
+
+cp -a "/lib/modules/$KVERSION" "$NEWROOT/lib/modules" \
+    || {
+        warn "Failed to export modules to target root."
+        exit 0
+    }
diff --git a/test/TEST-44-DRIVERS/Makefile b/test/TEST-44-DRIVERS/Makefile
new file mode 100644 (file)
index 0000000..2dcab81
--- /dev/null
@@ -0,0 +1 @@
+-include ../Makefile.testdir
diff --git a/test/TEST-44-DRIVERS/create-root.sh b/test/TEST-44-DRIVERS/create-root.sh
new file mode 100755 (executable)
index 0000000..49cc94d
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+trap 'poweroff -f' EXIT
+set -e
+
+mkfs.ext4 -q -L dracut /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_root
+mkdir -p /root
+mount -t ext4 /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_root /root
+cp -a -t /root /source/*
+mkdir -p /root/run
+umount /root
+mkfs.xfs -q /dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_mnt
+echo "dracut-root-block-created" | dd oflag=direct,dsync of=/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_marker status=none
+poweroff -f
diff --git a/test/TEST-44-DRIVERS/test.sh b/test/TEST-44-DRIVERS/test.sh
new file mode 100755 (executable)
index 0000000..016be56
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/env bash
+set -eu
+# shellcheck disable=SC2034
+TEST_DESCRIPTION="no (xfs) driver on root filesystem"
+
+test_check() {
+    if ! type -p mkfs.xfs &> /dev/null; then
+        echo "Test needs mkfs.xfs.. Skipping"
+        return 1
+    fi
+
+    if ! command -v systemctl > /dev/null; then
+        echo "This test needs systemd to run."
+        return 1
+    fi
+}
+
+# Uncomment this to debug failures
+#DEBUGFAIL="rd.shell=1 rd.break=pre-mount"
+test_run() {
+    declare -a disk_args=()
+    declare -i disk_index=0
+    qemu_add_drive disk_index disk_args "$TESTDIR"/marker.img marker
+    qemu_add_drive disk_index disk_args "$TESTDIR"/root.img root
+    qemu_add_drive disk_index disk_args "$TESTDIR"/mnt.img mnt
+
+    test_marker_reset
+
+    # This test should fail if rd.driver.export is not passed at kernel command-line
+    "$testdir"/run-qemu \
+        "${disk_args[@]}" \
+        -append "$TEST_KERNEL_CMDLINE rd.driver.export" \
+        -initrd "$TESTDIR"/initramfs.testing
+
+    test_marker_check
+}
+
+test_setup() {
+    # Create what will eventually be our root filesystem onto an overlay
+    call_dracut --tmpdir "$TESTDIR" \
+        --no-kernel \
+        --add "systemd-udevd systemd-journald systemd-tmpfiles systemd-ldconfig systemd-ask-password shutdown" \
+        --mount "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_mnt /mnt xfs rw" \
+        --add-confdir test-root \
+        -f "$TESTDIR"/initramfs.root
+    mkdir -p "$TESTDIR"/overlay/source
+    mv "$TESTDIR"/dracut.*/initramfs/* "$TESTDIR"/overlay/source
+    rm -rf "$TESTDIR"/dracut.*
+
+    # make sure no linux kernel driver is included in the rootfs
+    rm -rf "$TESTDIR"/overlay/source/lib/modules/*
+
+    # make sure /lib/modules directory exists inside the rootfs
+    mkdir -p "$TESTDIR"/overlay/source/lib/modules "$TESTDIR"/overlay/source/mnt
+
+    # create an initramfs that will create the target root filesystem.
+    # We do it this way so that we do not risk trashing the host mdraid
+    # devices, volume groups, encrypted partitions, etc.
+    call_dracut -i "$TESTDIR"/overlay / \
+        --add-confdir "test-makeroot" \
+        -I "mkfs.xfs" \
+        -i ./create-root.sh /lib/dracut/hooks/initqueue/01-create-root.sh \
+        -f "$TESTDIR"/initramfs.makeroot
+
+    declare -a disk_args=()
+    # shellcheck disable=SC2034  # disk_index used in qemu_add_drive
+    declare -i disk_index=0
+    qemu_add_drive disk_index disk_args "$TESTDIR"/marker.img marker 1
+    qemu_add_drive disk_index disk_args "$TESTDIR"/root.img root 1
+    qemu_add_drive disk_index disk_args "$TESTDIR"/mnt.img mnt 1
+
+    # Invoke KVM and/or QEMU to actually create the target filesystem.
+    "$testdir"/run-qemu \
+        "${disk_args[@]}" \
+        -append "root=/dev/fakeroot quiet console=ttyS0,115200n81" \
+        -initrd "$TESTDIR"/initramfs.makeroot
+    test_marker_check dracut-root-block-created
+    rm -- "$TESTDIR"/marker.img
+
+    test_dracut \
+        --add-drivers xfs \
+        --add kernel-modules-export
+}
+
+# shellcheck disable=SC1090
+. "$testdir"/test-functions