为什么写入过程中掉电、异常复位或 Flash 磨损引起,LittleFS 的失败概率一般会比FAT明显更低?
核心原因不是 LittleFS“不会损坏”,而是它把一次修改设计成:掉电后要么看到旧版本,要么看到完整的新版本,尽量不出现半新半旧的状态。
1. Flash 掉电时为什么容易损坏
Flash 有两个重要特性:
- 写入通常只能把 bit 从
1改成0 - 要恢复成
1,必须先擦除整个 erase block
如果编程或擦除过程中掉电,一个块可能处于不确定状态:
- 一部分字节已经写入,另一部分没有写入
- 擦除只完成了一部分
- 控制器已经返回部分操作,但数据尚未真正稳定
- 单个扇区更新可能在物理层变成“读整块、擦除、重写整块”
异常复位与掉电的效果类似:CPU、DMA 或存储控制器可能在更新元数据的中途停止。
2. FAT 为什么更容易出现“不一致状态”
FAT 更新一个文件通常需要修改多个相互关联的位置。例如向文件追加一个簇:
- 分配新簇
- 在 FAT 表中把新簇标记为已使用
- 修改旧簇的链表指针,使其指向新簇
- 写入新簇的数据
- 修改目录项中的文件大小、时间等
- FAT32 可能还会更新 FSInfo
这些操作通常不是一个原子事务。假设在不同时间掉电:
- 新簇已分配,但目录项未更新:产生丢失簇
- 链表已指向新簇,但数据还没写完:文件包含无效数据
- 文件大小已增加,但簇链还没接好:大小与簇链不一致
- 一份 FAT 表更新了,另一份还没有:两份 FAT 不一致
- 正在重写目录项时掉电:目录项可能部分损坏
标准 FAT 没有事务日志,也没有明确的“这批修改已经完整提交”标志。重新挂载时,文件系统往往难以判断:
- 哪些修改属于同一次操作
- 应该保留旧状态还是新状态
- 两份 FAT 中哪一份才正确
FAT 的两份 FAT 表主要是冗余副本,并不等同于 LittleFS 的两代事务版本。它们通常没有完整的版本选择和事务 CRC 机制。
需要注意:FAT 出现不一致不一定立即挂载失败。很多情况下仍能挂载,但需要 fsck/chkdsk 修复;严重损坏关键元数据时才可能挂载失败。
3. LittleFS 如何应对掉电
写时复制
LittleFS 修改数据时,通常不会先破坏当前有效版本,而是:
- 把新数据写到其他位置
- 写入新的元数据
- 计算并写入提交 CRC
- 完整提交后,新元数据才开始引用新数据
- 之后才回收旧数据
因此:
- 在提交前掉电:新内容被忽略,旧内容仍然有效
- 在提交后掉电:新内容有效
- 提交写了一半:CRC 不通过,挂载时回退到上一次有效提交
这相当于把结果限制为“旧版本”或“新版本”,而不是 FAT 中可能出现的“链表是新的、文件大小是旧的、数据只写了一半”。
元数据对
LittleFS 的重要元数据通常保存在一个 metadata pair 中,即两个块配合使用。
更新过程大致是:
- 当前块中保留有效提交记录
- 新修改以日志形式追加
- 每次提交带有 CRC
- 空间不足时,将有效状态整理到另一个块
- 新块完整有效之前,不销毁旧块
- 通过 revision count 判断哪个块更新
如果掉电发生在整理或切换过程中:
- 新块完整且 CRC 正确:使用新块
- 新块不完整:继续使用旧块
只有两边都无法恢复时,这组元数据才真正不可用。
CRC 提交记录
LittleFS 的 CRC 不只是检查某个字段,它还用于识别一次提交是否完整。
例如写入到一半时:
挂载时会扫描到最后一个完整且 CRC 正确的提交,将不完整的新提交丢弃。
CRC 的作用是检测损坏,不是修复任意损坏;真正保证可恢复的是“旧版本仍保留 + 新版本验证通过才生效”。
4. 异常复位为什么也是 LittleFS 更可靠
异常复位包括:
- 看门狗复位
- 软件崩溃后重启
- CPU lockup
- 总线错误
- 用户强制重启
只要复位发生在文件系统写入期间,对存储介质来说与掉电类似。LittleFS 的提交边界可以让挂载过程识别最后一次完整事务。
不过应用仍应正确调用:
lfs_file_sync()lfs_file_close()lfs_unmount()
LittleFS 保证的是文件系统结构尽量保持一致,不保证尚未 sync/close 的最新业务数据一定保存。掉电后可能丢失最后一次提交,但通常仍可挂载。
5. Flash 磨损方面为什么 LittleFS 更有优势
Flash 擦除次数有限,例如 NOR Flash 某个 erase block 可能只能承受数万到十万次擦除。
FAT 存在明显的热点区域:
- FAT 表
- 根目录或频繁更新的目录
- FSInfo
- 高频修改文件的目录项
即使文件数据分布在整个分区,少量关键元数据块也可能被反复重写。某个关键块先磨损,就可能造成严重损坏。
LittleFS 针对这种情况提供动态磨损均衡:
- 文件数据从空闲块中循环分配
- 元数据以追加方式写入,减少每次修改都擦除同一位置
- 元数据经过一定更新次数后可以迁移到其他块
block_cycles等参数可控制元数据迁移频率- 底层报告编程或擦除错误时,可以尝试放弃问题块并迁移
因此擦除次数会更均匀地分布,而不是长期集中在几个 FAT 热点块上。
但 LittleFS 不能替代:
- NAND ECC
- 坏块管理
- 电压稳定设计
- 正确的 Flash 驱动
- 存储控制器 cache flush
6. 为什么只能说“概率更低”
LittleFS 仍可能挂载失败,例如:
- 根元数据对的两个块都损坏
- 驱动报告写成功,但实际上数据没有落盘
read_size、prog_size、block_size配置错误- 固件升级后修改了 LittleFS 几何参数
- Flash 出现无法被 ECC 修复的位错误
- RAM 越界或错误地址写坏文件系统分区
另外,如果 FAT 位于 SD 卡、eMMC 或带 FTL 的设备上,底层控制器已经提供磨损均衡和一定的掉电保护,LittleFS 相对 FAT 的优势会缩小。
最终可以概括为:
所以对裸 NOR Flash、频繁写入、可能随时复位的嵌入式设备,LittleFS 通常比标准 FAT 更不容易因文件系统结构损坏而挂载失败。

浙公网安备 33010602011771号