web-dev-qa-db-ja.com

udevフックなしで最小限のinitramfsでルートbtrfsファイルシステムを起動する方法は?

Arch Linuxは、GPTと3つのパーティションを備えたUSBフラッシュドライブからブートされたUEFIです。

  1. EFI(vfatファイルシステム)
  2. ルート(btrfsファイルシステム、ext4から変換されました)
  3. ホーム(btrfsファイルシステム、ext4から変換されました)

Btrfsパーティションにはサブボリュームがなく、単一のディスク(USBフラッシュメモリドライブ)にあります。

仕事

Udevや他の多くのフックを削除して、 minimal initramfs を作成しようとしています。 mkinitcpioを使用したブートアップの最適化 もインスピレーションとして使用されました。
有効なmkinitcpioフックは次のとおりです: baseautodetect および modconf

Btrfsフック

mkinitcpio hooks documentation btrfsフックのリストであるため、btrfsフックは有効になっていません:

このフックは、単一のデバイスで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フックを挿入した後でのみ、システムは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.

ランタイムinitデバッグ/ログ出力

ブートパラメータrd.debugおよびrd.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コマンド

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

緊急シェルのblkidコマンドは、正しい(PART)UUID値をリストします。 /dev/disk/がないため、(PART)UUIDを使用したマウントが失敗する可能性がありますか?

質問

UdevなしでUSBフラッシュドライブにある非RAIDの非サブボリュームのシングルドライブルートbtrfsパーティションを起動するには何が必要ですか?


PSこのエラーは、initramfs/initmount ... UUID=...コマンドを実行したときにUUID/PARTUUIDがまだ使用できないというRACE状態が原因である可能性があります。

3
Pro Backup

原因

バージョン23では、 mkinitcpio resolve_device()関数 は1回だけ呼び出されます。実行時にドライブラベルがまだ読み取られていない場合、 blkid は、要求されたラベルのカーネルドライブ(/dev/...)名を検索できません。

解決

以下に示すように、「without-udev」フックを追加することにより、resolve_device関数は変更されません。標準で利用可能なmkinitcpio機能が mount_handlerをオーバーライドするadd run_hookを使用して、blkidが値を返すか、(タイムアウト)10秒が経過するまでポーリングします。したがって、「udev」フックはmkinitcpioconfigから削除できます。

ノート

  • このソリューションは、falconindyの助けを借りて作成されました。
  • Fsckに関連する初期ブートフェーズでエラーメッセージがありました。そのメッセージを削除するために、without-udevフックがrun_hookを使用するように書き直されました。 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:
2
Pro Backup