3. 文件系统类型对比:SquashFS、JFFS2、UBIFS、EXT4、RAMFS、TMPFS的优劣分析
选文件系统,说白了就是选「根」在哪、怎么存、怎么读。
我见过不少团队,启动慢到怀疑人生,最后发现是文件系统选错了。你想想看,一个只读的 rootfs 用 JFFS2 去跑,不光浪费 Flash 寿命,挂载时间还长到离谱。
这一章,我把嵌入式里最常见的六种文件系统拉出来,逐个拆解。不聊虚的,直接说它们适合什么场景、有什么坑、我踩过哪些雷。
核心观点:没有「最好」的文件系统,只有「最合适」的场景。选型错了,后面优化启动全是白费力气。
3.1 先看一张全景图
下面这张图,是我自己整理的文件系统选型决策流程。每次做新项目,我都会先过一遍这个逻辑。
3.2 SquashFS:只读场景的王者
SquashFS 是我个人最常用的只读文件系统。它把整个文件系统压缩成一个只读镜像,启动时直接解压到内存或挂载。
优点:
- 压缩率高:支持 gzip、lzma、lzo、zstd 等多种算法。我习惯用 zstd,解压速度快,压缩比也不错。
- 挂载快:不需要扫描整个镜像,直接按索引读取。启动时间可以控制在毫秒级。
- 防篡改:只读特性天然适合固件升级场景,不用担心意外写坏。
缺点:
- 不能写:运行时无法修改文件内容。需要配合 overlayfs 或 tmpfs 实现可写层。
- 不支持碎片化:镜像一旦生成,文件布局就固定了。如果后期要更新,得重新打包整个镜像。
我的经验:在 IoT 设备上,我通常把 SquashFS 作为 rootfs 的主镜像,挂载到 /ro。然后用 overlayfs 把 /etc、/var 等需要写的地方映射到 tmpfs 或小分区上。这样既保证了根文件系统的完整性,又保留了配置修改能力。
3.3 JFFS2:老将,但该退休了
JFFS2 是专门为 NOR Flash 设计的日志型文件系统。我在十年前的项目里用过它,现在基本不碰了。
优点:
- 磨损均衡:自动管理 Flash 块的擦写次数,延长寿命。
- 掉电安全:日志结构保证意外掉电后数据一致性。
缺点:
- 挂载极慢:启动时要扫描整个 Flash 重建日志。我遇到过 64MB 的 JFFS2 分区挂载耗时超过 10 秒。
- 内存占用高:日志结构需要在内存中维护大量元数据。
- 不支持大页 NAND:对现代 NAND Flash 支持很差。
避坑指南:我曾经在一个项目里用 JFFS2 做 rootfs,结果每次冷启动都要等 15 秒才能进 shell。后来换成 SquashFS + overlayfs,启动时间直接降到 3 秒。如果你的 Flash 容量超过 32MB,千万别用 JFFS2。
3.4 UBIFS:NAND Flash 的现代选择
UBIFS 是 JFFS2 的接班人,专门为 NAND Flash 设计。它工作在 UBI 层之上,解决了 JFFS2 的很多痛点。
优点:
- 挂载快:不需要扫描整个 Flash。UBI 层维护了逻辑块到物理块的映射,挂载时只读索引头。
- 支持大容量:可以轻松管理 GB 级别的 NAND Flash。
- 写性能好:异步写入,批量处理,比 JFFS2 快很多。
缺点:
- 需要 UBI 层:内核配置复杂,分区管理多了一层。
- 压缩可选:默认不压缩,需要手动开启。
- 对 NOR Flash 支持差:UBI 层是为 NAND 设计的,NOR 上用 UBIFS 性能反而不好。
适用场景:如果你的板子用 NAND Flash 做存储,且 rootfs 需要可读写(比如存日志、用户数据),UBIFS 是首选。我最近一个工业网关项目就用它,64MB 分区挂载不到 1 秒。
3.5 EXT4:SD/eMMC 的标配
EXT4 是 Linux 桌面和服务器上的标准文件系统。在嵌入式里,它主要用在 SD 卡、eMMC 这类块设备上。
优点:
- 成熟稳定:社区支持最好,工具链完善。
- 性能优秀:延迟分配、多块分配等特性让读写速度很快。
- 支持大文件:单个文件最大 16TB,分区最大 1EB。
缺点:
- 没有磨损均衡:直接操作块设备,Flash 寿命全靠硬件 FTL。
- 掉电不安全:日志模式可以保证元数据一致性,但数据可能丢失。
- 不适合小分区:EXT4 的元数据开销大,分区小于 64MB 时浪费严重。
我的建议:用 eMMC 做 rootfs 时,EXT4 是稳妥的选择。但记得开启 noatime 挂载选项,减少不必要的写操作。另外,分区大小至少留 256MB,否则 inode 不够用。
3.6 RAMFS 与 TMPFS:内存里的临时工
这两个都是基于内存的文件系统,但实现方式不同。
RAMFS:
- 基于 ramfs 驱动,直接使用物理内存。
- 没有大小限制,可以写满内存直到 OOM。
- 不支持 swap,数据不能换出。
- 适合极小系统,比如 initramfs 的根文件系统。
TMPFS:
- 基于 shmem,支持大小限制和 swap。
- 可以指定最大容量,防止 OOM。
- 性能略低于 RAMFS,但更安全。
- 适合 /tmp、/var/run 等临时目录。
避坑指南:我见过有人用 RAMFS 做 /tmp,结果一个进程写了个大文件,系统直接 OOM 挂了。换成 TMPFS 并设置 size=32M 就没事了。记住:RAMFS 是裸奔,TMPFS 是带安全带的。
3.7 横向对比表
下面这张表,我把六个文件系统的关键参数放在一起。选型时直接对照着看就行。
| 特性 | SquashFS | JFFS2 | UBIFS | EXT4 | RAMFS | TMPFS |
|---|---|---|---|---|---|---|
| 存储介质 | Flash/内存 | NOR/NAND | NAND | SD/eMMC | 内存 | 内存 |
| 读写属性 | 只读 | 可读写 | 可读写 | 可读写 | 可读写 | 可读写 |
| 挂载速度 | 极快 | 极慢 | 快 | 快 | 极快 | 极快 |
| 压缩支持 | 是(多种算法) | 否 | 可选 | 否 | 否 | 否 |
| 磨损均衡 | N/A(只读) | 是 | 是(UBI层) | 否(依赖FTL) | N/A | N/A |
| 掉电安全 | 是(只读) | 是 | 是 | 日志模式 | 否 | 否 |
| 典型用途 | 只读 rootfs | 老旧 Flash 设备 | NAND rootfs | eMMC/SD 卡 | initramfs | /tmp /var/run |
3.8 实战选型建议
说了这么多,到底怎么选?我总结几条实战经验:
- 只读 rootfs + SquashFS:这是最稳妥的组合。启动快、体积小、安全。配合 overlayfs 实现可写层。
- NAND Flash + UBIFS:如果需要可读写,UBIFS 是唯一现代选择。别碰 JFFS2,除非你的 Flash 小于 16MB。
- eMMC/SD + EXT4:块设备上 EXT4 最成熟。记得开启 noatime 和 discard。
- 临时目录 + TMPFS:永远用 TMPFS 而不是 RAMFS。设置 size 限制,防止 OOM。
- initramfs + RAMFS:内核启动阶段用 RAMFS 做临时根,等 SquashFS 挂载后再切换。
我的常用组合:SquashFS(只读 rootfs)+ overlayfs(可写层)+ TMPFS(/tmp、/var/run)+ EXT4(数据分区)。这个方案在启动速度、存储效率和可靠性之间取得了很好的平衡。