mkinitcpio/最小 initramfs

出自 ArchWiki

本文展示了如何为一个具有特定、已知和静态硬件配置的系统创建一个精简的、最小的 initramfs。此过程从 Falconindy (Dave Reisner) 的 使用 mkinitcpio 优化启动 一文中详细阐述。

Udev 要求

创建您自己的 initramfs 镜像的主要优势是可以消除 udev。仅此 hook 就占用了 initramfs 镜像相当大的大小(使用 LZ4 和 LZOP 约为 700-800 KiB,使用其他算法则更少)。更大的尺寸不仅会导致更长的启动时间(更多数据需要解压缩),而且初始化 udev 本身也需要额外的时间。然而,有些东西需要 udev。这包括解析 UUID、LABEL、PARTUUID 和 PARTLABEL 标识符(不使用 udev 的 workaround hook)以及包含 root 分区的 LVM 和 mdadm 设备的组装。如果您不确定是否需要 udev,请继续按照此页面上的说明操作,直到 #初始测试。如果未启用 udev 时并非所有功能都正常工作,请重新启用 hook 并重试。

此外,虽然大多数键盘(AT、PS/2、USB)不需要使用 udev hook,但使用 Logitech 优联接收器的 Logitech USB 设备则需要。此时,您可以选择在所有镜像中包含 udev,或者依赖于包含 udevfallback 镜像。

如果您需要 udev,那么您的最小化努力很可能将是徒劳的。您可能仍然能够将镜像大小缩小约 600 KiB,但启动时间不会得到显着改善。在这种情况下继续下去仍然可能是一次有价值的学习经历。

编辑 .preset 文件

在 Falconidy 的教程中,他编辑了 /etc/mkinitcpio.conf 并运行 mkinitcpio -g 来创建测试 initramfs 镜像,使系统上已知的良好 initramfs 镜像保持不变。但是,如果您之后盲目运行 mkinitcpio -P,即使是 fallback 镜像也会被精简。

一种更安全的方式来准备自己手动创建 initramfs 文件,是修改 /etc/mkinitcpio.d 中的 .preset 文件。以下示例配置将用最小的 initramfs 镜像取代 default,并创建一个新的 normal 镜像,该镜像以 Arch Way 构建。如果出现问题,您可以依赖 normalfallback 镜像。完成后,您可以从配置中删除 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_udevconsolefont hooks 不存在于默认的 Arch 配置中。在 *_options 行的 -S 参数中包含无关的 hooks 不会导致错误。

查找需要的模块

找出您需要哪些模块的最快方法是使用 fallback initramfs 镜像重启系统,并在启动加载程序的内核参数中添加 break=postmount,以便在根文件系统挂载后进入命令行。

系统重启后,运行以下命令以查看您需要的模块

lsmod | awk 'NF==3{print $1}'
注意: awk 命令仅返回每行正好有 3 个字段的第一字段,使用 {print $1} ,由 NF==3 强制执行。模块依赖项包括第 4 个字段以显示哪个模块引入了依赖项,因此由于第 4 个字段而被过滤掉。Arch 的 mkinitcpio 会处理数组 MODULES=()FILES=()BINARIES=() 中包含的合法值的依赖项。

写下已加载的模块,然后键入 exit 以继续启动。

或者,安装 软件包 hwdetect 以帮助确定必要的模块。虽然已不再维护,但它可以提供有价值的信息。另请参阅 内核模块 以开始使用原生工具。

mkinitcpio.conf 的初始编辑

编辑 /etc/mkinitcpio.conf 并修改 MODULES= 数组。值得注意的是,/etc/mkinitcpio.conf 是被 sourcing 的,因此您可以像在 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 启动) 分区
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

存储设备模块

  • 所有 SCSI、SATA 和 PATA (IDE) 设备的 sd_mod
  • 现代 AHCI 控制器上 SATA 设备的 ahci
  • NVMe (M.2, PCI-E) 设备的 nvmenvme_core
  • IDE 模式控制器上 SATA 设备的 sata_*
  • PATA (IDE) 设备的 pata_*
  • USB 存储设备的 ehci_pciusb_storage
  • 使用 VirtIO 进行存储的 QEMU/KVM VM 的 virtio_blkvirtio_pci

键盘模块

  • AT 和 PS/2 键盘以及 QEMU/KVM 中模拟键盘的 atkbd
  • 普通 USB 键盘的 hid_genericohci_pciusbhid
  • 使用 Logitech 优联接收器的 Logitech USB 键盘的 hid_logitech_djuhci_hcdusbhid需要 udev hook)。

完成

一旦您尽可能精简了 initramfs,请从 .preset 文件中删除(或注释掉)normal_* 行,并从 /boot 中删除 initramfs-linux*-normal.img 文件。