mkinitcpio/最小 initramfs

出自 ArchWiki
(重定向自 Minimal initramfs

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

Udev 要求

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

此外,虽然大多数键盘(AT、PS/2、USB)不需要使用 udev hook,但使用 Logitech Unified Receiver 的 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 的方式构建。如果出现问题,您可以依赖 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 是被 sourced 的,因此您可以像在 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

存储设备模块

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

键盘模块

  • atkbd 用于 AT 和 PS/2 键盘,以及 QEMU/KVM 中的模拟键盘。
  • hid_genericohci_pciusbhid 用于普通 USB 键盘。
  • hid_logitech_djuhci_hcdusbhid 用于使用 Logitech Unified Receiver 的 Logitech USB 键盘(需要 udev hook)。

完成

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