FTL(Flash Translation Layer,闪存转换层)是 闪存控制器 中把主机看到的逻辑块地址映射到 NAND Flash 物理页的机制,它让 eMMC、UFS 或 SSD 能对外表现为普通块设备。
FTL 的本质是地址映射加维护策略:主机以为自己在覆盖某个 LBA,控制器内部通常是在写新 page、更新映射、回收旧 block。
核心问题
NAND Flash 有“擦除后才能写”和“按 block 擦除”的限制,而主机文件系统会频繁覆盖逻辑扇区。如果每次覆盖都直接擦除物理 block,性能和寿命都会很差。
FTL 要解决:
- 逻辑地址和物理地址分离。
- 更新写入不原地覆盖。
- 无效页越来越多时如何垃圾回收。
- 哪些 block 被频繁擦除,如何配合 磨损均衡。
- 掉电时映射表如何恢复一致。
核心对象
| 对象 | 含义 | 工程关注点 |
|---|---|---|
| LBA | 主机看到的逻辑块地址 | 512B/4KiB 扇区、文件系统请求 |
| physical page | NAND 中实际存数据的位置 | page 大小、block 所属、是否有效 |
| mapping table | LBA 到物理页的映射 | 页级/块级/混合映射、缓存 |
| invalid page | 已被新数据替代的旧页 | 垃圾回收候选 |
| free block pool | 可写空闲块集合 | 空闲不足会造成写延迟毛刺 |
| garbage collection | 垃圾回收 | 搬迁有效页、擦除 block、写放大 |
核心机制
简化的页级映射如下:
write LBA = X, data = D
new_page = allocate_free_page()
program(new_page, D)
old_page = mapping[X]
mapping[X] = new_page
mark_invalid(old_page)allocate_free_page()从空闲块中选择一个可写 page。program(new_page, D)把数据写入 NAND。mapping[X] = new_page让后续读取 LBAX时读新数据。mark_invalid(old_page)表示旧 page 仍在 NAND 中,但逻辑上已经废弃。
当空闲页不足时,FTL 做垃圾回收:
select block B
copy valid pages from B to other free pages
erase B
return B to free block pool如果为了写入 4 KiB 数据,控制器内部额外搬迁了很多有效页,就产生写放大。写放大越高,性能越差,NAND 磨损也越快。
工程用途
- 支撑 eMMC/UFS/SSD 的块设备抽象。
- 让文件系统无需直接管理 NAND page、block 和坏块。
- 配合 TRIM/discard,告诉控制器哪些 LBA 已不再使用,减少垃圾回收压力。
- 通过冷热数据分离和磨损均衡延长设备寿命。
调试时,随机写延迟突然升高、长时间写入后性能下降、满盘后写入变慢,常常和 FTL 垃圾回收、空闲块池和写放大有关。
边界与常见坑
- FTL 不是文件系统:文件系统管理文件和目录;FTL 管理逻辑块到物理 NAND 的映射。
- 主机看不到真实物理布局:同一个 LBA 的物理位置可能不断变化。
- 删除文件不等于控制器知道空间可回收:如果没有 discard/TRIM,FTL 可能仍把那些 LBA 当有效数据。
- 满盘会恶化写放大:空闲块太少时,垃圾回收需要搬迁更多有效页。
- 掉电一致性是控制器能力差异点:映射表更新过程如果保护不好,可能导致数据损坏。