您之前可能听说过 Journaling Flash File System(JFFS)和 Yet Another Flash File System(YAFFS),但是您知道使用底层 flash 设备的文件系统意味着什么吗?本文将向您介绍 Linux? 的 flash 文件系统,并探索它们如何通过平均读写(wear leveling)处理底层的可消耗设备(flash 部件),并鉴别各种不同的 flash 文件系统以及它们的基本设计。
固态驱动器当前非常流行,但是嵌入式系统很久以前就开始使用固态驱动器进行存储。您可以看到 flash 系统被用于个人数字助理(PDA)、手机、MP3 播放器、数码相机、USB flash 驱动(UFD),甚至笔记本电脑。很多情况下,商业设备的文件系统可以进行定制并且是专有的,但是它们会遇到以下挑战。
基于 Flash 的文件系统形式多种多样。本文将探讨几种只读文件系统,并回顾目前可用的各种读/写文件系统及其工作原理。但是,让我们先看看 flash 设备及其所面对的挑战。
Flash 内存技术
Flash 内存(可以通过几种不同的技术实现)是一种非挥发性内存,这意味着断开电源之后其内容仍然保持下来。要了解 flash 内存的辉煌历史,请参阅 参考资料。
两种最常见的 flash 设备类型为:NOR 和 NAND。基于 NOR 的 flash 技术比较早,它支持较高的读性能,但以降低容量为代价。NAND flash 提供更大容量的同时实现快速的写擦性能。NAND 还需要更复杂的输入/输出(I/O)接口。
Flash 部件通常分为多个分区,允许同时进行多个操作(擦除某个分区的同时读取另一个分区)。分区再划分为块(通常大小为 64KB 或 128KB)。使用分区的固件可以进一步对块进行独特的分段 — 例如,一个块中有 512 字节的分段,但不包括元数据。
Flash 设备有一个常见的限制,即与其他存储设备(如 RAM 磁盘)相比,它需要进行设备管理。flash 内存设备中惟一允许的 Write 操作是将 1 修改为 0。如果需要撤销操作,那么必须擦除整个块(将所有数据重置回状态 1)。这意味着必须删除该块中的其他有效数据来实现持久化。NOR flash 内存通常一次可以编写一个字节,而 NAND flash 内存必须编写多个字节(通常为 512 字节)。
这两种内存类型在擦除块方面有所不同。每种类型都需要一个特殊的 Erase 操作,该操作可以涵盖 flash 内存中的一个整块。NOR 技术需要通过一个准备步骤将所有值清零,然后再开始 Erase 操作。Erase 是针对 flash 设备的特殊操作,非常耗费时间。擦除操作与电有关,它将整个块的所有单元中的电子放掉。
NOR flash 设备通常需要花费几秒时间来执行 Erase 操作,而 NAND 设备只需要几毫秒。flash 设备的一个关键特性是可执行的 Erase 操作的数量。在 NOR 设备中,flash 内存中的每个块可被擦除 100,000 次,而在 NAND flash 内存中可达到一百万次。
Flash 内存面临的挑战
除了前面提到的一些限制以外,管理 flash 设备还面临很多挑战。三个最重大的挑战分别是垃圾收集、管理坏块和平均读写。
垃圾收集
垃圾收集 是一个回收无效块的过程(无效块中包含了一些无效数据)。回收过程包括将有效数据移动到新块,然后擦除无效块从而使它变为可用。如果文件系统的可用空间较少,那么通常将在后台执行这一过程(或者根据需要执行)。
管理坏块
用的时间长了,flash 设备就会出现坏块,甚至在出厂时就会因出现坏块而不能使用。如果 flash 操作(例如 Erase)失败,或者 Write 操作无效(通过无效的错误校正代码发现,Error Correction Code,ECC),那么说明出现了坏块。
识别出坏块后,将在 flash 内部将这些坏块标记到一个坏块表中。具体操作取决于设备,但是可以通过一组独立的预留块来(不同于普通数据块管理)实现。对坏块进行处理的过程 — 不管是出厂时就有还是在使用过程中出现 — 称为坏块管理。在某些情况下,可以通过一个内部微控制器在硬件中实现,因此对于上层文件系统是透明的。
平均读写
前面提到 flash 设备属于耗损品:在变成坏块以前,可以执行有限次数的反复的 Erase 操作(因此必须由坏块管理进行标记)。平均读写算法能够最大化 flash 的寿命。平均读写有两种形式:动态平均读写 和静态平均读写 。
动态平均读写解决了块的 Erase 周期的次数限制。动态平均读写算法并不是随机使用可用的块,而是平均使用块,因此,每个块都获得了相同的使用机会。静态平均读写算法解决了一个更有趣的问题。除了最大化 Erase 周期的次数外,某些 flash 设备在两个 Erase 周期之间还受到最大化 Read 周期的影响。这意味着如果数据在块中存储的时间太长并且被读了很多次,数据会逐渐消耗直至丢失。静态平均读写算法解决了这一问题,因为它可以定期将数据移动到新块。
系统架构
到目前为止,我已经讨论了 flash 设备及其面临的基本挑战。现在,让我们看看这些设备如何组合成为一个分层架构的一部分(参加图 1)。架构的顶层是虚拟文件系统(VFS),它为高级应用程序提供通用接口。VFS 下面是 flash 文件系统(将在下节介绍)。接下来是 Flash 转换层(Flash Translation Layer,FTL),它整体管理 flash 设备,包括从底层 flash 设备分配块、地址转换、动态平均读写和垃圾收集。在某些 flash 设备中,可以在硬件中实现一部分 FTL 。
图 1. flash 系统的基本架构
Linux 内核使用内存技术设备(Memory Technology Device,MTD)接口,这是针对 flash 系统的通用接口。MTD 可以自动检测 flash 设备总线的宽度以及实现总线宽度所需设备的数量。
Flash 文件系统
Linux 可以使用多种 flash 文件系统。下一小节将解释每种文件系统的设计和优点。
Journaling Flash File System
Journaling Flash File System 是针对 Linux 的最早 flash 文件系统之一。 JFFS 是一种专门为 NOR flash 设备设计的日志结构文件系统。它非常独特,能够解决许多 flash 设备问题,但同时也导致一些新问题。
JFFS 将 flash 设备视为一种循环的块日志。写入 flash 的数据被写到了空间的末尾,开始部分的块则被收回,而两者之间的空间是空闲的;当空间变少时,将执行垃圾收集。垃圾收集器将有效块移动到日志的尾部,跳过无效或废弃块,并擦除它们(参见图 2)。因此这种文件系统可以自动实现静态和动态平均读写。这种架构的主要缺点是过于频繁地执行擦除操作(而没有使用最佳擦除策略),从而使设备迅速磨损。
图 2. 在垃圾收集之前和之后循环日志
挂载 JFFS 时结构细节将读取到内存中,这将延缓挂载时间并消耗更多的内存。
Journaling Flash File System 2
尽管 JFFS 在早期非常有用,但是它的平均读写算法容易缩短 NOR flash 设备的寿命。因此重新设计了底层算法,去掉了循环日志。JFFS2 算法专门为 NAND flash 设备设计,并且改善压缩性能。
在 JFFS2 中,flash 中的每个块都是单独处理的。JFFS2 通过维护块列表来充分地对设备执行平均读写。clean 列表表示设备中的块全部为有效节点。dirty 列表中的块至少包含有一个废弃节点。最后,free 列表包含曾经执行过擦除操作并且可以使用的块。
垃圾收集算法通过合理的方法智能地判断应该回收的块。目前,这个算法根据概率从 clean 或 dirty 列表中选择。dirty 列表的选择概率为 99%(将有效内容移到另一个块),而 clean 列表的选择概率为 1%(将内容移到新的块)。在这两种情况中,对选择的块执行擦除操作,然后将其置于 free 列表(参见图 3)。这允许垃圾收集器重用废弃的块,但是仍然围绕 flash 移动数据,以支持静态平均读写。
图 3. JFFS2 中的块管理和垃圾收集
Yet Another Flash File System
YAFFS 是针对 NAND flash 开发的另一种 flash 文件系统。最早的版本(YAFFS)支持 512 字节页面的 flash 设备,但是较新的版本(YAFFS2)支持页面更大的新设备以及更大的 Write 限制。
大多数 flash 文件系统会对废弃块进行标记,但是 YAFFS2 使用单调递增数字序列号额外地标记块。在挂载期间扫描文件系统时,可以快速标识有效的 inode。YAFFS 保留在 RAM 中的树以表示 flash 设备的块结构,包括通过检查点(checkpointing)实现快速挂载 — 这个过程将在正常卸载时将 RAM 树结构保存到 flash 设备,以在挂载时快速读取和恢复到 RAM(参见图 4)。与其他 flash 文件系统相比,YAFFS2 的挂载时性能是它的最大优势。
图 4. YAFFS2 中的块管理和垃圾收集
只读式压缩文件系统
在某些嵌入式系统中,没有必要提供可更改的文件系统:一个不可更改(immutable)的文件系统已经足够。Linux 支持多种只读文件系统,最有用的两种是 cramfs 和 SquashFS。
Cramfs
Cramfs 文件系统是一种可用于 flash 设备的压缩式 Linux 只读文件系统。cramfs 的主要特点是简单和较高的空间利用率。这种文件系统用于内存占用较小的嵌入式设计。
虽然 cramfs 元数据没有经过压缩,但是 cramfs 针对每个页面使用 zlib 压缩,从而允许随机的页面访问(访问时对页面进行解压缩)。
您可以通过 mkcramfs 实用工具和 loopback 设备尝试使用 cramfs。
SquashFS
SquashFS 是另一种可用于 flash 设备的压缩式 Linux 只读文件系统。您可以在很多 Live CD Linux 发行版中找到 SquashFS。除了支持 zlib 压缩外,SquashFS 还使用 Lembel-Ziv-Markov chain Algorithm (LZMA) 改善压缩并提高速度。
和 cramfs 一样,您可以通过 mksquashfs 和 loopback 设备在标准 Linux 系统上使用 SquashFS。
结束语
和大多数开放源码一样,软件在不断演变,并且新的 flash 文件系统正在开发之中。一种还处于开发阶段的有趣的备选文件系统是 LogFS,它包含了一些非常新颖的想法。例如,LogFS 在 flash 设备中保持了一个树结构,因此挂载时间和传统的文件系统差不多(比如 ext2)。它还使用一种复杂的树实现垃圾收集(一种 B+树形式)。然而,LogFS 最有趣的地方是它具有出色的可伸缩性并且支持大型 flash 部件。
随着 flash 文件系统的日益流行,您将看到针对它们的大量研究。LogFS 就是一个例子,但是其他类似于 UbiFS 的文件系统也在不断发展。Flash 文件系统的架构非常有趣,并在还将是未来技术创新的源泉。