3. 文件系统类型对比:SquashFS、JFFS2、UBIFS、EXT4、RAMFS、TMPFS的优劣分析

选文件系统,说白了就是选「根」在哪、怎么存、怎么读。

我见过不少团队,启动慢到怀疑人生,最后发现是文件系统选错了。你想想看,一个只读的 rootfs 用 JFFS2 去跑,不光浪费 Flash 寿命,挂载时间还长到离谱。

这一章,我把嵌入式里最常见的六种文件系统拉出来,逐个拆解。不聊虚的,直接说它们适合什么场景、有什么坑、我踩过哪些雷。

核心观点:没有「最好」的文件系统,只有「最合适」的场景。选型错了,后面优化启动全是白费力气。

3.1 先看一张全景图

下面这张图,是我自己整理的文件系统选型决策流程。每次做新项目,我都会先过一遍这个逻辑。

嵌入式文件系统选型决策流程 嵌入式文件系统选型决策流程 根文件系统选型 根文件系统是否只读? 是(只读) 否(可读写) SquashFS RAMFS(内存盘) UBIFS(NAND Flash) JFFS2(老旧 NOR/NAND) EXT4(SD/eMMC) TMPFS(运行时临时文件) 💡 说明: 实际项目中,常采用「SquashFS + overlayfs + TMPFS」组合方案:只读根 + 可写上层。

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 实战选型建议

说了这么多,到底怎么选?我总结几条实战经验:

  1. 只读 rootfs + SquashFS:这是最稳妥的组合。启动快、体积小、安全。配合 overlayfs 实现可写层。
  2. NAND Flash + UBIFS:如果需要可读写,UBIFS 是唯一现代选择。别碰 JFFS2,除非你的 Flash 小于 16MB。
  3. eMMC/SD + EXT4:块设备上 EXT4 最成熟。记得开启 noatime 和 discard。
  4. 临时目录 + TMPFS:永远用 TMPFS 而不是 RAMFS。设置 size 限制,防止 OOM。
  5. initramfs + RAMFS:内核启动阶段用 RAMFS 做临时根,等 SquashFS 挂载后再切换。

我的常用组合:SquashFS(只读 rootfs)+ overlayfs(可写层)+ TMPFS(/tmp、/var/run)+ EXT4(数据分区)。这个方案在启动速度、存储效率和可靠性之间取得了很好的平衡。