🧩 Linux 内核启动阶段的临时根文件系统技术文档

🧩 Linux 内核启动阶段的临时根文件系统技术文档

📘 1. 概述(Overview)

在 Linux 启动的早期阶段,内核尚未挂载实际的根文件系统(例如 eMMC 上的 ext4 或 NFS 根目录)。
为了让系统具备运行基本命令、加载驱动、挂载真实根文件系统的能力,
内核引入了一种称为 临时根文件系统 (Early Root Filesystem) 的机制。

该机制在不同内核时代有两种主要实现:

阶段 技术名称 实现方式
Linux 2.4 及以前 initrd (initial RAM disk) 将压缩镜像加载为虚拟块设备 /dev/ram0,再挂载
Linux 2.6 及以后 initramfs (initial RAM filesystem) cpio 压缩包直接解包进内存文件系统(ramfs/tmpfs)

⚙️ 2. 启动阶段流程概览

Linux 启动阶段涉及从 bootloader → 内核 → initramfs/initrd → 用户空间 init 的完整链路。

1. BIOS/UEFI
2. Bootloader (GRUB/U-Boot)
   - 加载 vmlinuz (内核映像)
   - 加载 initramfs/initrd 到内存
3. Linux Kernel
   - 初始化内核子系统
   - 创建 rootfs (ramfs/tmpfs)
   - 解包 initramfs 或挂载 initrd
   - 执行临时根中的 /init
4. /init
   - 探测真实根文件系统(eMMC/NFS/overlay)
   - 挂载目标根目录
   - 调用 `switch_root` 或 `pivot_root`
5. 启动真正的 /sbin/init 或 systemd

🧩 3. 技术架构与数据流

3.1 逻辑结构图

┌────────────────────────────┐
│ Bootloader                 │
│  - 加载 Kernel + Initramfs │
└────────────┬───────────────┘
┌────────────▼───────────────┐
│ Linux Kernel               │
│  - 创建 rootfs (ramfs)     │
│  - 解包 initramfs.cpio.gz  │
│  - 执行 /init              │
└────────────┬───────────────┘
┌────────────▼───────────────┐
│ /init 用户态脚本           │
│  - 探测真实根文件系统      │
│  - 挂载 /new_root          │
│  - switch_root /new_root   │
└────────────┬───────────────┘
┌────────────▼───────────────┐
│ 真正根文件系统 (ext4/NFS)  │
│ /sbin/init → systemd/init  │
└────────────────────────────┘

🧱 4. Initramfs 内部结构

Initramfs 是一个 cpio 格式的压缩包,包含早期启动所需的最小文件集:

initramfs/
├── bin/
│   └── busybox
├── dev/
├── etc/
├── proc/
├── sys/
├── init          ← 启动脚本(最关键)
└── lib/

典型创建命令:

find . | cpio -H newc -o | gzip > ../initramfs.cpio.gz

加载方式(由 Bootloader 指定):

qemu-system-x86_64 -kernel bzImage -initrd initramfs.cpio.gz -append "console=ttyS0"

🧩 5. 内核解包与挂载流程(源码级)

以 Linux 6.x 为例,主流程如下:

5.1 调用链概览

start_kernel()
 └── rest_init()
      └── kernel_init()
           └── prepare_namespace()
                ├── create_rootfs()
                ├── unpack_to_rootfs()     ← 解包 initramfs.cpio
                └── run_init_process("/init")

5.2 关键函数说明

函数 文件 功能描述
populate_rootfs() init/initramfs.c 将 cpio 包内容解包到内存文件系统
do_mounts_initrd() init/do_mounts_initrd.c 若为旧版 initrd,挂载 /dev/ram0
run_init_process() init/main.c 尝试执行 /init/sbin/init
switch_root() /usr/sbin/switch_root.c 从 initramfs 切换到真正 rootfs

🧩 6. 关键内核配置项

配置项 作用 典型值
CONFIG_BLK_DEV_INITRD 启用旧版 initrd 支持 y
CONFIG_INITRAMFS_SOURCE 指定内嵌 initramfs 源路径 "initramfs_list"
CONFIG_RD_GZIP 支持 gzip 压缩 y
CONFIG_TMPFS 允许 tmpfs 用作 rootfs y
CONFIG_INIT_ENV_ARG_LIMIT 控制 /init 参数限制 默认 32

🧩 7. 内核内嵌 Initramfs

可以直接将 initramfs 打包进内核:

make menuconfig
→ General setup → Initramfs source file(s)

或通过环境变量:

make INITRAMFS_SOURCE=../rootfs

生成的内核会在 usr/initramfs_data.c 中嵌入二进制数据:

const char __initramfs_start[];
const char __initramfs_end[];

⚙️ 8. /init 启动脚本职责

/init 是 initramfs 的“入口点”,它在真正的 /sbin/init 启动前执行。

典型实现(BusyBox 风格):

#!/bin/sh
echo "[INITRAMFS] Booting early init system..."

mount -t proc proc /proc
mount -t sysfs sysfs /sys

# 检测真实根分区
mount /dev/mmcblk0p2 /new_root

# 切换根文件系统
exec switch_root /new_root /sbin/init

🔩 9. 与真实根文件系统的切换机制

9.1 pivot_root(旧方式)

  • 将新根文件系统切换到 /new_root
  • 原根文件系统挂载到 /new_root/initrd
  • 已弃用,需手动卸载旧根

9.2 switch_root(现代方式)

  • 替换根并清空旧文件系统
  • 由 BusyBox 或 util-linux 提供
  • 更简洁、安全
switch_root /new_root /sbin/init

🧩 10. 调试与验证

操作目标 命令或方法
查看内核是否加载 initramfs dmesg
解包 initramfs 文件 gzip -dc initramfs.cpio.gz
在 /init 中打调试日志 echo "step 1..." > /dev/console
查看 rootfs 类型 cat /proc/filesystems
切换失败原因分析 检查 /dev, /proc, /sys 是否挂载

🧩 11. 嵌入式系统应用案例

应用场景 描述
单镜像系统 BusyBox + initramfs 直接作为系统根,无需外部存储
固件升级系统 initramfs 启动后校验、刷写、重启
加密文件系统启动 initramfs 中负责解密根分区后切换根
容灾/救援系统 提供最小恢复环境 (rescue shell)

🧩 12. 实验验证(QEMU Demo)

# 构建 busybox
make defconfig
make install

# 构建 initramfs
mkdir -p rootfs/{bin,dev,proc,sys}
cp -a _install/* rootfs/
echo -e '#!/bin/sh\nmount -t proc proc /proc\nmount -t sysfs sysfs /sys\necho "Hello Initramfs"\nexec /bin/sh' > rootfs/init
chmod +x rootfs/init

find . | cpio -H newc -o | gzip > ../initramfs.cpio.gz

# 启动 QEMU
qemu-system-x86_64 -kernel bzImage -initrd initramfs.cpio.gz -append "console=ttyS0"

输出:

[INITRAMFS] Booting...
Hello Initramfs
/ #

🧩 13. 内存占用与性能分析

项目 initrd initramfs
解包方式 解压到块设备 直接展开到 tmpfs
内存占用 双倍(块设备+文件系统) 单份(直接文件缓存)
启动速度 较慢 快 30–50%
占用结构 页缓存 + ramdisk VFS 缓存
回收机制 手动卸载 自动回收 tmpfs 空间

🧩 14. 总结

项目 initrd initramfs
文件格式 ext2 镜像 cpio 包
是否需块设备
文件系统类型 ext2 tmpfs/ramfs
兼容性 老内核 新内核(2.6+)
性能 一般 优秀
推荐使用

🧩 15. 参考资料

  • Linux Kernel Documentation
    /usr/src/linux/Documentation/filesystems/ramfs-rootfs-initramfs.txt
  • BusyBox 官方文档: https://busybox.net/
  • 内核源码:init/initramfs.c, init/main.c
  • LWN: “Early userspace in Linux 2.6”
  • Yocto Project: initramfs integration guide