来源:chinaunix 作者:登高望远海
1、F2FS文件系统简介
F2FS (Flash Friendly File System) 是专门为基于 NAND 的存储设备设计的新型开源 flash 文件系统。特别针对NAND 闪存存储介质做了友好设计。F2FS 于2012年12月进入Linux 3.8 内核。目前,F2FS仅支持Linux操作系统。 F2FS 选择 log-structured文件系统方案,并使之更加适应新的存储介质(NAND)。同时,修复了旧式日志结构文件系统的一些已知问题,如(1) wandering tree 的滚雪球效应和(2)高清理开销。 根据内部几何结构和闪存管理机制(FTL),闪存存储设备有很多不同的属性,所以F2FS的设计者增加了多种参数,不仅用于配置磁盘布局,还可以选择分配和清理算法,优化性能(并行IO提高性能)。 1.1 F2FS文件系统的设计背景和要解决的主要问题1.1.1 LFS(Log-strctured File System)为管理磁盘上的大的连续的空间以便快速写入数据,将 log 切分成 Segments,使用 Segment Cleaner 从重度碎片化的 Segment 中转移出有效的信息,然后将该 Segment 清理干净用于后续写入数据。 1.1.2 Wandering Tree 问题在 LFS 中,当文件的数据块被更新的时候是写到 log 的末尾,该数据块的直接指针也因为数据位置的改变而更改,然后间接指针块也因为直接指针块的更新而更新。按照这种方式,上层的索引结构,如 inode、inode map 以及 checkpoint block 也会递归地更新。这就是所谓的 wandering tree 问题。为了提高性能,数据块更新的时候应该尽可能地消除或减少wandering tree 的更新节点传播。 1.1.3 Cleaning 开销
为了产生新的 log 空闲空间,LFS 需要回收无效的数据块,释放出空闲空间,这一过程称为 Cleaning 过程。Cleaning 过程包含如下操作: (1)通过查找 segment 使用情况链表,选择一个 segment; (2)通过 segment summary block 识别出选中的 segment 中的所有数据块的父索引结构并载入到内存; (3)检查数据及其父索引结构的交叉引用; (4)选择有效数据进行转移有效数据。 Cleaning工作可能会引起难以预料的长延时,因而 LFS 要解决的一个重要问题是对用户隐藏这种延时,并且应当减少需要转移的数据的总量以及快速转移数据。 2、F2FS文件系统特性和功能2.1 F2FS不支持的特性和功能(后续可能会支持)
当前F2FS不支持如下的特性,但是这些特性在以后如果必要的话也会支持: (1)快照 (2)用户配额——最难实现 (3)不支持NFS (4)不支持“security”方面的扩展特性(xattrs) 2.2 F2FS的特性和功能
F2FS具有以下特性和功能: (1)最大文件系统16TB; (2)32位块寻址空间; (3)最大文件大小3.94TB; (4)Log-structured; (5)Flash 感知 a) 扩大随机写区域(元数据区域,two-location)以获取更好的性能; b) 尽量使 F2FS 的数据结构与 FTL 的运算部件对齐。 (6)解决Wandering Tree 问题 a) 用术语“node”表示 inode 以及各种索引指针块; b) 引入 Node Address Table (NAT) 包含所有“node”块的位置,这将切断数据块更新的递归传播。 (7)最小化Cleaning 开销 a) 支持后台 Cleaning 进程; b) 支持 greedy 和 低成本(转移数据最少)的待清理 Section 选择算法; c) 支持 multi-head logs 用于动态/静态 hot 与 cold 数据分离; d) 引入自适应 logging 用于有效块分配。 3、F2FS文件系统的磁盘布局分析F2FS 将整个卷切分成大量的 Segments,每个 Segment 的大小是固定的2 MB。连续的若干个Segments 构成 Section,连续的若干个 Sections 构成 Zone。默认情况下一个 Zone大的大小是一个 Section,而一个 Section 的大小是一个 Segment。 F2FS 将整个卷切分成6个区域,除了超级块(Superblock,SB)外,其余每个区域都包含多个 Segments。
3.1 块(Blocks)、段(Segments)、区段(Sections)、存储区(Zone)3.1.1 Blocks(1) F2FS文件系统的所有块大小都是4KB,F2FS 代码隐式地将块大小链接到系统的页大小,因而F2FS不可能在更大的页的系统上运行,如 IA64 和 PowerPC。 (2) 块地址是32位的,最大文件系统是2^(32+12) Bytes,也就是16TB(完全大于当前的 NAND flash 设备的大小)。 3.1.2 Segments
(1) 连续的Blocks集合成Segments,一个Segment的大小是512个Blocks(也就是2MB); (2) 每个Segment都有一个Segment Summary Block元数据结构,描述了Segment 中的每个Block的所有者(该块所属的文件及块在文件内的偏移)。Segment Summary主要用于在执行Cleaning操作时识别哪些Blocks中的数据需要转移到新的位置,以及在转移之后如何更新Blocks的索引信息。一个Block就可以完全存储512个Blocks的summary信息,每个blocks都有一个1 bit的额外空间用于其它目的。 (3) 2MB是最合适的Segment大小,太大不合适,太小又会造成存储summary信息的Block空间浪费; 3.1.3 Sections
(1) 连续的Segments集合成Section。Section中具有的segments个数是任意的,但是要满足是2的幂;默认情况下,一个Section大小等同于一个Segment(2^0 Segments); (2) 一个Section对应log structuring的一个区域“region”,log在使用下一个Section之前,通常要从头到尾将当前的Section填满数据; (3) 清理器Cleaner一次处理一个Section; (4) 在F2FS中,任意时刻都有6个“打开的”Sections用于将各种不同种类的数据(元数据、数据)分别写入到各个Sections中,实现数据分离。这样便允许文件内容(数据)与其索引信息(节点,node)分离,允许F2FS文件系统根据各种启发式方法将Sections划分成三类:即“hot”、“warm”、“cold”。例如,目录数据被当做hot来对待,使其与文件数据分离,存放到“hot”Section中。Cold数据是指那些很长时间内都不会改变的数据,因而装满Cold数据的Section就不需要执行Clean操作。对于hot节点(索引信息节点),一般更新很快,一段时间之后,装满 hot 节点的Section中的有效数据(alive data)就会很少,因而选择这样的Section进行Clean操作开销就很小(因为要转移的数据很少)。
3.1.4 Zone (1) 连续的Sections集合成Zone。一个Zone可以包含任意整数个Sections。默认是一个Zone中包含一个Section; (2) 设置Zone的唯一目的是尽可能将6个打开的Sections位于Flash设备的不同的子设备中。理论上,Flash设备通常是由一组相互完全独立的子设备构成,每个子设备都可单独地处理I/O请求,不同子设备可并行处理I/O请求;如果Zone的大小与子设备大小对齐,6个打开的Sections可并行写入,充分利用设备的特性; (3) Zone构成了F2FS的“主要(main)”区域。 3.1.5 Meta AreaF2FS有一个“meta”区域,包含了各种不同的元数据(如之前提到的segment summary),这一部分不是采用标准的log-structured流水线方式管理,因而更多的工作留给了FTL去做。有三种方法管理对“meta”区域的写操作: a)第一,有少量的只读数据(超级块)从来都不是不是在文件系统创建的时候立即写入; b)第二,对Segment Summary Block 简单采取本地更新的方法。这种本地更新可能导致文件系统奔溃后数据块“修正”内容的不确定性,但对segment summary来说这都不是问题,segment summary blocks中的数据在使用前要进行有效性验证,如果有任何信息丢失的可能,它都将会在恢复进程中从其他source中恢复。 c)第三种方法,分配需求空间两倍大小的空间,使得每个block都有两个不同的位置:一个Primary,一个Secondary,任意时刻,两个位置的block仅有一个是live状态。因而LFS的Copy-On-Write需求就可以通过向non-live位置的block写入更新后的block内容并且更新记录哪个位置的block是live状态的方式简单实现。对于元数据来说,这种技术是实现快照功能的主要实现方法。当创建一个Checkpoint的时候,F2FS执行少量的Journaling更新到最后的组(last group),这在一定程度上减轻了FTL的工作。
文件(Files)、索引节点(Inodes)、数据块索引(Indexing)
1. 文件索引树结构大多数现代文件系统都喜欢使用 B-trees 或类似的结构来管理索引(index)以定位文件中的 blocks。大多数文件系统中通过使用“extents”来减少文件数据块的总索引大小。F2FS 不采用 B-tree 结构管理索引,也不使用extents减少文件数据块索引的大小(虽然F2FS为每个节点(node)维护一个extent作为提示)。 2. 索引节点管理数据位置的关键数据结构是“node”,与传统文件系统相似,F2FS 使用三种 node:inode,直接 node,间接 node。F2FS 分配4 KB 的空间给一个 inode,其中包括929个数据块索引指针,两个一级索引块(直接 node )指针,两个二级索引块(间接 node )指针,以及一个三级索引块(二级间接 node)指针。一个一级索引块(直接 node )包含1018个数据块指针,一个二级索引块(间接 node )包含1018个一级索引块(直接 node )指针,一个三级索引块(二级间接 node)包含1018个二级索引块(间接 node )指针。因此一个文件的最大大小是: 4 KB * (929 + 2*1018 + 2*1018*1018 + 1018*1018*1018) := 3.94 TB
3. 文件数据块索引F2FS 使用索引树(如原始Unix文件系统和Ext3的索引树)索引数据块。Inode中包含了文件开始的一部分的数据块的地址列表,然后一些地址用于间接索引块以及二级和三级间接索引块。Ext3有12个直接索引地址以及三个间接索引块(一级、二级、三级)。F2FS 有929个直接索引地址,2个一级间接索引块,2个二级间接索引块,1个三级间接索引块。允许寻址接近4TB的文件,也就是最大文件系统的1/4大小。
按大家最熟悉的Ext2、Ext3的索引方式看,F2FS的索引树就是如下的结构:
4. 文件索引树对F2FS的意义但是这种索引树机制有一定的代价——这也是其他文件系统抛弃这种索引方式的主要原因——但是这种方式对 LFS 却有好处。因为F2FS不使用 extents ,任意给定文件的索引树是固定的而且大小已知。这意味着,当数据块由于 cleaning 操作需要转移数据时,不可能因为可用 extens 发生改变而导致索引树变得更大(原来文件中每个 extent 很大,一个文件的索引树仅仅用少数几个 extents 就可完全表示,而新的存储部分每个可用 extent 都很小,要存储原来的文件就需要更多的 extents,导致文件的索引树变大)的情况产生——这可能会导致一种尴尬的情况产生就是 cleaning 的目的本来是要释放空间,而现在索引树变大却导致空间变小了。Logfs 文件系统也因为相同的原因,使用了许多相同的编排处理方式。 显然,所有这些需求都要求 F2FS 的 inode 比 Ext3 的inode要大许多。因为Copy-on-write 不适用于小于块大小的对象,因而 F2FS 中每个 inode 占用的空间大小是一个 4 KB的块,该 4 KB 的空间中提供了大量的空间用于索引。甚至提供空间存储(基本的)文件名,或者名字之一,以及其父节点的 inode 号,这简化了在文件系统 crash 恢复过程中近期创建的文件的恢复操作,减少了为保证文件安全需要写入的数据块的数量。 5. 加速文件查找的ExtentInode 中包含了一个 extent,它总结了索引树的某些部分,它说明该文件的某些范围的blocks在存储上是空间连续的,并给出该范围的地址。F2FS 文件系统尝试在此处表示文件中最大的 extent,使用其加速地址查找。例如,通常情况下文件是连续写入且无任何明显的暂停,这样可能的结果是整个文件构成一个 extent,使得没有必要进入文件的索引树查找。 6. NAT解决wandering Tree问题任何基于 Copy-on-write 技术的文件系统的一个缺点在于,无论何时要改写一个数据块,该数据块的地址就会因为数据重写到其他位置而发生改变。然后,在索引树中该块的父节点也因此必须重写到其他位置,如此往复下去直到重写操作传播到索引树的根。LFS 的logging 特性意味着在恢复过程中向前回滚可以重建近期对索引树的修改,因而所有这些修改不必立即写到磁盘(只是写到 log 中),但是这些修改最终还是会写到磁盘的,这就将更多的工作丢给 cleaner 去做。 这是 F2FS 为了方便而使用其底层 FTL 去处理的另一个区域。“元数据”区域('meta' area)中的内容是一个 NAT——Node Address Table(节点地址表)。这里的节点是指inode 和间接索引块,以及用于存储扩展属性的数据块。当 inode 的地址存储在目录中,或者索引块存储在一个 inode 中或者其他的索引块中的时候,它存储的不是(存储的内容所在的)地址,而是其在 NAT 中的偏移。实际的(存储内容的)块地址是存储在 NAT 中对应的偏移处。这意味着当一个数据块被写入,仍然需要更新和修改指向该数据块的节点,但是修改该节点仅需更新对应的 NAT 项。NAT 是元数据的一部分,NAT 使用两个位置(two-location)的 Journaling(依靠FTL实现写聚合),因而不需要进一步的索引。 7. Inline技术支持情况F2FS 目前不使用小文件内嵌(Inline)技术。针对这一技术的实际情况是:暂时还不支持 Inline 技术,但是很容易实现加入这一技术,并且这一技术迟早会加入到 F2FS 中。 8. 时间分辨率很不幸,F2FS 没有足够空间存储64位的时间戳,也就是最小时间分辨率不是纳秒(ns),而是以秒(s)为时间分辨率。这可能导致2038问题,但时间戳分辨率问题应该会在未来的版本中解决。
|