第4章:FTL(闪存转换层)详解

FTL,全称Flash Translation Layer,闪存转换层。说白了,它就是NAND Flash和文件系统之间的「翻译官」。文件系统只认识逻辑地址,而NAND只认识物理地址。FTL干的事,就是把这两者打通。

我刚开始接触车载存储时,总觉得FTL就是个地址映射表,没什么了不起。后来踩了坑才发现——FTL的算法好坏,直接决定了你的存储系统能用3年还是3个月。嗯,这话一点不夸张。

4.1 逻辑地址到物理地址映射

这是FTL最核心的功能。文件系统发来一个LBA(逻辑块地址),FTL要把它翻译成PBA(物理块地址)。

映射的粒度很关键。常见的映射方式有三种:

映射方式 粒度 优点 缺点
页级映射 4KB 灵活,写放大小 映射表大,占内存
块级映射 512KB 映射表小 写放大严重
混合映射 页+块 折中方案 实现复杂

我个人习惯在车载项目里用页级映射。为什么?因为车载场景下随机写入很多,页级映射能有效降低写放大。代价就是内存占用大一点——但现在的车规级SoC,内存已经不是瓶颈了。

关键点:映射表必须掉电不丢失。我见过一个项目,FTL的映射表只存在DRAM里,结果一次掉电,整块盘的数据全废了。后来我们强制要求:映射表必须定期刷到NAND的预留区域。

4.2 垃圾回收

NAND有个特性:写入前必须先擦除。而擦除的最小单位是块(Block),不是页(Page)。这就带来了一个问题——你更新了一个4KB的数据,原来的物理页就变成了「脏页」。时间长了,整个块里全是脏页,必须回收。

垃圾回收的流程大致是这样:

  1. 选一个脏页最多的块
  2. 把块里还「活着」的有效页读出来
  3. 写到另一个空闲块里
  4. 擦除原块,标记为空闲

听起来简单,但坑很多。我曾经在一个项目里遇到过:垃圾回收太激进,导致前台写入延迟飙升。用户操作导航时,地图加载卡了3秒——这在车上是不能接受的。

我的建议:车载场景下,垃圾回收一定要做「后台静默回收」。利用系统空闲时间,比如车停着的时候,慢慢回收。别等到写入请求来了才临时抱佛脚。

4.3 磨损均衡

NAND Flash的擦除次数是有限的。SLC大约10万次,MLC 3000-5000次,TLC只有1000-1500次。车载设备要用10年,如果某些块被频繁擦写,它们会先「挂掉」。

磨损均衡分两种:

  • 动态磨损均衡:只在写入时做均衡。新数据尽量写到擦除次数少的块上。
  • 静态磨损均衡:连那些长期不动的「冷数据」也要搬走,把它们的块腾出来给新数据用。

你想想看,车载系统里有很多冷数据——比如导航地图的静态数据、系统固件。这些数据写入一次后,可能几年都不更新。如果不做静态磨损均衡,这些块永远不被擦写,而日志分区那些块却一直在磨损。结果就是:日志分区先坏,整块盘报废。

注意:静态磨损均衡会引入额外的写入放大。我见过一个方案,为了追求完美的均衡,把冷数据搬来搬去,结果写放大到了5倍以上。嗯,过犹不及。车载场景下,建议把磨损差异控制在20%以内就够了。

4.4 坏块管理

NAND出厂时就可能有坏块,使用过程中还会产生新的坏块。这是NAND的「天生缺陷」,没办法。

坏块管理分两个层面:

出厂坏块:厂商会在每个块的第一个页的备用区标记坏块信息。FTL初始化时,扫描所有块,把标记为坏块的加入黑名单。

运行时坏块:使用过程中,如果某个块擦写失败或写入失败,FTL要能检测出来,并把它标记为坏块。同时,把有效数据迁移到备用块。

我遇到过最头疼的问题:坏块标记被误擦除。有一次,某个固件升级程序把备用区也格式化了,结果所有坏块标记都没了。系统把坏块当成好块用,数据写进去就读不出来。从那以后,我要求所有项目必须把坏块表单独存一份,放在NAND的保留区域,并且要有CRC校验。

实战经验:车载系统建议预留2%-3%的备用块。别省这个空间,关键时刻能救命。我见过一个项目,为了省成本只留了0.5%,结果用了两年后坏块爆发,系统直接挂了。

4.5 写在最后

FTL这东西,说复杂也复杂,说简单也简单。但有一点我特别想强调:别把FTL当成黑盒。很多车载工程师觉得FTL是NAND厂商的事,自己只管调接口。结果出了问题,连日志都看不懂。

我建议你至少搞清楚:你的FTL用的是页级映射还是块级映射?垃圾回收的触发阈值是多少?磨损均衡的差异容忍度是多少?这些参数,在车载项目里都是可以调的。

下一章,我们会聊文件系统选型。到时候你会发现,FTL和文件系统是「搭伙过日子」的关系——选对了,事半功倍;选错了,互相拖累。