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

各位同学,咱们今天正式开讲《Rootfs 镜像裁剪与性能优化实战》的第一章。说实话,我每次带新人做嵌入式项目,第一个要讲清楚的就是 Rootfs。很多人觉得它不就是个文件系统嘛,挂上去就能跑。但实际上一旦你开始做裁剪、做优化,就会发现这里面的门道深得很。

我个人习惯把 Rootfs 比作一个房子的「内部装修」。内核是房子的框架和地基,而 Rootfs 就是里面的家具、水电、网络、甚至是你贴在墙上的便利贴。没有装修,房子也能住人,但你什么都干不了。嵌入式系统也是一样——内核启动后,如果没有 Rootfs,它就卡在 panic 状态,啥也做不了。

1.1 什么是 Rootfs

Rootfs,全称 Root Filesystem,根文件系统。它不是一个具体的文件系统类型(比如 ext4、squashfs),而是一个 逻辑概念。它指的是 Linux 内核启动后挂载的第一个文件系统,挂载点就是根目录 /。

你想想看,Linux 系统里所有进程的起点是 /sbin/init 或者 /bin/bash,这些可执行文件放在哪?就在 Rootfs 里。没有 Rootfs,内核连第一个用户态进程都启动不了。

核心定义: Rootfs 是 Linux 系统启动时挂载的第一个文件系统,它包含了系统运行所必需的文件、目录、设备节点、配置文件和工具程序。它是内核从「裸金属」过渡到「可用系统」的桥梁。

我记得刚入行那会儿,有个同事把 Rootfs 和根目录搞混了。他问我:「Rootfs 不就是 / 吗?」我说不对。/ 是挂载点,Rootfs 是挂载上去的那个东西。就好比 USB 接口和 U 盘的关系——接口是固定的,但插上去的 U 盘可以换。Rootfs 可以是一个 ramdisk、一个 squashfs 镜像、一个 NFS 共享目录,甚至是一个 initramfs 包。

1.2 Rootfs 在 Linux 系统中的作用

Rootfs 的作用,我用三个词来概括:启动、运行、管理。咱们一个一个说。

1.2.1 启动系统

内核启动的最后一步,就是挂载 Rootfs 并执行第一个用户态程序。这个程序通常是 /sbin/init,它负责启动所有后续的服务和进程。如果 Rootfs 里没有 /sbin/init,内核会报 Kernel panic - not syncing: No init found,然后死在那。

我曾经在一个 ARM 板子的项目上遇到过这个问题。当时我裁剪 Rootfs 裁得太狠,把 /sbin/init 给删了,结果板子死活起不来。查了半天日志才发现是这个问题。嗯,从那以后我裁剪 Rootfs 都会留一个最小可用的 init 程序。

1.2.2 提供运行时环境

系统启动后,所有用户态进程都依赖 Rootfs 提供的文件和服务。包括但不限于:

  • 动态链接库:/lib 和 /usr/lib 下的 .so 文件,没有它们,任何动态链接的程序都跑不起来。
  • 设备节点:/dev 下的设备文件,比如 /dev/null、/dev/console,没有这些,程序连标准输入输出都用不了。
  • 配置文件:/etc 下的各种配置,比如 /etc/inittab、/etc/fstab,决定了系统的行为。
  • 临时文件系统:/tmp、/var 等目录,用于运行时数据存储。

我的经验: 在做嵌入式系统时,我建议你把 Rootfs 分成「最小启动集」和「功能扩展集」两部分。最小启动集只包含内核启动后必须的文件,比如 init、sh、基本的 libc 和设备节点。功能扩展集按需添加。这样裁剪起来思路清晰,不容易出错。

1.2.3 提供管理接口

Rootfs 还提供了系统管理的工具和接口。比如 /bin/ls、/bin/ps、/sbin/ifconfig 这些命令,都是放在 Rootfs 里的。没有它们,你连系统里跑了哪些进程、网络通不通都查不了。

说白了,Rootfs 就是用户和内核之间的「翻译官」。用户通过 Rootfs 里的工具程序,向内核发起系统调用,完成各种操作。

1.3 Rootfs 与内核的关系

这个关系我画了一张图,大家先看看,我再细讲。

Rootfs 与内核的关系 硬件层(CPU / 内存 / 外设) Linux 内核(进程调度 / 内存管理 / 驱动 / VFS) 提供系统调用接口(open, read, write, execve...) Rootfs(根文件系统) /sbin/init /bin/sh /lib/libc.so /etc/inittab /dev/console 提供用户态环境:进程管理、文件访问、设备操作 用户态进程(init, shell, daemon, application) 内核通过 VFS(虚拟文件系统)访问 Rootfs,Rootfs 通过系统调用为进程提供服务

从这张图可以看得很清楚:

  • 内核在最底层,直接管理硬件。它提供系统调用接口,但不关心用户怎么用。
  • Rootfs 在中间层,它挂载在内核之上,提供文件系统和用户态环境。
  • 用户进程在最上层,它们通过 Rootfs 里的工具和库,间接使用内核的服务。

内核和 Rootfs 之间有一个关键的接口——VFS(虚拟文件系统)。VFS 是内核中的一个抽象层,它屏蔽了不同文件系统(ext4、squashfs、tmpfs 等)的差异。内核通过 VFS 来读写 Rootfs 里的文件,不管底层是 flash、ram 还是网络。

注意: 内核和 Rootfs 是 独立编译 的。内核编译出来是 zImage 或 uImage,Rootfs 编译出来是 .img 或 .squashfs 文件。它们可以分开烧录、分开升级。但内核必须知道 Rootfs 在哪里(通过 bootargs 参数指定),否则启动时会 panic。

我举个例子你就明白了。假设你有一个嵌入式设备,内核放在 flash 的 0x100000 位置,Rootfs 放在 0x200000 位置。bootloader 启动内核时,会传一个参数:root=/dev/mtdblock2 或者 root=31:02。内核根据这个参数找到 Rootfs 的物理位置,挂载它,然后执行 init。

这里有个坑,我曾经踩过。有一次我改了分区表,Rootfs 的偏移地址变了,但忘了改 bootargs。结果内核启动后找不到 Rootfs,直接 panic。查了半天才发现是参数没更新。所以,每次调整分区或镜像位置,一定要同步更新 bootargs。

1.4 Rootfs 的常见形态

在实际项目中,Rootfs 有几种常见的形态。我整理了一个表格,方便你对比:

形态 存储介质 特点 适用场景
initramfs 内存(cpio 归档) 启动快,体积小,可定制;但掉电丢失 早期启动、救援系统、Live CD
squashfs Flash(只读压缩) 体积小,压缩率高,只读安全;但不可写 嵌入式设备、路由器、IoT 终端
ext4 / ubifs Flash / 硬盘(读写) 可读写,支持日志;但体积大,有磨损问题 通用 Linux、开发板、需要持久化数据的设备
NFS Rootfs 网络(远程挂载) 方便调试,无需烧录;但依赖网络,速度慢 开发调试阶段、原型验证

我个人在项目中最常用的是 squashfs + overlayfs 的组合。squashfs 作为只读基座,overlayfs 在内存或 flash 上叠加一个可写层。这样既保证了 Rootfs 的稳定性和安全性,又保留了可写能力。后面讲到裁剪的时候,我会详细展开这个方案。

1.5 本章小结

好了,第一章的内容就这些。咱们回顾一下重点:

  • Rootfs 是内核启动后挂载的第一个文件系统,它提供了系统运行所需的所有用户态文件。
  • Rootfs 的作用是启动系统、提供运行时环境、提供管理接口,缺一不可。
  • 内核和 Rootfs 是独立但依赖的关系,内核通过 VFS 访问 Rootfs,Rootfs 通过系统调用为进程服务。
  • Rootfs 有多种形态,选择哪种取决于你的硬件、性能和功能需求。