资讯动态

NAND坏块管理与BBT核心逻辑:从原理到工程落地指南

发布时间:2026/10/20 16:32:28 来源:尧图企业网站定制
做嵌入式存储相关的开发不管是写裸NAND驱动、搭文件系统还是选型eMMC芯片迟早都会撞上一个绕不开的话题——坏块管理。这个词听起来像给数据存储做“安检”但它实际上是贯穿NAND Flash整个生命周期的基本功。我刚开始接触的时候也以为坏块管理就是单纯把坏块找出来做个标记后来在轻视它这件事上栽了不少跟头。这篇内容就围绕BBT坏块表和坏块管理的核心逻辑展开用贴近实操的方式说清楚NAND为什么必然会产生坏块、BBT是怎么运作的、不同方案下坏块管理到底该怎么落地。适合刚入行的嵌入式软件工程师也适合准备把存储方案做到产品级的开发者。1. NAND的物理宿命为什么坏块是躲不掉的1.1 一个数据单元是怎么“累死”的NAND Flash的存储单元本质上是一个浮栅晶体管数据是靠电荷存在浮栅里来表达的。写入时电子被强电场穿过隧穿氧化层注入浮栅擦除时又用相反的电压把这些电子拉出来。问题就出在这个“穿来穿去”的过程上。每做一次编程/擦除循环隧穿氧化层就会被“搓”掉一层。次数多了氧化层变薄、漏电、锁不住电荷这个单元的可靠性就越来越差直到彻底无法判断里面存的是0还是1。这就像一张纸反复铅笔写、又反复擦掉重写擦到最后纸面起毛、破洞再怎么写也写不成型了。这个过程不是说整个芯片一起坏而是按块Block为单位逐步恶化的。NAND的最小读单元是页Page最小擦除单元是块Block一块通常包含64、128甚至几百个页。只要一个块里的关键单元坏了导致这个块没法被可靠擦除或写入那这个块基本上就宣告报废。1.2 坏块的正式判定不是你想坏就能坏工程上判断一个块是不是坏块靠的是操作结果和ECC校验而不是靠肉眼观察编程/写入失败往某个页写数据时状态寄存器回报编程失败。这类失败通常意味着整个块已经处于不可用状态。擦除失败擦除操作回报失败这个块基本无药可救。ECC纠错无法容忍读取时数据错误比特数超过ECC能力上限说明这个块的电荷保持能力已经崩了。坏块管理的核心对象就是以块为单位的这些东西。有不少人第一次接触NAND时习惯把坏块理解成“硬盘的坏道”这个类比其实不太准。坏道往往是一个扇区坏了还能隔离掉而NAND的坏块是物理上“一整块”不可用而且坏掉的块数量会随着使用时间持续增长不是一个恒定值。2. 出厂坏块与运行期坏块两种语境下的同一件事2.1 出厂坏块原厂已经帮我们做了标记NAND出厂时就不是完美的。原厂在晶圆制造、切割、封测阶段就能检测出一部分不合格的块。这不是成品没做好而是工艺上允许有一定比例的不良品存在。比较有意思的是随着制程不断微缩出厂坏块的比例反而在上升。以前SLC时代出厂坏块可能也就千分之几到了TLC、QLC时代1%~2%甚至更高的出厂坏块比例都很常见原厂会在芯片出厂前把这些坏块状态“烧”到一个固定位置。最常见的标记方式是在块内第一个页的OOB区域带外区域固定偏移位置写入非0xFF的值。比如某个行业约定俗成的规则把OOB里特定字节写成0x00代表坏块保留0xFF代表好块。原厂还会多写几处重复标记防止标记位置本身被破坏后读不出来。2.2 运行期坏块系统运行中的拦截信号出厂坏块是“天生的”运行期坏块则是“用坏的”。系统运行中主要靠两类信号发现新坏块第一类是操作层回报的硬错误。比如文件系统往某个块发擦除命令返回擦除失败往某个页发写命令返回编程失败。这些都是硬性的物理故障信号基本不用怀疑直接标记坏块就行。第二类要靠ECC状态位来判断。NAND的页读取通常会返回ECC纠错情况如果当前页的错误比特数已经逼近甚至超过ECC阈值这通常是一个预警信号。行业里一般不会马上把它当成坏块处理而是尝试把这个块的数据搬走、做一次擦除如果擦除还失败再确定坏块。这个“二次确认”流程能有效减少误判毕竟有些时候只是电荷发生暂时性偏移重新擦写后还能继续用。2.3 两种坏块的管理权重差异从管理策略上看出厂坏块属于静态信息产品出厂前处理好就行运行期坏块则是动态事件整个生命周期都要盯。下面这个表格可以把两者的差异看得很清楚对比维度出厂坏块运行期坏块来源制造环节的工艺缺陷擦写磨损、电荷泄漏、环境干扰特点数量固定出厂时已确定数量随P/E次数增长而增加获取方式读OOB区域的原厂标记操作失败、ECC阈值告警处理阶段设备初始化阶段扫描并建立BBT运行中实时监测并动态更新BBT误判风险低标记固定较高需要二次确认很多嵌入式工程师只重视出厂坏块的扫描对运行期坏块的动态更新不够上心这是后面会踩大坑的地方。3. BBT的内核逻辑一张表如何撑起整片存储的可靠性3.1 BBT到底记了什么BBT的全称是Bad Block Table坏块表。它的本质很简单用一张结构化的记录标记出哪几个块是坏的哪几个块是好的。常见的表项记录内容有这么几类块编号或物理地址让人能定位到具体哪个块。坏块状态0表示好块1表示坏块也可以用枚举值细分坏的原因。发现时间或原因标识像是出厂坏块还是运行期新损坏方便后期做统计分析和寿命预测。保留字段为以后扩展留位置比如记录被替换的备用块映射关系。BBT可以有不同形态。最简单的是位图形式一个bit对应一个块稍微复杂一点的是引导区形式记录每个块的详细状态。位图形式省空间、查询快但信息量少引导区形式占用大一点但能承载更多现场信息。实际产品里两者经常结合使用位图做索引、详细记录做兜底。3.2 BBT自己放在哪里才安全这里的核心矛盾是BBT是用来记录坏块的但存放BBT的区域自身也存在坏块风险。如果把BBT放在固定的一个块里这个块坏了BBT就全丢了。行业里通用的做法是冗余副本加分散放置多个副本通常存放2到4份分散在不同Plane、不同Die或不同分区。写入仲裁每次更新时按序写入副本并带序列号或CRC校验。读取时取校验通过且序列号最新的那份。动态搬迁如果发现某个BBT存放块开始出现ECC告警就主动把BBT搬到一个健康的保留块里并更新指针。这些思路和数据库的WAL预写式日志有点相似核心思想都是“不能把鸡蛋放在一个篮子里”。有些方案甚至会把BBT管理器体本身做成一个小文件系统专门管理这些系统块这样可扩展性更强但复杂度也高不少。3.3 BBT什么时候更新、怎么防止更新丢一半BBT不是启动时读一次就完事它在运行中是持续演变的。触发更新的典型时机包括某个块在擦除、编程时失败确认坏块后立即更新。后台巡检发现ECC错误率异常升高完成了坏块替换后更新。磨损均衡模块切换活跃块更新映射关系。这里最容易出问题的是更新过程中的掉电。假如正在往BBT块里写新数据写到一半突然断电老数据被覆写了一部分新数据也没写完BBT直接就“残废”了。行业里的通用做法是双页交替写保留上一版有效BBT把新版本写在另一个位置写完后再做一个切换标记。下次启动时先读切换标记再决定用哪个版本。如果两个版本都校验失败那就只能回到出厂扫描状态——意味着所有运行期的坏块记录全部丢失系统不得不重新全盘扫描这在量产设备里属于重大事件。4. 坏块管理的三种主流策略与选择权衡4.1 跳过坏块最朴素也最常见跳过策略很好理解就是通过BBT查询到坏块地址后在寻址时直接跳到下一个可用块。这种方案不需要维护复杂的映射表逻辑简单、开销低对工程量有限的产品很友好。但它的缺点也很明显。因为物理地址的连续性破坏了逻辑块号和物理块号之间无法一一对应。如果上层文件系统直接按连续物理地址计算偏移就会踩到坏块上。所以跳过策略一般得配合某种地址转换层至少是一个简单的“逻辑块号到物理块号”的重排序表。4.2 重映射与保留块池FTL层的基本功更专业的方案是引入FTL闪存转换层把逻辑块号映射到物理块号并在芯片出厂时就划出一块保留块池。当某个活跃块损坏时FTL从保留块池里选一个新块把旧块里的有效数据搬过去然后更新映射表。这个过程对上层来说是透明的。这套机制最大的优势是分布更均衡不会因为个别坏块导致空间利用率断崖式下降。但代价是FTL本身复杂度高映射表也要占用一部分NAND空间还得时刻处理映射表的持久化问题。尤其到了掉电恢复场景如果映射表丢了后果比BBT丢失还严重整个用户文件系统都可能无法挂载。4.3 策略选择的现实权衡我做过几次选型对比简单总结一下三种策略的适用场景策略实现难度NAND利用率运行开销适合场景跳过坏块低中等低裸NAND自主文件系统、数据可重建场景地址重映射中较高中需要随机读写性能的小型设备保留池磨损均衡高高较高追求长寿命、高可靠性的产品级方案需要注意的是选择策略时不能只盯着“坏块怎么办”这一个问题还得和磨损均衡、掉电保护、垃圾回收这些功能综合起来考虑。比如一个产品的数据更新频率很高那磨损均衡的重要性可能远大于坏块替换反过来如果产品生命周期短、写入量少复杂的FTL层反而可能因为映射表写入放大而加速磨损。5. 裸NAND与带主控存储玩法的分水岭5.1 裸NAND从启动阶段就要自己扛如果方案用的是裸NAND没有内置主控的Flash芯片那坏块管理就是嵌入式软件自己躲不开的工作。难点在于从Boot阶段开始就得处理坏块因为引导代码本身也放在NAND里。常见做法是把引导代码分成多份冗余存放BootROM加载第一份失败后尝试第二份。同时Boot阶段的代码要尽量小能塞进几个块中不跨坏块。等主系统运行起来再加载完整BBT进入工作模式。曾有团队在某个项目里把Boot分区紧挨着一块出厂坏块放置反复测试几十次没问题结果量产某批次芯片因为坏块位置偏移直接导致一批设备刷机后起不来。这就是跳过策略下没做冗余引导的典型事故。5.2 eMMC/UFS主控替你扛但你仍要懂对于eMMC和UFS这类带主控的存储坏块管理和磨损均衡大多数已经由内部FTL处理了。上层开发者不用再去扫描出厂坏块也不需要维护BBT看起来很省心。但省心不意味着可以无知。带主控的存储依然有寿命上限而且内部容量里面还藏着一块保留空间专门给坏块替换和磨损均衡用。当主控内部保留块消耗殆尽芯片就会出现大量写入失败或强制只读。所以就算用eMMC我也建议在产品里保留SMART数据的读取通道监控平均擦写次数和重映射块数。不然设备突然间批量变砖排查起来很痛苦。5.3 几个容易混淆的判断我经常看到有人把“裸NAND”和“eMMC”混为一谈这里有几个判断上的关键分歧点第一裸NAND没有统一的状态汇报接口坏块信息只能靠上层扫描或原厂标记eMMC有标准状态寄存器可以查询寿命和重映射情况。第二裸NAND的坏块管理策略完全取决于自己代码的健壮性换了主控方案后代码基本可以复用eMMC的方案则依赖于主控厂商实现质量换供应商后行为可能有细微差异。第三裸NAND对掉电非常敏感映射表丢失风险高eMMC由于有内置电容和固件保护机制掉电容错性要好得多但也不是100%免疫。6. 实战里最容易踩的四个坑6.1 坏块表更新的掉电瞬间我们在某个模拟项目X里调试了很久最后发现问题出在BBT更新流程。当时为了图省事BBT只有一个副本每次更新都是直接擦除原块再写新内容。结果设备在频繁掉电测试下大概每几百次就会遇到一次BBT校验失败。原因很简单擦除原块后新数据还没写完电就断了整个表变成了空白。后来改成双副本轮流写并增加“当前有效版本”标志位这个问题基本清零。经验是坏块表的更新流程里必须有一个原子切换动作不能存在“中间状态可被识别为有效”的窗口。6.2 上电全盘扫描的正确打开方式每次上电都做全盘扫描最稳妥但代价很大。一片中等容量的MLC NAND全盘读一遍可能要好几十秒很多产品根本接受不了这个启动时间。更实用的办法是把扫描拆成两级启动阶段只扫描出厂坏块标记区和最近记录的BBT快速进入工作状态后台再慢慢做全量巡检发现新坏块再动态更新。当然前提是文件系统访问NAND的路径本来就要走统一的坏块查询接口否则后台扫描还没跑完某个坏块可能已经被读过了。6.3 出厂坏块标记的重复判断陷阱原厂标记一般在OOB区域重复写好几份目的是防止某个标记位置被意外改写。但我见过一些代码只判断第一个标记位置一旦那个位置损坏明明是坏块却被当成好块写入后就出现数据打水漂的情况。正确做法是检查多个标记位置并设定判定规则比如“任意一个标记为非0xFF即视为坏块”或者“多数标记一致才判定”。后一种更稳健但要注意有些原厂在擦除后会把标记区一起擦成0xFF这会导致“重复擦除后标记消失”的假象。所以这块逻辑一定要基于原厂手册仔细核对不能想当然。6.4 放久了不读的盘坏块会“变多”这是我在售后数据里发现的一个反直觉现象。一批设备存放了几个月后开机发现坏块数量比出厂时多了不少。起初怀疑是器件批量问题后来排查才发现是电荷泄漏。长时间断电状态下NAND单元里的电荷会慢慢衰减导致读取时ECC错误变多。如果错误率超过阈值巡检程序就会把这类块标记成坏块。处理办法有两条一是产品在长期存储前尽量把数据重新刷写一遍给电荷“续个命”二是巡检判坏时不要把一次性读取错误直接定性为永久坏块可以加一个“擦除-重写-再验证”的流程。很多时候擦写一次之后块又能正常用了。从我个人的实际经验看坏块管理做得好的项目不一定代码写得有多花哨而是把每一条边界条件都想清楚了。比如掉电时序、扫描时机、误判保护、冗余策略这些环节单独看都不难难的是一起发生时系统依然能自洽。刚开始做嵌入式存储时我也犯过“一张表打天下”的毛病总觉得坏块管理就是启动时扫一次、查表跳过去就行后来面对现场设备才明白真正的可靠性是靠一层层冗余和兜底逻辑堆出来的。如果你正在设计存储方案不妨先把这篇文章里提到的边界场景列成一份检查清单逐条对照自己的实现大概率能省下不少返工的功夫。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑