[翻译] 非易失性内存上的文件系统支持

原文: Supporting filesystems in persistent memory September 2, 2014

前言:在今年的CLSF会议上,一个NVDIMM的话题非常火爆,大家对这种可以把内存当硬盘用的设备都很感兴趣。同时上游内核也在做DAX相关的东西,以后RHEL7上可能也是要支持的。我就趁着热呼劲儿再多看看相关文章了。

正文:
近几年来,一直有传言说非易失性内存设备(non-volatile memory – NVM)将会改变我们使用系统的方式。这种设备能够提供大量(也许是TB级别)的非易失的、能以内存的速度进行访问的存储空间。这么大量的非易失性内存可以用来做什么现在还不是很清楚,但是NVM已经引起越来越大的关注了。可能我们会在NVM上运行传统的文件系统——但是这些文件系统需要一些修改从而让用户能够得到NVM的全部性能优势。

在NVM上加上一层块设备驱动而让NVM设备看起来像普通存储设备是很容易的事情。但是,这样做会强制所有数据和系统page cache之间进行复制。既然NVM设备是可以直接访问的,那么这些复制就是效率低下的。对性能敏感的用户会尽可能的避免使用page cache来达到NVM设备的最高速度。

事实上从2005年开始,随着ext2加入了excute-in-place(XIP)支持,内核就已经对NVM设备直接访问有一定支持了。这些代码可以把可以直接寻址的设备映射到用户空间,这样文件数据就不需要通过page cache来访问了。但是使用XIP的人很少,这些代码已经多年没有更新了,并且无法在现在的文件系统上工作。

去年,Matthew Wilcox开始着手改进XIP代码,试图把它和ext4文件系统整合在一起。在整理的过程中,他发现XIP无法和同时代的文件系统很好的结合在一起,并且代码里还有很多恼人的race condition。所以,随后他的工作从改进XIP转向了代替它。这项工作由21个patch组成,受到越来越多的关注。现在已经接近完成,可以并入主线内核了。

这些patch使用了一个叫做DAX(很显然代表“direct access”)子系统代替了XIP。在块设备层上,它用以下函数替换掉了struct block_device_operations中的direct_access()函数

    long (*direct_access)(struct block_device *dev, sector_t sector,
			  void **addr, unsigned long *pfn, long size);

这个函数接收sector号和size作为参数来说明调用者想访问多少字节的数据。如果给定的空间是可以直接访问的,那么基地址(内核地址)就通过addr返回,同时相应的页帧号(page frame number)也保存在pfn中。当从用户空间直接访问这些内存的时候,页表会使用这个页帧号。

这种使用页帧号和地址的方法可能有些奇特,内核大部分时候通过struct page来处理这一级别的内存。但这在DAX的情况下是不可行的,因为一个简单的原因:非易失性内存不是普通的内存,没有和它们相关联的页结构体(page structure)。缺少页结构体产生了很多后果,也许最重要的一个是这些NVM不能被其他设备用来做DMA访问。所以在网络设备和存储设备之间做零拷贝(zero-copy)传输,像这样的操作在NVM设备上就无法实现了。Boaz Harrosh正在写一些patch来增加NVM的page structure的支持,但这项工作还处于一个早期阶段。

再把目光移向IO栈的更上一层,NVM的支持在VFS层已经做了很多所有文件系统都能用到的工作。新建了各种通用的帮助函数(helpers)用以辅助一些常见的操作(reading, writing, truncating, memory-mapping等等)。在大部分情况下,文件系统只需要在可以使用DAX的inode中标记一个新的S_DAX标志然后在正确的地方调用帮助函数就可以了。(一点点)更多的信息可以参考patchset中的文档。这个patchset在ext4中加上了一些必要的支持。

但是Andrew Morton针对这项工作有一些疑问。最主要的问题是,为什么不直接使用一个经过修改的内存文件系统(ramfs, tmpfs)?这看上去是一个很好的问题,因为这些文件系统已经是为可以直接访问的内存设计的并且做了很多优化。但问题也在这,ram-based文件系统是为ram设计的,并不能很好的适应NVM设备。

来自Dave Chinner的信对此做了详细的解释,而且这封信很值得一读。大体上概括起来说,问题归结到以下这一点上:ram-based文件系统并没有针对数据持久性做任何设计。它们在每次启动的时候都是一个全新的文件系统,并不需要处理上一次系统运行遗留下来的东西。但在另一方面,NVM需要处理更多数据持久性相关的问题,比如在NVM上存储的数据在机器重启之后也不会丢失,并且需要在系统崩溃的时候足够健壮,在升级内核之后数据也是需要依然存在的等等。这些需求ram-based文件系统都无法满足。

所以,NVM文件系统需要所有传统文件系统所拥有的工具,用来来识别磁盘上的文件系统,做检查并处理文件系统损坏的情况。为了保证持久存储上的数据一直处于一致的状态,NVM也需要各种传统文件系统所使用的技术。例如,元数据写入的顺序必须非常仔细的处理并且用屏障来保护。因为在不同内核之间的兼容性是很重要的,所以内核中的数据结构不能直接存储在文件系统中,数据必须在host format和on-disk format之间来回转换。这些都是传统文件系统做了而ram-based文件系统没有做的事情。

然后,Dave解释道,在可扩展性方面还存在一些问题:

更进一步,NVM文件系统需要可以被扩展到非常大的存储上。在不久的将来机器上会有好几十TB的NVDIMM存储容量,所以对空闲空间的管理和对已使用空间的分配/释放的并发操作,这些都会是影响NVM文件系统性能的关键问题。所以最后你需要使用块/分配组来把空间做进一步划分。这看起来很像XFS和EXT4现在做的。

然后你需要所有的索引扩展到千万级别。至少是千万级别的,其实更可能是亿或者十亿级别。因为存储好几十TB的小文件就需要对数十亿的文件进行索引。而且因为这样做基本上没有性能上的惩罚,人们就会把文件系统当作一个大的数据库来用。所以现在你又需要有一个可扩展的并且和posix兼容的文件夹结构,可扩展的空闲空间索引,动态的、可扩展的inode分配/释放操作等等。噢,为了处理机器上的上百个cpu核还需要高并发性。

作为结论,Dave指出现在内核已经有不少满足上述需求的“非易失存储实现”了,那就是XFS和EXT4文件系统(虽然Dave一直认为ext4的可扩展性有问题)。现在这两种文件系统都能够在非易失性内存的块设备上工作。但最大的问题就是没有一种方法能够让用户直接访问数据而不需要经过page cache,这就是DAX所需要提供的功能。

现在有一些工作组在从头为NVM设计文件系统。但这些工作基本都还处于早期阶段,在内核邮件列表里还没有人发出patch来,更没有申请合并到主线内核的。所以想充分利用NVM性能的用户,在未来几年是不会从这些工作上得到什么帮助了。所以说,在目前已有的文件系统上增加NVM支持是一个真实的需求,得出这样的结论也并不是不合理的。

目前来看DAX就是通往这个目标的一条路。现在所需要做的就是尽快review这些patch并让patch达到让所有相关子系统的维护者都同意合并的状态。review工作目前进行缓慢,因为patch很复杂并且修改了很多不同的子系统。但是,作为对之前review的回应,patch已经有了很多的改进,并且看起来离最终的版本不远了。也许在不久的将来DAX功能最终就会进入主线内核。

Leave a Reply