2. Buildroot文件系统框架:BR2_TARGET_ROOTFS_* 配置体系,如何选择文件系统类型

好,咱们进入第二个章节。这一节我打算聊聊Buildroot里那个让人又爱又恨的配置体系——BR2_TARGET_ROOTFS_*

说实话,我第一次接触这个配置项的时候,看着那一长串选项,心里直犯嘀咕:怎么这么多文件系统类型?选错了会不会把板子搞成砖?后来踩过几次坑,才慢慢摸清了门道。

2.1 配置体系概览:BR2_TARGET_ROOTFS_* 到底在管什么?

简单来说,BR2_TARGET_ROOTFS_* 就是Buildroot用来决定「最终生成什么格式的根文件系统镜像」的那组配置开关。你想想看,我们编译完内核、装好各种应用,总得有个东西能塞到Flash或者SD卡里让板子跑起来吧?对,就是它。

make menuconfig 里,你会在 Filesystem images 菜单下找到这些选项。它们长这样:

Filesystem images --->
    [*] ext2/3/4 root filesystem
    [ ] cramfs root filesystem
    [ ] squashfs root filesystem
    [ ] ubifs root filesystem
    [ ] jffs2 root filesystem
    [ ] tar root filesystem
    [ ] cpio root filesystem
    ...

每个选项背后,都对应着一套完整的打包脚本和参数配置。你勾选了哪个,Buildroot就会在编译结束后,调用对应的工具链去生成那个格式的镜像。

核心要点:BR2_TARGET_ROOTFS_* 不是让你「选一个」,而是可以「选多个」。我见过不少新手以为只能单选,结果只生成了一种格式,后面调试时发现烧录工具不支持,又得重新编译——白白浪费一两个小时。

2.2 主流文件系统类型对比:选型前的必修课

咱们来看看最常见的几种文件系统类型。我按使用场景把它们分成了三类:

文件系统类型 适用存储介质 压缩支持 可写性 典型场景
ext2/3/4 SD卡、eMMC、硬盘 可读写 开发板、通用Linux
squashfs Flash、SD卡 是(gzip/lzma/lzo) 只读 嵌入式只读根文件系统
ubifs NAND Flash 是(LZO/zlib) 可读写 NAND Flash设备
jffs2 NOR/NAND Flash 是(zlib) 可读写 老旧Flash设备
cramfs Flash、ROM 是(zlib) 只读 极小系统、老旧内核
cpio 内存(initramfs) 内存中可写 早期启动、急救系统
tar 任意(打包格式) 是(gzip/bzip2/xz) N/A 分发、备份、二次处理

这张表我建议你收藏一下。每次做新项目,拿出来对照着看,选型思路会清晰很多。

2.3 如何选择:我的实战决策流程

我个人习惯按下面这个顺序来决策:

  1. 先看存储介质——是NAND Flash、NOR Flash、eMMC还是SD卡?
  2. 再看容量限制——存储空间够不够?需不需要压缩?
  3. 最后看运行需求——根文件系统需要可写吗?还是只读就够了?

举个例子。我在做一个工业控制器的项目时,用的是128MB的NAND Flash。当时我第一反应是选jffs2,毕竟它支持NAND嘛。但后来发现jffs2在挂载大分区时慢得让人抓狂——128MB的分区,第一次挂载要等将近两分钟。后来我换成了ubifs,挂载时间缩短到几秒钟。嗯,这里要注意:ubifs需要内核开启UBI支持,而且对NAND的坏块管理更智能。

我的建议:

  • 如果存储介质是 eMMC或SD卡,优先考虑 ext4。性能好,工具链成熟,调试方便。
  • 如果存储介质是 NAND Flash,优先考虑 ubifs。jffs2只建议在老旧内核(2.6.x)上使用。
  • 如果存储介质是 NOR Flash,jffs2 或 squashfs 都可以,看是否需要可写。
  • 如果 空间极度紧张(比如只有4MB),squashfs 配合高压缩比算法是首选。
  • 如果系统需要 从内存启动(比如急救模式),cpio 格式的 initramfs 是标配。

2.4 配置实战:在Buildroot中设置文件系统类型

好,理论说完了,咱们来点实际的。假设你手头有一个项目,用的是NAND Flash,需要可读写的根文件系统。我会这样配置:

# 进入配置界面
make menuconfig

# 进入文件系统镜像菜单
Filesystem images --->
    [*] ubifs root filesystem
        (0x20000) UBI logical erase block size    # 根据NAND的页大小调整
        (2048)   UBI minimum I/O unit size        # 通常等于NAND页大小
        (1)      UBI sub-page size                # 有些NAND支持子页
        (0x1f000) UBI physical erase block size   # 通常等于NAND块大小
    [*] tar root filesystem                       # 同时生成tar包,方便调试

这里有个坑,我曾经踩过:UBI的LEB(Logical Erase Block)大小如果设置不对,生成的ubifs镜像在烧录后根本挂载不上。怎么算?公式很简单:LEB = PEB - 2 * 页大小。比如你的NAND块大小是128KB(0x20000),页大小是2KB(0x800),那么LEB就是 0x20000 - 2 * 0x800 = 0x1F000。

注意:如果你同时勾选了多个文件系统类型,Buildroot会依次生成对应的镜像文件。但要注意,它们之间是独立的,不会互相影响。比如你同时选了ext4和squashfs,最终会得到 rootfs.ext4rootfs.squashfs 两个文件。

2.5 选型避坑指南

做嵌入式存储优化这么多年,我总结了几条血泪教训:

  • 别盲目追求压缩率——squashfs的zstd压缩比gzip高,但解压速度慢。如果你的CPU主频只有200MHz,解压时间可能比读取时间还长。
  • 注意内核配置——选了ubifs,别忘了在内核里开启UBI和UBIFS支持。我见过有人折腾了半天ubifs镜像,结果内核根本没编译进去——白忙活。
  • tar格式不是用来直接跑的——它只是个打包格式,方便你解压到目标分区。别想着把tar包直接当根文件系统用。
  • cpio格式的initramfs有大小限制——早期内核可能只支持几MB的initramfs,太大了会启动失败。

我曾经在一个项目里,为了省那几百KB的空间,选了cramfs。结果发现cramfs不支持4KB以上的文件,而且最大文件系统大小只有256MB。后来产品迭代,固件体积涨到了300MB,cramfs直接废了,不得不重新选型。所以我的建议是:除非你的系统真的小到极致,否则别碰cramfs,squashfs是更好的选择。

2.6 小结

这一节我们聊了Buildroot的BR2_TARGET_ROOTFS_*配置体系。说白了,选文件系统类型就是三个问题:用什么存?空间多大?要不要写?想清楚这三点,选型就不难了。

下一节我会深入讲讲文件系统的裁剪技巧——怎么把根文件系统从几十MB砍到几MB,同时保证功能完整。到时候我会拿一个实际项目做案例,一步步演示裁剪过程。