1、Rootfs 概述:什么是 Rootfs、它在嵌入式系统中的作用、与内核的关系

各位好,我是老李。做嵌入式 Linux 也有十几年了,今天咱们来聊聊 Rootfs。很多刚入行的朋友总觉得 Rootfs 就是个文件系统,装点库和脚本就完事了。其实不然,Rootfs 是整个用户态的灵魂,内核只是把硬件拉起来,真正干活的全靠它。

说白了,Rootfs 就是根文件系统。它挂载在 / 目录下,包含了系统启动后所需的一切:init 程序、共享库、配置文件、设备节点、应用程序等等。没有 Rootfs,内核启动完就只能打印一句 Kernel panic - not syncing: VFS: Unable to mount root fs,然后死在那。

一句话总结:Rootfs 是用户态世界的基石,内核负责提供舞台,Rootfs 负责上演好戏。

1.1 什么是 Rootfs

Rootfs 的全称是 Root Filesystem,根文件系统。它不仅仅是一个文件系统类型,更是一个逻辑概念。你想想看,系统启动后,内核会挂载一个文件系统到根目录 /,这个被挂载的文件系统就是 Rootfs。

它可以是真实的块设备分区,比如 /dev/mmcblk0p2;也可以是内存中的 tmpfs;还可以是 initramfs,直接打包在内核镜像里。我个人习惯把 Rootfs 理解为「用户态程序的生存环境」。

这里有个容易混淆的点:Rootfs 和根文件系统类型是两码事。Rootfs 是挂载点 / 上的内容,而它底层的格式可以是 ext4、squashfs、ubifs、jffs2 等等。我在项目中遇到过有人把这两者搞混,调试了三天才发现是文件系统类型选错了。

概念 说明 常见形式
Rootfs 挂载在 / 下的文件系统整体 目录树、文件、链接
文件系统类型 底层存储格式 ext4、squashfs、ubifs
存储介质 物理存储设备 eMMC、NAND Flash、SD 卡

1.2 Rootfs 在嵌入式系统中的作用

嵌入式系统不像 PC 那样有完整的硬盘和 BIOS,资源有限,启动流程也精简得多。Rootfs 在这里扮演了三个关键角色:

  • 提供用户态运行环境:内核启动后,第一个用户态进程(通常是 /sbin/init 或 /init)就来自 Rootfs。它负责拉起所有后续服务。
  • 承载应用程序和库:你的业务逻辑、第三方库、脚本、配置文件,全在 Rootfs 里。没有它,内核就是个空壳。
  • 管理设备节点和运行时数据:/dev、/proc、/sys、/tmp、/var 这些目录,要么在 Rootfs 中预置,要么在启动时动态挂载。

我记得有一次做工业网关,客户要求系统启动时间必须控制在 3 秒以内。我优化了内核还不够,最后发现 Rootfs 的 init 脚本里有个 sleep 2 秒的冗余等待。去掉之后,启动时间直接降到 2.1 秒。你看,Rootfs 的细节直接影响系统表现。

小提示:嵌入式系统中,Rootfs 的大小直接影响 Flash 占用和启动速度。我建议你根据实际需求裁剪,不要一股脑把整个 buildroot 或 yocto 的默认包全塞进去。

1.3 Rootfs 与内核的关系

内核和 Rootfs 的关系,我经常用「硬件驱动 + 用户态服务」来比喻。内核负责管理硬件、调度任务、提供系统调用;Rootfs 负责提供具体的业务逻辑和用户接口。两者通过 VFS(虚拟文件系统)层交互。

具体来说,内核启动流程是这样的:

  1. 内核解压并初始化,挂载 Rootfs。
  2. 内核执行 Rootfs 中的 /init 或 /sbin/init。
  3. init 进程根据配置文件启动其他服务。

如果内核找不到 Rootfs,系统就会 panic。我曾经在调试一块新板子时,内核启动参数里 root= 写错了设备节点,结果内核打印了一堆错误后直接挂掉。排查了半天才发现是 root=/dev/mmcblk0p2 写成了 root=/dev/mmcblk1p2。

避坑指南:内核启动参数中的 root= 和 rootfstype= 必须与你的 Rootfs 实际位置和类型匹配。我曾经见过有人把 squashfs 的 Rootfs 指定为 ext4 类型,内核挂载失败后直接 panic。

下面这张图展示了内核与 Rootfs 的协作关系:

内核与 Rootfs 协作关系图 内核与 Rootfs 协作关系 硬件层(CPU、内存、Flash、外设) Linux 内核(进程调度、内存管理、驱动、VFS) Rootfs(根文件系统) /sbin/init | /lib | /etc | /usr | /dev | /tmp 用户态服务(业务逻辑、网络、日志、监控) 内核通过 VFS 访问 Rootfs,Rootfs 中的 init 进程拉起所有用户态服务

从这张图可以看得很清楚:硬件在最底层,内核在中间层,Rootfs 和用户态服务在上层。每一层都依赖下一层提供的接口。内核启动后,第一个动作就是挂载 Rootfs,然后执行里面的 init 程序。如果 Rootfs 损坏或缺失,整个系统就停摆了。

嗯,这里要注意一点:Rootfs 不一定非得是持久化存储。比如 initramfs 就是在内存中解压的,系统掉电后内容就没了。这种方案适合快速启动或只读系统。我在做安全网关时就用过 initramfs,把核心校验逻辑放在内存里,防止被篡改。

1.4 常见的 Rootfs 类型对比

不同的嵌入式场景,Rootfs 的选型也不同。我整理了一张表,方便你对比:

类型 存储位置 读写特性 典型场景 优点 缺点
initramfs 内存 读写(掉电丢失) 快速启动、安全启动 启动快、无 Flash 磨损 容量受限、掉电丢失
squashfs Flash 只读 固件升级、只读系统 高压缩比、防篡改 不可写、更新需重烧
ext4 eMMC/SD 读写 通用嵌入式系统 成熟稳定、支持日志 需要较大的存储空间
ubifs NAND Flash 读写 大容量 NAND 设备 磨损均衡、掉电安全 配置复杂、依赖 UBI
jffs2 NOR/NAND Flash 读写 老旧设备、小容量 Flash 直接操作 Flash 挂载慢、内存占用高

我个人习惯是:如果系统需要频繁更新,用 squashfs + overlayfs 组合;如果对启动速度要求极高,用 initramfs;如果存储空间充裕且需要读写,直接上 ext4。

核心要点:Rootfs 的选型直接影响系统的启动速度、存储占用、可靠性和可维护性。没有银弹,只有最适合你项目的方案。