Arch-Linux

如何在沒有 udev 掛鉤的情況下使用最少的 initramfs 引導到根 btrfs 文件系統?

  • March 9, 2021

Arch Linux 是從帶有 GPT 和三個分區的 USB 快閃記憶體驅動器啟動的 UEFI:

  1. EFI(vfat 文件系統)
  2. root(btrfs 文件系統,由 ext4 轉換而來)
  3. home(btrfs 文件系統,由 ext4 轉換而來)

btrfs 分區沒有子卷並且位於單個磁碟(USB 快閃記憶體驅動器)上。此處未使用 LVM。

任務

嘗試通過刪除 udev 和許多其他鉤子來創建最小的 initramfs 。使用 mkinitcpio 優化啟動也被用作靈感。

有效的mkinitcpio鉤子是:baseautodetectmodconf

Btrfs 鉤子

btrfs 鉤子未啟用,因為 btrfs 鉤子的mkinitcpio鉤子文件列表:

在單個設備上使用 Btrfs 不需要此掛鉤。

回歸

  1. 我試圖刪除 udev -> 啟動錯誤
  2. 我試圖添加 btrfs 模組 -> 啟動錯誤
  3. 我添加了 btrfs 掛鉤 -> 啟動錯誤
  4. 將 root=PARTUUID= 更改為 root=UUID= 表示法 -> 引導錯誤
  5. 添加參數 rootfstype=btrfs -> 啟動錯誤
  6. rootdelay=0 -> 啟動錯誤
  7. rootdelay=10 -> 啟動錯誤
  8. 從緊急外殼使用 /dev/sda2 掛載 -> ok

錯誤

只有插入udev或systemd hooks後系統才會root到btrfs根分區,否則會出現這個錯誤:

ERROR: device 'PARTUUID=c2...c13' not found. Skipping fsck.
:: mounting 'PARTUUID=c2...c13' on real root 
mount: can't find 'PARTUUID=c2...c13'
You are now being dropped into an emergency shell.

執行時初始化調試/日誌輸出

啟用引導參數rd.debugrd.log顯示“premount”呼叫resolve_device函式並返回空查找。

resolve_device PARTUUID=c2...c13
local major minor dev tag device=PARTUUID=c2...c13
blkid -lt PARTUUID=c2...c13 -o device
dev=

最後一個空開發導致設備未找到錯誤。

initramfs 掛載命令

mount_handler=default_mount_handler
...
# Mount root at /new_root
"$mount_handler" /new_root

來源:https ://git.archlinux.org/mkinitcpio.git/tree/init

default_mount_handler() {
   msg ":: mounting '$root' on real root"
   mount ${rootfstype:+-t $rootfstype} -o ${rwopt:-ro}${rootflags:+,$rootflags} "$root" "$1"

來源:https ://git.archlinux.org/mkinitcpio.git/tree/init_functions#n375

initramfs 掛載版本

[rootfs ]# mount -V
mount from util-linux 2.29.2 (libmount 2.29.2: btrfs, assert, debug)

initramfs 內容

$ lsinitcpio -a /boot/initramfs-linux-tiny.img
==> Image: /boot/initramfs-linux-tiny.img
==> Created with mkinitcpio 23
==> Kernel: 4.10.3-1-ARCH
==> Size: 3.53 MiB
==> Compressed with: lz4 -l
 -> Uncompressed size: 8.32 MiB (.424 ratio)
 -> Estimated extraction time: 0.028s

==> Included modules:
 ahci [explicit]         hid-generic [explicit]      raid6_pq            usbcore
 atkbd [explicit]        i8042 [explicit]        scsi_mod            usbhid [explicit]
 btrfs [explicit]        libahci             sd_mod [explicit]       xhci-hcd
 crc32c-intel [explicit]     libata              serio               xhci-pci [explicit]
 crc32c_generic          libcrc32c           serio_raw [explicit]        xor
 ehci-hcd            libps2              uas [explicit]
 ehci-pci [explicit]         ohci-hcd            usb-common
 hid                 ohci-pci [explicit]         usb-storage

==> Included binaries:
 blkid       busybox     dosfsck     fsck        fsck.vfat   kmod        mount       switch_root

緊急 shell 的blkid命令列出了正確的 (PART)UUID 值。使用 (PART)UUID 安裝會失敗,因為沒有/dev/disk/

問題

在沒有 udev 的情況下引導到位於 USB 快閃記憶體驅動器上的非 RAID 非子卷單驅動器根 btrfs 分區需要什麼?


initramfs/initPS 此錯誤可能是由 RACE 條件引起的,執行mount ... UUID=...命令時 UUID/PARTUUID 尚不可用。

原因

在版本 23 中,mkinitcpio resolve_device() 函式只被呼叫一次。在執行時尚未讀取驅動器標籤時,無法為請求的標籤blkid查找核心驅動器 ( ) 名稱。/dev/...

解決方案

通過添加“without-udev”鉤子,如下所示,resolve_device 函式保持不變。儘管覆蓋 mount_handler 的標準可用 mkinitcpio 功能添加了一個 run_hook用於輪詢,直到blkid返回一個值,或者(超時)10 秒過去。因此“udev”鉤子可以從 mkinitcpio 配置中刪除。

筆記

  • *這個解決方案是在falconindy*的幫助下創建的。
  • 在涉及 fsck 的早期引導階段出現錯誤消息。要刪除該消息,無 udev 掛鉤已被重寫為使用 arun_hook而不是 a mount_handler。較新的程式碼甚至更短。

$ cat /usr/lib/initcpio/hooks/without-udev
#!/bin/ash
# Minimal initramfs files are created without udev.
# This hooks provides a polling disk mount replacement for udev.
# Udev hook can be removed, resulting in smaller initramfs files.

run_hook () {
   local dev timeout sleepval device=$root
   # if udev is running then exit
   [ "$udevd_running" -eq 1 ] && return
   # try for (timeout * sleepval =) 10 seconds to handle slow (USB) devices
   timeout=1000
   sleepval=0.01

   case $device in
       # label to resolve, when resolved the kernel block device also exists
       UUID=*|LABEL=*|PARTUUID=*|PARTLABEL=*)
           while [ $timeout -gt 0 ]; do
               timeout=$((timeout - 1))
               dev=$(blkid -lt "$device" -o device)
               [ -n "$dev" ] && timeout=0 || sleep $sleepval
           done
           ;;
       # kernel named block device, poll for existence
       /dev/*)
           while [ $timeout -gt 0 ]; do
               timeout=$((timeout -1))
               if [ -b "$device" ]; then
                   dev=$device
                   timeout=0
               else
                   sleep $sleepval
               fi
           done
           ;;
   esac
}

# vim:set syntax=sh:

$ cat /usr/lib/initcpio/install/without-udev
#!/bin/bash

build() {
   add_runscript
}

help() {
   cat <<HELPEOF
This hook provides support for booting without the "udev" hook,
including support for UUID, LABEL, PARTUUID, PARTLABEL.
HELPEOF
}

# vim: set ft=sh ts=4 sw=4 et:

引用自:https://unix.stackexchange.com/questions/352381