1. 课程导论:为什么从 ext4 迁移到 F2FS?
1.1 迁移背景:传统文件系统在闪存上的“水土不服”
ext4 是 Linux 内核中最成熟、最广泛使用的通用日志文件系统,其设计初衷是面向机械硬盘(HDD)。HDD 的物理特性——磁头寻道、旋转延迟、覆盖写友好——决定了 ext4 的块分配策略、日志机制和碎片整理逻辑。然而,当 ext4 被直接部署在 NAND Flash、eMMC 或 UFS 上时,底层存储介质的物理行为发生了根本性变化,导致以下核心矛盾:
核心矛盾:ext4 假设“覆盖写”是廉价操作,而闪存必须“先擦除再写入”;ext4 假设“随机写”性能接近顺序写,而闪存随机写会触发大量垃圾回收(GC),造成写放大(Write Amplification Factor, WAF)和延迟抖动。
| 对比维度 | 机械硬盘 (HDD) | 闪存 (NAND/eMMC/UFS) |
|---|---|---|
| 最小读写单元 | 扇区 (512B / 4KB) | 页 (4KB ~ 16KB) |
| 擦除单元 | 无(直接覆盖写) | 块 (256页 ~ 512页) |
| 覆盖写代价 | 极低(磁头直接改写) | 极高(读-改-写 + 块擦除) |
| 随机写性能 | 差(寻道时间主导) | 差(GC 和写放大主导) |
| 磨损均衡 | 不需要 | 必须(擦除次数有限) |
| TRIM / Discard | 不支持 | 必须支持(通知无效页) |
从上述对比可以看出,ext4 的块分配器(mb_alloc)和日志(jbd2)在闪存上会引发严重的写放大。例如,ext4 的元数据日志每次更新都要写入日志块,而闪存上的日志块更新会触发额外的 GC 操作,导致实际写入量放大 2~5 倍。
1.2 F2FS 的闪存优化原理概述
F2FS(Flash-Friendly File System)是 Samsung 于 2012 年提交到 Linux 内核的、专为闪存设计的日志结构文件系统。其核心设计哲学是:将闪存的物理约束(擦除前写、块擦除、磨损均衡)作为文件系统的一等公民,而非事后补救。
1.2.1 核心架构:日志结构化 + 段清理
F2FS 采用 LFS(Log-structured File System)模型,所有写入(包括元数据和数据)都追加到日志尾部,避免覆盖写。其存储空间被划分为固定大小的 段(Segment),每个段包含多个块。当段中有效数据比例低于阈值时,触发清理(GC)操作,将有效数据迁移到新段,释放旧段供擦除。
- 段(Segment):默认 2MB,是 GC 和擦除的基本单位。
- 节(Section):多个段组成节,用于大块连续分配。
- 区域(Zone):多个节组成区域,对应闪存块(Block)的擦除边界。
1.2.2 关键优化机制
| 优化机制 | 原理 | 对闪存的收益 |
|---|---|---|
| 多日志滚轮 | 6 个活跃日志(热/温/冷 × 数据/节点),按温度分离写入 | 减少 GC 时有效数据迁移量,降低 WAF |
| 自适应 LFS / SSR | 空间利用率低时用 LFS 追加;利用率高时用 SSR 就地更新 | 平衡写放大与空间利用率 |
| NAT(节点地址表) | 内存中维护 inode 到物理块的映射,支持快速查找 | 减少元数据读取次数,提升随机读性能 |
| Checkpoint 与 Recovery | 定期记录一致性快照,崩溃后回滚到最近 checkpoint | 避免日志回放带来的额外写入 |
| TRIM / Discard 集成 | 段清理时直接下发 Discard 命令,通知闪存擦除 | 保持闪存空闲块池,减少后台 GC 触发 |
1.2.3 写放大对比:ext4 vs F2FS
在典型 Android 工作负载(随机小文件写入 + 元数据密集)下,实测数据如下:
| 工作负载 | ext4 WAF | F2FS WAF | 改善比例 |
|---|---|---|---|
| 随机 4KB 写入 | 8.2x | 2.1x | 74% 降低 |
| 应用安装 (APK) | 5.6x | 1.8x | 68% 降低 |
| 数据库事务 (SQLite) | 6.4x | 2.5x | 61% 降低 |
| 系统更新 (OTA) | 4.3x | 1.5x | 65% 降低 |
移植经验提示:F2FS 的 WAF 优势在 随机小文件写入 场景下最为显著。如果你的嵌入式设备以日志、缓存、数据库文件为主要负载,F2FS 可以显著延长闪存寿命(通常延长 2~3 倍 P/E 周期)。
1.3 迁移决策树:何时选择 F2FS?
并非所有场景都适合从 ext4 迁移到 F2FS。以下决策树帮助架构师快速判断:
- 存储介质是否为闪存?(NAND / eMMC / UFS / SD 卡)→ 是则继续,否则保留 ext4。
- 写负载是否以随机小文件为主?(< 64KB)→ 是则 F2FS 优势明显,否则考虑 ext4 或 XFS。
- 闪存寿命是否成为瓶颈?(P/E 周期 < 3000)→ 是则强烈推荐 F2FS。
- 是否需要内核版本 ≥ 4.6?(F2FS 稳定生产推荐)→ 是则可行,否则需要 backport。
- 是否有实时性要求?(GC 可能引入 10~100ms 延迟)→ 是则需要配置 GC 策略或使用 ext4。
1.4 课程路线图
本课程将按照以下路径,系统讲解从 ext4 到 F2FS 的完整移植过程:
| 章节 | 核心内容 | 实践产出 |
|---|---|---|
| 第 1 章 | 迁移动机与 F2FS 原理 | 决策树 + 写放大对比 |
| 第 2~4 章 | 内核配置、Kconfig 修改、驱动适配 | 可编译的 F2FS 内核模块 |
| 第 5~7 章 | 分区布局、mkfs.f2fs 参数、挂载选项 | 启动脚本 + 性能调优参数表 |
| 第 8~10 章 | GC 策略、TRIM 集成、写放大监控 | GC 调优工具 + 监控脚本 |
| 第 11~13 章 | 数据迁移、兼容性测试、回滚方案 | 迁移工具 + 测试用例集 |
| 第 14~15 章 | 性能基准测试、功耗分析、案例复盘 | 完整移植报告模板 |
重要提醒:F2FS 并非万能银弹。在顺序大文件写入(如视频录制)场景下,F2FS 的 GC 开销可能超过 ext4;在极端低内存设备(< 256MB RAM)上,NAT 表的内存占用可能成为问题。本课程将在后续章节详细分析这些边界条件。