「initramfs」- Initial RAM File System

认识

initramfs,Initial RAM File System,是 initrd(Initial Ramdisk)的接替者,since Kernel 2.5.46(自 Linux 2.6.13 起可用)。

initramfs,其本质上是个经过压缩(可选多种压缩之一)的 `cpio` 归档文件,保存在 /boot/ 中,通常会被命名为 `initrd.img-<kernel-version>` 或类似的名字。

initramfs 是个临时的根文件系统,它在 Linux 内核启动后、真正的根文件系统被挂载之前被加载到内存中使用。它的主要任务是准备好必要的环境,以便能够成功挂载真正的根文件系统。若无 initramfs 的存在,我们的 Linux 系统将无法从加密硬盘、LVM 或网络存储上启动,将极大地限制其灵活性和安全性。

Linux Kernel 将 initramfs 解压到特殊的 tmpfs 实例中,该实例成为初始 root 文件系统。

BLFS / About initramfs / http://www.linuxfromscratch.org/blfs/view/svn/postlfs/initramfs.html

组成

该镜像包含初始文件系统,其中包含在启动时所有必要资源(例如,硬件的内核模块、初始化脚本、块驱动、……)。该微型文件系统里通常包含以下内容:

必要的工具(Tools)

实用程序:busybox,其集成上百个常用 Linux 命令(如 `ls`, `mount`, `echo`, `insmod`)的单一可执行文件,非常节省空间。

特定工具:如 `cryptsetup`(用于解密)、`lvm`(用于管理 LVM)、`mdadm`(用于管理软 RAID)等。

内核模块(Kernel Modules)

存储控制器驱动、文件系统驱动(如 `ext4`, `xfs`, `btrfs`)、加密模块等。这些模块不是编译进内核,而是以可加载模块(`.ko` 文件)的形式存在。

初始化脚本(Init Script)

一个名为 `/init` 的脚本(有时是二进制文件),它是 initramfs 启动后执行的第一个进程(PID 1)。这个脚本负责协调所有启动任务。

设备节点(Device Nodes)

例如 `/dev/null`, `/dev/console`, `/dev/sda1` 等,用于与硬件交互。

工作流程

整个启动过程中,initramfs 的生命周期如下:

  1. BIOS/UEFI:执行硬件自检,并加载引导程序(如 GRUB)。
  2. Bootloader (GRUB):根据配置文件,将 Linux 内核和 initramfs 镜像加载到内存中,然后将控制权交给内核。
  3. Linux 内核:
    • 内核解压并执行。
    • 它在内存中找到一个空闲区域,将 initramfs 解压到那里,并将其挂载为临时的根文件系统。
    • 内核最后执行这个临时根文件系统中的 `/init` 脚本。
  4. /init 脚本:
    • 这个脚本开始工作,它的任务通常按顺序包括:
      1. 加载内核模块:加载访问真实根文件系统所在磁盘所需的驱动(如 NVMe、SATA 控制器驱动)。
      2. 提供解密接口:如果根文件系统被加密,脚本会暂停启动,并提示用户输入密码或读取密钥文件。使用 `cryptsetup` 工具解密映射设备。
      3. 激活逻辑卷:如果使用了 LVM,则使用 `vgchange` 等命令激活卷组。
      4. 识别设备:使用 `udev` 规则在 `/dev` 目录下创建正确的设备节点(如 `/dev/mapper/vg0-root`)。
  5. 切换根文件系统(Pivot Root):
    • `/init` 脚本使用 `pivot_root` 系统调用,将当前进程的根目录从 initramfs 的根目录切换到刚刚挂载好的、真正的根文件系统上。
  6. 执行真正的 init:
    • initramfs 的 `/init` 脚本会执行真正根文件系统中的 `/sbin/init`(通常是 Systemd 或 SysVinit)。
    • Systemd 接管后续的启动过程,挂载其他文件系统(如 `/home`, `/var`),启动系统服务等。
  7. 清理:
    • initramfs 所占用的内存会被释放。

性质

initramfs vs. initrd

它们的目的相同,但实现方式不同:

initrd:是个基于块设备的镜像文件(如 `image.gz`),所以内核将其加载到内存中,模拟成磁盘(如 `/dev/ram0`),然后将其格式化为某种文件系统(如 `ext2`)并挂载。该方式效率较低,因其需要额外的块设备抽象层来中转。

initramfs:是基于 tmpfs(是种内存中的文件系统)的 `cpio` 归档。内核直接将其解压到 tmpfs 中并挂载,更加简单高效。它也是 `cpio` 格式,比 `ext2` 更容易构建。

针对 initrd 方式,initramfs 的优点:

不需要将“中间文件系统的驱动”编译到内核:initramfs 是 CPIO 格式(且被压缩),直接解压到在 tmpfs 上,而 tmpfs 在内核上,不需要单独文件系统驱动来访问。

不需要将块驱动编译到内核:其实当 Kernel 加载到内存并开始运行后,操作系统便已开始运行。至于运行具体的应用程序服务,那是用户空间的事情,也就说从 HDD 还是 NFS 启动那是用户空间的工作,由用户空间自行实现即可,内核不再关心这些块驱动。

构建

文件位置:通常位于 `/boot` 目录下,例如 `/boot/initrd.img-5.15.0-86-generic`。

针对常见操作,例如,“创建 initramfs 文件”、“查看 initramfs 内容”、“更新 initramfs 文件”、……,相关的工具有:

  • 针对 Debian Ubuntu …… 类别,使用 initramfs-tools 工具
  • 针对 CentOS RHEL …… 类别,使用 dracut 工具。
# 先解压(如果是.gz压缩)
cp /boot/initrd.img-5.15.0-86-generic /tmp/my_initrd.gz
cd /tmp
gzip -d my_initrd.gz

# 然后解包cpio归档
mkdir extract_dir
cd extract_dir
cpio -idv < ../my_initrd

# 现在你就可以在 `extract_dir` 目录下浏览 initramfs 的完整内容了。

:当安装新的内核模块或修改了相关配置(比如磁盘加密设置),需要重新生成 initramfs 文件。

# 在基于 Debian/Ubuntu 的系统上使用:
sudo update-initramfs -u -k all

# 在基于 RHEL/CentOS/Fedora 的系统上使用:

sudo dracut -f
sudo mkinitcpio -P # 或,通过该命令

dracut

  • dracut,用来创建 initramfs 镜像。
  • lsinitrd,用来查看 initramfs 镜像。
  • ……

应用

在 RHEL 7 中,initramfs 包含自身可用的整个系统。

参考

Initramfs arrives [LWN.net]
Documentation/filesystems/ramfs-rootfs-initramfs.txt
cpio – Wikipedia
DeepSeek / 介绍 initramfs