4. 根文件系统概念

根文件系统(Root Filesystem,简称 rootfs)是 Linux 系统启动过程中挂载的第一个文件系统,也是整个用户空间的基础。在 QEMU 系统级模拟中,根文件系统的正确挂载是内核从“启动”进入“可用”状态的关键转折点。本章将深入剖析根文件系统的核心作用、标准目录结构以及它与内核的协作关系。

核心要点:根文件系统是内核与用户态程序之间的桥梁。内核启动后,必须挂载根文件系统才能执行 init 进程,进而启动所有用户空间服务。没有根文件系统,内核将 panic 并停止启动。

4.1 根文件系统的作用

根文件系统不仅仅是存储文件的容器,它在系统启动和运行中承担着多重关键角色:

  • 启动入口:内核完成初始化后,从根文件系统加载并执行第一个用户态进程(通常是 /sbin/init 或 /init)。
  • 系统配置中心:存放系统配置文件(/etc)、设备节点(/dev)、运行时数据(/var)等。
  • 动态库与工具链:提供用户态程序所需的共享库(/lib、/usr/lib)和基础命令工具(/bin、/sbin)。
  • 挂载点基础:作为其他文件系统(如 proc、sysfs、tmpfs、块设备分区)的挂载点根目录。
  • 内核模块仓库:存放可动态加载的内核模块(/lib/modules),用于扩展内核功能。
QEMU 调试提示:在 QEMU 中模拟嵌入式系统时,根文件系统通常以 initramfs(内存盘)或磁盘镜像(如 rootfs.ext4)的形式提供。内核启动参数中的 root= 选项指定了根文件系统的设备路径。
根文件系统核心作用 根文件系统 启动入口 加载 init 进程 配置中心 /etc, /dev, /var 动态库与工具 /lib, /bin, /sbin 挂载点基础 proc, sysfs, tmpfs 根文件系统是内核与用户空间之间的唯一桥梁

4.2 FHS 标准目录结构

文件系统层次结构标准(Filesystem Hierarchy Standard,FHS)定义了 Linux 系统中目录的布局和用途。遵循 FHS 标准可以确保不同发行版之间的兼容性,并使系统管理更加可预测。以下是根文件系统中最核心的目录及其作用:

目录 作用 QEMU 调试关注点
/bin 基本用户命令(如 ls, cp, mv) 必须包含 sh 和 init 相关工具
/sbin 系统管理命令(如 mount, ifconfig) 需要 mount 和 swapon 用于挂载
/etc 系统配置文件(如 fstab, inittab) fstab 决定自动挂载行为
/dev 设备节点文件 至少包含 console、null、tty
/lib 共享库和内核模块 缺少 ld-linux.so 会导致程序无法运行
/proc 进程和内核信息虚拟文件系统 内核启动后自动挂载,提供运行时信息
/sys 设备和内核对象虚拟文件系统 用于设备驱动管理和热插拔
/tmp 临时文件存储 通常挂载为 tmpfs 以提高性能
/var 可变数据(日志、缓存、锁文件) 日志文件对调试启动问题至关重要
/usr 用户程序和数据(二级层次) 嵌入式系统常将 /usr 合并到根目录
常见陷阱:在构建最小根文件系统时,开发者经常遗漏 /dev/console 设备节点。这会导致内核无法输出启动信息到控制台,表现为 QEMU 启动后黑屏或无响应。务必使用 mknod /dev/console c 5 1 创建该节点。
FHS 标准目录结构 / (root) /bin /sbin /etc /dev /lib /proc /sys /etc/fstab /dev/console /lib/modules FHS 标准确保不同 Linux 系统之间的目录布局一致性 嵌入式系统可精简,但 /dev/console 和 /sbin/init 是必须的

4.3 根文件系统与内核的关系

根文件系统与 Linux 内核之间存在着紧密的依赖和协作关系。理解这种关系对于调试 QEMU 启动问题至关重要。

4.3.1 启动阶段的交互流程

  1. 内核自解压与初始化:QEMU 加载内核镜像后,内核进行自解压、CPU 检测、内存初始化等操作。
  2. 挂载根文件系统:内核根据启动参数 root= 指定的设备(如 /dev/vda、/dev/mmcblk0)或 initrd/initramfs 尝试挂载根文件系统。
  3. 执行 init 进程:挂载成功后,内核在根文件系统中查找并执行 /sbin/init(或 /init、/bin/sh,取决于内核配置)。
  4. 用户空间接管:init 进程读取 /etc/inittab 或 /etc/init.d/rcS,启动系统服务、网络配置、挂载其他文件系统。
  5. 运行时协作:用户态程序通过系统调用(syscall)请求内核服务,内核通过 /proc 和 /sys 向用户空间暴露系统信息。
关键参数:在 QEMU 命令行中,通过 -append "root=/dev/vda rw console=ttyS0" 传递给内核的启动参数决定了根文件系统的挂载方式。root= 指定设备路径,rw 表示以读写模式挂载,console=ttyS0 指定控制台输出到串口。

4.3.2 内核与根文件系统的依赖关系

依赖方向 具体依赖 QEMU 调试影响
内核 → 根文件系统 内核需要根文件系统提供 init 进程、设备节点、配置文件和动态库 根文件系统缺失或损坏 → 内核 panic
根文件系统 → 内核 用户态程序依赖内核提供的系统调用、设备驱动和虚拟文件系统 内核配置错误(如缺少块设备驱动)→ 无法挂载根文件系统
双向协作 内核通过 /proc 和 /sys 向用户空间提供信息;用户空间通过 ioctl、read/write 控制硬件 /proc 和 /sys 未挂载 → 许多工具无法正常工作
内核与根文件系统启动交互流程 1. 内核自解压与初始化 2. 挂载根文件系统 3. 执行 init 进程 4. 用户空间接管 5. 运行时协作 QEMU 启动参数示例 -append "root=/dev/vda rw" -initrd initramfs.gz -drive file=rootfs.ext4,format=raw 常见失败原因 • 缺少块设备驱动 • 根文件系统格式不支持 • /sbin/init 不存在或损坏

4.4 根文件系统的挂载方式

在 QEMU 系统级模拟中,根文件系统可以通过多种方式挂载,每种方式适用于不同的场景:

  • initramfs(内存盘):内核将压缩的 cpio 归档解压到内存中作为根文件系统。适用于快速启动和调试,无需磁盘驱动。
  • 磁盘镜像(块设备):根文件系统存储在磁盘镜像文件(如 rootfs.ext4)中,通过 QEMU 的 -drive 或 -sd 选项模拟为块设备。
  • 网络文件系统(NFS):根文件系统通过网络挂载到远程服务器上。适用于开发阶段,无需反复制作镜像。
  • 9P 共享目录:QEMU 特有的虚拟化文件系统,将宿主机目录直接共享给客户机。适用于快速原型开发。
调试建议:在 QEMU 开发初期,优先使用 initramfs 方式。它不依赖块设备驱动,可以快速验证内核启动流程。待内核配置稳定后,再切换到磁盘镜像方式以模拟真实硬件环境。

4.5 构建最小根文件系统的关键步骤

在 QEMU 调试中,构建一个最小但可用的根文件系统是常见需求。以下是核心步骤:

  1. 创建目录结构:按照 FHS 标准创建 /bin、/sbin、/etc、/dev、/lib、/proc、/sys、/tmp 等目录。
  2. 添加设备节点:使用 mknod 创建 /dev/console(主设备号 5,次设备号 1)和 /dev/null(主设备号 1,次设备号 3)。
  3. 复制 BusyBox:编译 BusyBox 并安装到根文件系统中,提供基本的 shell 和命令工具。
  4. 配置 init 进程:创建 /sbin/init 或 /init 脚本,执行必要的初始化操作(如挂载 /proc、/sys)。
  5. 添加共享库:使用 ldd 检查 BusyBox 依赖的共享库,并将其复制到 /lib 目录下。
  6. 打包为 cpio 归档:使用 find . | cpio -o -H newc | gzip > ../rootfs.cpio.gz 创建 initramfs 镜像。
最小 init 脚本示例:
#!/bin/sh
# 最小根文件系统初始化脚本
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp
echo "Welcome to Minimal Rootfs!"
exec /bin/sh
将此脚本保存为 /init 并赋予可执行权限(chmod +x /init),即可在 QEMU 中启动一个可交互的 shell 环境。