2. 嵌入式Linux根文件系统基础
在嵌入式 Linux 系统中,内核负责管理 CPU、内存、外设和驱动,而用户真正能“看见并使用”的系统环境,几乎都由根文件系统提供。内核启动完成后,会尝试挂载一个根文件系统,并执行其中的第一个用户态程序。如果根文件系统缺失、损坏或结构不符合预期,系统即使内核正常,也会停在启动阶段,无法进入可交互环境。因此,理解根文件系统的概念、目录标准、核心组件和启动流程,是发布 SDK 根文件系统版本工程的基础。
一、根文件系统到底是什么
根文件系统(Root Filesystem,简称 rootfs)是内核挂载在“/”目录下的文件系统。它不只是存放文件的目录集合,还承担着用户态运行环境、系统初始化、设备节点管理、库依赖、配置文件和应用程序入口等职责。嵌入式设备常见的根文件系统形态包括:
- 只读压缩镜像:如 squashfs、cramfs,体积小、启动快,适合量产固件。
- 可读写文件系统:如 ext4、ubifs、jffs2,适合需要保存配置或日志的设备。
- 内存文件系统:如 initramfs、tmpfs,常用于早期启动或临时根环境。
- 混合方案:只读根文件系统叠加可写分区,兼顾稳定性和可配置性。
从发布工程角度看,根文件系统不是“随便打包一个目录”,而是需要明确版本、依赖、权限、启动脚本和升级策略的软件制品。
二、目录结构标准:FHS 与嵌入式裁剪
Linux 根文件系统通常遵循 FHS(Filesystem Hierarchy Standard)思想,但嵌入式系统会根据资源限制进行裁剪。常见目录及其职责如下:
| 目录 | 主要职责 | 嵌入式常见内容 |
|---|---|---|
| /bin | 基础用户命令 | busybox 软链接、sh、ls、cp |
| /sbin | 系统管理命令 | init、ifconfig、reboot |
| /etc | 系统配置 | inittab、fstab、网络配置 |
| /lib | 共享库与内核模块 | libc.so、ld-linux.so、modules |
| /dev | 设备节点 | console、tty、mtdblock |
| /proc、/sys | 内核与设备信息接口 | 启动时挂载的虚拟文件系统 |
| /usr | 用户程序与资源 | 应用、脚本、资源文件 |
| /var | 可变数据 | 日志、锁文件、运行时状态 |
在嵌入式场景中,/usr 常被合并或简化,/var 可能挂载为 tmpfs,/dev 由 devtmpfs 或 mdev 动态管理。发布根文件系统时,必须确认这些目录的权限、属主和挂载点是否符合目标设备要求。
三、BusyBox 与系统库:用户态的最小骨架
BusyBox 是嵌入式 Linux 中最常见的用户态工具集。它把 ls、cp、mv、sh、ifconfig、mount 等大量命令集成到一个可执行文件中,通过软链接或 applet 机制提供不同命令入口。这样做可以显著减小根文件系统体积,同时保持基本 Shell 环境可用。
# 典型 BusyBox 安装后的目录结构
/bin/busybox
/bin/ls -> busybox
/bin/cp -> busybox
/sbin/init -> ../bin/busybox
系统库则是用户态程序运行的基础。动态链接的程序依赖 libc、libm、libpthread、libdl 等共享库,以及动态加载器 ld-linux.so。发布时必须确保:
- 库文件与目标架构匹配,如 arm、aarch64、mips。
- 库版本与应用程序、BusyBox 的编译环境一致。
- 动态加载器路径正确,避免出现 “No such file or directory” 但文件实际存在的情况。
- 必要时使用 strip 减小体积,但保留调试符号用于问题定位。
readelf -d 或 arm-linux-gnueabihf-objdump -p 查看 NEEDED 项,再逐一确认根文件系统中是否存在对应库。四、启动流程:从内核到用户态
嵌入式 Linux 的启动流程可以概括为:BootROM → Bootloader → Kernel → 根文件系统 → init → 用户应用。根文件系统相关部分主要集中在后三个阶段。
内核挂载根文件系统后,会寻找并执行 init 程序。嵌入式系统常见两种路径:一是 /sbin/init,通常由 BusyBox 提供;二是 /init,常见于 initramfs 或定制启动方案。init 会读取 /etc/inittab,执行 /etc/init.d/rcS 等脚本,完成挂载虚拟文件系统、设置网络、启动应用等操作。
# 典型 /etc/inittab 片段
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
五、案例与常见误区
假设某 ARM 设备内核启动日志停在 Kernel panic - not syncing: No init found。这通常不是内核问题,而是根文件系统没有正确挂载,或 init 程序不存在、权限错误、动态库缺失。排查顺序可以是:
- 确认内核命令行中的
root=与rootfstype=是否匹配实际存储分区。 - 确认根文件系统镜像已正确烧录,文件系统类型被内核支持。
- 确认
/sbin/init或/init存在且具有可执行权限。 - 使用
readelf -d检查 init 依赖的共享库是否齐全。 - 确认
/dev/console存在,否则 init 可能无法打开控制台。
从版本工程角度看,根文件系统应当像内核和 Bootloader 一样被版本化管理:记录 BusyBox 版本、libc 版本、目录清单、启动脚本变更和镜像校验值。只有这样,后续发布、回滚和问题定位才有可靠依据。