嵌入式存储文件系统:ext4、jffs2、ubifs 格式选型与适配
嵌入式存储文件系统:ext4、jffs2、ubifs 格式选型与适配
选文件系统就像选鞋子——跑步穿跑鞋,登山穿登山靴。把 ext4 硬塞进 NOR Flash,就像穿高跟鞋踢足球,不是不行,是疼。
引言
嵌入式设备的存储介质种类繁多:SD 卡、eMMC、NOR Flash、NAND Flash……每种介质的特性不同,对应的文件系统也不同。选错文件系统,轻则性能拉胯,重则数据丢失。本文将对比主流嵌入式文件系统格式,给出选型建议和适配方法。
一、嵌入式存储介质分类
在选文件系统之前,先搞清楚存储介质的类型:
| 介质类型 | 特点 | 典型容量 | 常见用途 |
|---|---|---|---|
| NOR Flash | 读取快、随机访问、XIP可执行 | 1~32MB | 存放Bootloader、内核 |
| NAND Flash | 密度高、便宜、有坏块 | 128MB~4GB | 存放根文件系统、用户数据 |
| eMMC | 内置控制器、无坏块问题 | 4~64GB | 手机、平板、开发板 |
| SD/TF卡 | 可插拔、便携 | 4~128GB | 开发板、便携设备 |
| SPI Flash | 接口简单、容量小 | 4~32MB | 小型IoT设备 |
关键区别:NOR/NAND Flash 是裸芯片,需要文件系统处理坏块和磨损均衡;eMMC/SD 卡内置了 FTL(Flash Translation Layer)控制器,对上层透明。
二、主流文件系统格式对比
2.1 全面对比表
| 特性 | ext4 | JFFS2 | UBIFS | SquashFS | YAFFS2 |
|---|---|---|---|---|---|
| 支持介质 | eMMC/SD | NOR/NAND | NAND | 任意 | NAND |
| 可写性 | 读写 | 读写 | 读写 | 只读 | 读写 |
| 掉电安全 | 否(需journal) | 是 | 是 | N/A | 是 |
| 磨损均衡 | 不需要(FTL处理) | 内置 | UBI层处理 | 不需要 | 内置 |
| 坏块管理 | 不需要(FTL处理) | 内置 | UBI层处理 | 不需要 | 内置 |
| 压缩 | 否 | 是(zlib) | 是(lzo/zlib) | 是(xz/gzip) | 否 |
| 挂载速度 | 快 | 慢(全扫描) | 快(索引) | 快 | 中 |
| 内存占用 | 低 | 高(全加载) | 中 | 低 | 中 |
| 适用容量 | 任意 | <128MB | <2GB | 任意 | <2GB |
2.2 各格式详解
ext4
桌面 Linux 的主力文件系统。在嵌入式中主要用于 eMMC 和 SD 卡。
- 优点:成熟稳定、性能好、工具链完善
- 缺点:不支持掉电安全(虽然有 journal,但嵌入式突然断电仍有风险)
- 适用:eMMC、SD 卡,资源相对充足的设备
JFFS2
专为 Flash 设计的日志结构文件系统。
- 优点:掉电安全、支持压缩、支持 NOR 和 NAND
- 缺点:挂载速度随容量线性增长(128MB 需要 10+ 秒),内存占用大
- 适用:小容量 NOR Flash(<32MB),小容量 NAND
UBIFS
JFFS2 的继任者,基于 UBI 子系统,专为大容量 NAND Flash 优化。
- 优点:挂载快(维护索引树)、支持压缩、掉电安全
- 缺点:配置复杂(需要先创建 UBI 卷)
- 适用:大容量 NAND Flash(128MB~2GB)
SquashFS
只读压缩文件系统,适合存放不需要修改的系统文件。
- 优点:压缩率高(xz压缩可节省60%+空间)、挂载快
- 缺点:只读,无法修改
- 适用:根文件系统的只读部分、overlayfs 的底层
三、选型决策流程
存储介质是什么?
│
┌────────────┼────────────┐
│ │ │
eMMC/SD NAND Flash NOR Flash
│ │ │
ext4(首选) 容量>128MB? 容量<32MB?
│ / \ / \
否 是 否 是 否
│ │ │ │ │
SquashFS UBIFS JFFS2 JFFS2 SquashFS
(只读层) (只读层)
选型原则总结
- eMMC/SD 卡 → ext4(读写)或 squashfs(只读)
- 大容量 NAND → UBIFS
- 小容量 NAND → JFFS2
- NOR Flash → JFFS2(小容量)或 SquashFS(只读)
- 需要只读保护 → SquashFS + OverlayFS(上层可写)
四、各文件系统适配方法
4.1 ext4 适配
# 1. 创建 ext4 镜像
dd if=/dev/zero of=rootfs.ext4 bs=1M count=256
mkfs.ext4 -L rootfs rootfs.ext4
# 2. 挂载并填充内容
mkdir -p /mnt/rootfs
sudo mount -o loop rootfs.ext4 /mnt/rootfs
sudo cp -a _install/* /mnt/rootfs/
sudo umount /mnt/rootfs
# 3. 烧录到 SD 卡分区
sudo dd if=rootfs.ext4 of=/dev/sdb2 bs=1M
内核 bootargs 配置:
root=/dev/mmcblk0p2 rootfstype=ext4 rootwait rw
4.2 JFFS2 适配
JFFS2 镜像使用 mkfs.jffs2 工具制作:
# 1. 安装 mtd-utils
sudo apt install mtd-utils
# 2. 制作 JFFS2 镜像
# -p 0x1000000: 镜像大小16MB
# -r rootfs/: 源目录
# -o rootfs.jffs2: 输出文件
# --pad: 填充到指定大小
mkfs.jffs2 \
-s 0x800 \
-e 0x20000 \
-p 0x1000000 \
-d rootfs/ \
-o rootfs.jffs2
# 参数说明:
# -s: 页大小(NAND页大小,2048字节=0x800)
# -e: 擦除块大小(128KB=0x20000)
# -p: 填充到指定大小
# -d: 源目录
# -o: 输出文件
内核 bootargs 配置:
root=/dev/mtdblock2 rootfstype=jffs2 rw
4.3 UBIFS 适配
UBIFS 的制作流程比 JFFS2 复杂,需要两步:先制作 UBIFS 镜像,再封装为 UBI 镜像。
# 1. 制作 UBIFS 镜像
# -m 2048: 最小IO大小(NAND页大小)
# -e 129024: 擦除块大小(128KB减去UBI头开销)
# -c 2048: 最大逻辑擦除块数
# -r rootfs/: 源目录
mkfs.ubifs \
-m 2048 \
-e 129024 \
-c 2048 \
-r rootfs/ \
-o rootfs.ubifs
# 2. 封装为 UBI 镜像
# 需要创建 ubifs.ini 配置文件
cat > ubifs.ini << 'EOF'
[ubifs]
mode=ubi
image=rootfs.ubifs
vol_id=0
vol_size=256MiB
vol_type=dynamic
vol_name=rootfs
vol_alignment=1
vol_flags=autoresize
EOF
# 生成 UBI 镜像
ubinize \
-m 2048 \
-p 128KiB \
-s 2048 \
-O 2048 \
-o rootfs.ubi \
ubifs.ini
关键参数计算:
| 参数 | 含义 | 计算方式 |
|---|---|---|
-m | 最小IO大小 | = NAND 页大小 |
-e | 逻辑擦除块大小 | = 物理擦除块 - 2×(页大小+8) |
-c | 最大LEB数 | = 分区大小 / 逻辑擦除块大小 |
-p | 物理擦除块大小 | = NAND 擦除块大小 |
内核 bootargs 配置:
ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs rw
4.4 SquashFS + OverlayFS 适配
这种方案下,底层 SquashFS 提供只读的系统文件,上层 OverlayFS 提供可写层。常见于 OpenWrt 等路由器系统。
# 1. 制作 SquashFS 镜像
mksquashfs rootfs/ rootfs.squashfs \
-comp xz \
-no-xattrs \
-no-fragments
# 2. 烧录到 Flash 分区
# Flash 分区布局:
# | u-boot | kernel | rootfs(squashfs) | overlay(jffs2) |
# 3. 内核启动后,用 overlayfs 合并可写层
mount -t squashfs /dev/mtdblock2 /rom
mount -t jffs2 /dev/mtdblock3 /overlay
mount -t overlay overlay \
-o lowerdir=/rom,upperdir=/overlay/upper,workdir=/overlay/work \
/mnt
五、NAND Flash 适配注意事项
5.1 分区划分
NAND Flash 通常在设备树中定义分区:
&nand {
partition@0 {
label = "bootloader";
reg = <0x000000 0x100000>; /* 1MB */
};
partition@100000 {
label = "kernel";
reg = <0x100000 0x500000>; /* 5MB */
};
partition@600000 {
label = "rootfs";
reg = <0x600000 0x2000000>; /* 32MB */
};
partition@2600000 {
label = "userdata";
reg = <0x2600000 0x1A00000>; /* 26MB */
};
};
5.2 硬件 ECC 配置
NAND Flash 需要配置 ECC(Error Correction Code)校验方式:
# 查看NAND Flash信息
cat /proc/mtd
dev: size erasesize name
mtd0: 04000000 00020000 "nand-flash"
mtd1: 00100000 00020000 "bootloader"
mtd2: 00500000 00020000 "kernel"
mtd3: 02000000 00020000 "rootfs"
总结
文件系统选型的核心原则:存储介质决定文件系统类型。eMMC/SD 用 ext4,NAND 用 UBIFS 或 JFFS2,NOR 小容量用 JFFS2。如果需要只读保护,SquashFS + OverlayFS 是最佳组合。选对文件系统只是第一步,正确配置分区参数(页大小、擦除块大小、LEB数量)才是成功适配的关键。下一阶段就是打包烧录,让系统真正在板子上跑起来。
更多推荐
所有评论(0)