本文介绍如何为具有特定、已知和静态硬件配置的系统创建精简、最小的 initramfs。 Falconindy (Dave Reisner) 的 Optimizing Bootup With mkinitcpio 详细阐述了该过程。
Udev 要求
创建自己的 initramfs 映像的一大优点是可以移除 udev
钩子。这个钩子在 initramfs 中占了相当大一块空间(使用 LZ4 和 LZOP 压缩时约为 700-800 KiB,其他算法较小)。因此它不仅导致启动时加载耗时更长(需要解压更多的数据),而且初始化其自身时也要额外的时间。但是,仍有部分操作需要 udev
,包括解析 UUID、LABEL、PARTUUID 和 PARTLABEL 标识符(workaround hook without-udev)以及包含 root
分区的 LVM 和 mdadm 设备。
若您不确定是否需要 udev
,请继续按照本页上的说明操作,直到 #初步测试章节。如果在没有 udev
的时候出了问题,请重新启用此钩子,再试一次。
另请注意,虽然大部分键盘(AT,PS/2,USB)不需要 udev
钩子也能正常工作,但使用罗技统一接收器(Logitech Unified Receiver)的 USB 设备需要。此时,您可以在所有映像中包含 udev
或依赖 fallback
映像正常工作。
如果您确实需要 udev
,最小化映像的努力可能就白费了。映像大小也许能减小约 600 KiB,但是启动时间不会有显著改变。在此情况继续下去,不失为一次学习机会。
编辑 .preset 文件
在 Falconidy 的教程中,他编辑 /etc/mkinitcpio.conf
并运行 mkinitcpio -g
来创建测试 initramfs 映像,使系统上已知正常启动的 initramfs 映像保持不变。 但是,如果您事后盲目运行 mkinitcpio -P
,甚至 fallback
映像也会被删除。
准备自行创建 initramfs 的更安全方法是修改 /etc/mkinitcpio.d
中的 .preset
文件。以下的示例设定将以最小的 initramfs 映像取代default
,并依照 The Arch Way 的方式建立一个新的正常映像文件。 如果出现问题,您仍可以使用 normal
或 fallback
映像。 完成后,您可以从配置中删除 normal_*
行并删除 initramfs-linux*-normal.img
文件。
... PRESETS=('default' 'normal' 'fallback') ... default_options="-S udev,block,mdadm_udev,filesystems,keyboard,fsck,consolefont" ... #normal_config="/etc/mkinitcpio.conf" normal_image="/boot/initramfs-linux-normal.img" #normal_options="" ...
mdadm_udev
和 consolefont
钩子不在 Arch Linux 默认的配置中,在 *_options
行的 -S
参数中包含无关的钩子不会导致错误。
找出需要的模块
找出机器需要的模块的最快方法是重启电脑,使用 fallback
映像并通过引导加载程序(boot loader)添加 break=postmount
内核参数。于是在根文件系统挂载好后便可进入命令行界面。
重启电脑后,通过以下命令来获取需要的模块:
lsmod | awk 'NF==3{print $1}'
awk
命令会返回每一行的第一个字段(使用 {print $1
),但只限于那些刚好有三个字段的行,这是通过 NF==3
来强制筛选的。
模块依赖关系会包含第四个字段,用来显示是由哪个模块引入这个依赖,因此这些行会因为有第四个字段而被过滤掉。Arch 的 mkinitcpio
会处理那些正当包含在 MODULES=()
、FILES=()
和 BINARIES=()
数组中的依赖项目。保存已加载模块的清单,输入 exit
继续启动机器。
另一种方式是安装 hwdetect包 来帮助确定所需的模块。虽然此软件包已停止维护,它仍可提供有价值的信息。另外,请参阅内核模块以开始使用本机工具。
初步编辑 mkinitcpio.conf
编辑 /etc/mkinitcpio.conf
修改 MODULES=
数组。值得注意 /etc/mkinitcpio.conf
作为脚本调用,可以使用 bash 脚本构建 MODULES 数组。
MODULES=() # filesystems MODULES+=() # storage MODULES+=() # keyboard MODULES+=() # miscellaneous
把模块添加到配置中最后的 miscellaneous
行中,整理时再将模块移至合适的行去。
若需要对 root
分区设备和在 /etc/fstab
的任何其他挂载点进行文件系统检查操作,请按下文配置:
- 对于 ext[2|3|4] 设备:
BINARIES=(fsck fsck.ext[2|3|4] e2fsck)
- 对于 vfat (UEFI boot) 设备:
BINARIES=(fsck fsck.vfat dosfsck)
- 对于 btrfs 单盘设备:
BINARIES=(fsck fsck.btrfs btrfsck)
- 对于 btrfs 多盘设备:
BINARIES=(fsck fsck.btrfs btrfs btrfsck)
- 对于 xfs 设备:
BINARIES=(fsck fsck.xfs xfs_repair)
- 上述示例中的第三个选项都是可选的,但除去它们将导致无法修复损坏的文件系统,此时需要从另一个 initramfs 启动。
- 鼓励添加其他文件系统的条目。
初步测试
编辑 /etc/mkinitcpio.conf
并运行 mkinitcpio -P
重建所有 initramfs 镜像。 然后重启。
如果不需要 udev
,第一次启动应该会成功。 如果出现故障(例如,Arch 找不到根分区或键盘失灵),则需要返回并从default_options
行的-S
参数中删除udev
,然后再试一次。 如果需要使用 udev
,请注意启动时间不会有明显改善,继续尝试只能作为学习经验。
整理模块
现在您已经有了一个已知正常的可启动 initramfs,是时候进一步精简 initramfs 了。通常是一次删除几个模块,重建 initramfs 映像,然后重新启动以查看一切是否仍然正常。若有功能异常,请使用 fallback
initramfs 映像重启并重新添加已删除的模块,直到再次恢复正常。多次重复,直到只剩下所需的模块。
这可能是相对乏味的过程,因此提供了以下列表,以便减少前期工作。
文件系统模块
root
设备和在 /etc/fstab
中的其他设备ext[2,3,4]
xfs
jfs
reiserfs
存储设备模块
-
sd_mod
用于所有 SCSI、SATA 和 PATA(IDE)设备 -
ahci
用于现代 AHCI 控制器上的 SATA 设备 -
nvme
和nvme_core
用于 NVMe(M.2、PCI-E)设备 -
sata_*
用于 IDE 模式控制器上的 SATA 设备 -
pata_*
用于 PATA(IDE)设备 -
ehci_pci
和usb_storage
用于 USB 存储设备 -
virtio_blk
和virtio_pci
用于使用 VirtIO 进行存储的 QEMU/KVM 虚拟机
键盘模块
-
atkbd
用于 AT 和 PS/2 键盘,以及 QEMU/KVM 中的模拟键盘。 -
hid_generic
、ohci_pci
和usbhid
用于普通 USB 键盘。 -
hid_logitech_dj
、uhci_hcd
和usbhid
适用于使用罗技统一接收器的罗技 USB 键盘(需要 {ic|udev}} 钩子)。
收尾工作
将 initramfs 压缩到最小后,移除(或注释掉).preset
文件中的 normal_*
行,并移除 /boot
中的 initramfs-linux*-normal.img
文件。