Arch Linux is UEFI booted from USB flash drive with GPT and three partitions:
- EFI (vfat file system)
- root (btrfs file system, was converted from ext4)
- home (btrfs file system, was converted from ext4)
The btrfs partitions have no sub-volumes and are on a single disk (the USB flash memory drive). LVM is not in use here.
Task
Trying to create a minimal initramfs by removing udev and a lot of other hooks. Optimizing Bootup With mkinitcpio was used as inspiration too.
The effective mkinitcpio
hooks are: base, autodetect and modconf.
Btrfs hook
The btrfs hook is not enabled because mkinitcpio
hooks documentation lists for btrfs hook:
This hook is not required for using Btrfs on a single device.
Regression
- I have tried to remove udev -> boot error
- I have tried to add the btrfs module -> boot error
- I have added btrfs hook -> boot error
- Changed root=PARTUUID= to root=UUID= notation -> boot error
- adding paramters rootfstype=btrfs -> boot error
- rootdelay=0 -> boot error
- rootdelay=10 -> boot error
- Mounting using /dev/sda2 from emergency shell -> ok
Error
Only after inserting udev or systemd hooks the system will root into the btrfs root partition, otherwise this error appears:
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.
Runtime init debug/log output
Enabling boot parameters rd.debug
and rd.log
shows that "premount" calls the resolve_device function and that returns an empty lookup.
resolve_device PARTUUID=c2...c13
local major minor dev tag device=PARTUUID=c2...c13
blkid -lt PARTUUID=c2...c13 -o device
dev=
The last empty dev is causing the device not found error.
initramfs mount command
mount_handler=default_mount_handler
...
# Mount root at /new_root
"$mount_handler" /new_root
source: 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ドル"
source: https://git.archlinux.org/mkinitcpio.git/tree/init_functions#n375
initramfs mount version
[rootfs ]# mount -V
mount from util-linux 2.29.2 (libmount 2.29.2: btrfs, assert, debug)
initramfs contents
$ 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
The emergency shell its blkid
command lists the correct (PART)UUID value. Could the mounting using using (PART)UUID fail because there is no /dev/disk/
?
Question
What is necessary to boot into a non-raid non-subvolume single-drive root btrfs partition located on a USB flash drive without udev?
PS This error might be caused by a RACE condition, UUID/PARTUUID not yet available when initramfs/init
executes the mount ... UUID=...
command.
1 Answer 1
Cause
In version 23, the mkinitcpio resolve_device() function is called only once. When at execution time the drive labels are not yet read, blkid
can't lookup the kernel drive (/dev/...
) name for the requested label.
Solution
By adding the "without-udev" hook, as listed below, the resolve_device function is left untouched. Though standard available mkinitcpio functionality to (削除) override the mount_handler (削除ここまで) add a run_hook is used to poll until blkid
returns a value, or (a timeout of) 10 seconds has passed. Thus the "udev" hook can be removed from mkinitcpio config.
Notes
- This solution was created with the help of falconindy .
- There was an error message in the early boot phase involving fsck. To remove that message the without-udev hook has been rewritten to use a
run_hook
instead of a(削除). The newer code is even shorter.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:
-
Should I be getting
ERROR: Device 'PARTUUID:XXXX..' not found. Skipping fsck.
with this workaround? I boot fine, but that error gets listed.ZeroPhase– ZeroPhase2017年05月01日 13:02:02 +00:00Commented May 1, 2017 at 13:02 -
@ZeroPhase I my initcpio-without-udev setup, I do indeed also get the message
ERROR: Device 'PARTUUID:XXXX..' not found. Skipping fsck.
during boot.Pro Backup– Pro Backup2017年05月10日 19:20:51 +00:00Commented May 10, 2017 at 19:20 -
That's not going to cause issues with fsck?ZeroPhase– ZeroPhase2017年05月10日 22:23:39 +00:00Commented May 10, 2017 at 22:23
-
@ZeroPhase I don't think that ERROR: Device PARTUUID message will cause issues with fsck. A little later in code fsck is done again on /dev/sd(a). That is the line prepended with the comment:
# call fsck again because in main loop $root device was unknown at that time
.Pro Backup– Pro Backup2017年05月11日 11:14:29 +00:00Commented May 11, 2017 at 11:14 -
2@ZeroPhase The without-udev hook code has been updated to no longer output the
ERROR: Device 'PARTUUID:XXXX..' not found. Skipping fsck.
message. As a side effect the code is even shorter.Pro Backup– Pro Backup2017年05月11日 17:21:32 +00:00Commented May 11, 2017 at 17:21