]> git.ipfire.org Git - thirdparty/dracut.git/commitdiff
fix(dracut-functions.sh): get block device driver if in a virtual subsystem
authorAntonio Alvarez Feijoo <antonio.feijoo@suse.com>
Wed, 10 Nov 2021 09:19:14 +0000 (10:19 +0100)
committerHarald Hoyer <harald@hoyer.xyz>
Wed, 24 Nov 2021 10:15:25 +0000 (11:15 +0100)
dracut does not install the kernel module of the block device that contains
the root filesystem if the following preconditions are met:
- Running in host-only mode.
- Symlinks of all block devices needed to boot the system pointing to virtual
subsystems.

The get_dev_module function uses "udevadm info -a" to get the corresponding
kernel modules of a /sys/class/*/* or /dev/* device. This function is called
in modules.d/90kernel-modules/module-setup.sh to detect if dracut must install
block device drivers in host-only mode. The symlinks in /sys/dev/block/
usually point to "real" devices in /sys/devices/pci*. But, we have come across
some NVMe systems where the kernel creates the symlinks in /sys/dev/block/
pointing to "virtual" devices instead. In this case, udevadm never finds any
"driver" attributes following up the chain of parent devices.

dracut-functions.sh

index 32177994822e8e13fa421adbd4683d1c8ae81185..63b6c892d433475772679966e987c86455449f4a 100755 (executable)
@@ -945,5 +945,29 @@ block_is_netdevice() {
 
 # get the corresponding kernel modules of a /sys/class/*/* or/dev/* device
 get_dev_module() {
-    udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p'
+    local dev_attr_walk
+    local dev_drivers
+    dev_attr_walk=$(udevadm info -a "$1")
+    dev_drivers=$(echo "$dev_attr_walk" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p')
+    # if no kernel modules found and device is in a virtual subsystem, follow symlinks
+    if [[ -z $dev_drivers && $(udevadm info -q path "$1") == "/devices/virtual"* ]]; then
+        local dev_vkernel
+        local dev_vsubsystem
+        local dev_vpath
+        dev_vkernel=$(echo "$dev_attr_walk" | sed -n 's/\s*KERNELS=="\(\S\+\)"/\1/p' | tail -1)
+        dev_vsubsystem=$(echo "$dev_attr_walk" | sed -n 's/\s*SUBSYSTEMS=="\(\S\+\)"/\1/p' | tail -1)
+        dev_vpath="/sys/devices/virtual/$dev_vsubsystem/$dev_vkernel"
+        if [[ -n $dev_vkernel && -n $dev_vsubsystem && -d $dev_vpath ]]; then
+            local dev_links
+            local dev_link
+            dev_links=$(find "$dev_vpath" -maxdepth 1 -type l ! -name "subsystem" -exec readlink {} \;)
+            for dev_link in $dev_links; do
+                [[ -n $dev_drivers && ${dev_drivers: -1} != $'\n' ]] && dev_drivers+=$'\n'
+                dev_drivers+=$(udevadm info -a "$dev_vpath/$dev_link" \
+                    | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p' \
+                    | grep -v -e pcieport)
+            done
+        fi
+    fi
+    echo "$dev_drivers"
 }