EROFS(Extendable Read-Only File System)是华为最近发布的一个新的Linux文件系统,它是一个基于ROM的只读文件系统。目前已经并入内核主线4.19分支。该文件系统因为其所宣传的“可提升随机读写速度数倍”引起了业内外广泛关注。下面将从两个方向对该文件系统取得如此成效的原因进行解读。
通过fixed output压缩缓解读放大问题
一般存储器以4K为最小的读写单元,要找到一个读写单元就要寻址。如果有一组数据大小在5K左右,压缩后占用3.5K的空间。当这3K的数据全部在一个单元内时,一次读写就能完成我们的操作,但是如果这3K的数据前1.5K在第一个存储单元内,后2K在另一个存储单元内,就需要进行至少两次读写,会导致性能的下降。
在以往Linux内核使用的压缩只读文件系统squashfs中,每4K数据进行一次压缩。数据不同,压缩率也不一样,有的数据可以压缩到很小,有的数据几乎没办法压缩。这样就会压缩出很多大小不一的数据块。尽管这些数据块全部小于4K,然而可以说,这些数据块几乎完全不能和4K单元对齐,因此读写时会造成很多的额外消耗。
例如一个128k的文件, squashfs会采用固定大小(比如32K)为输入,即会将每32k数据压缩成不确定的大小,如可能是12K;那么读取文件中的任意4k数据,都需要至少读取完整的12k压缩数据,然后解压再读取其中的4k,这多读取的8K就是所谓的“读放大问题”。
EROFS也是一种压缩文件系统,采用了一种叫做fixed-sized output文件压缩算法。该算法在EROFS中应用的示意图如下:
一个文件4K不对齐的结尾的部分会作为内联文件数据和inode head连接在一起,故压缩后的物理块大小为固定值(4K)。相比于以固定大小为输入,变长输出的fixed-size input能够有效的缓解读放大问题,降低I/O读取量。对于上面的情况,EROFS采用的是固定大小为压缩输出,即可能会将这128k数据的0-7k压缩成4k,7-25k也压缩成4k,25-32k也压缩成4k,以此类推。那么读取文件中的任意4k数据,只要读取最少4k,最多8k(任意4k数据压缩后最多分布到两个block中)的压缩数据。相比squashfs,读放大问题明显减少了。
只读特性
EROFS被应用于Android的只读系统分区。以往Android只读系统分区使用ext4文件系统的只读挂载参数和挂载dm-verity虚拟块设备(用于文件系统校验)来配合实现只读。这并非是一种结构上的限制,通过去除Ext4只读挂载选项并且不挂载dm-verity设备,就可以对系统分区进行写操作。
而EROFS在结构上即为天然只读,由于时间有限,其具体实现我还没有了解的很清楚,但根据网络上的一些讲解,EROFS存储单元间通过一种类似链表的结构进行连接,前面的存储单元保存着其后一个存储单元的位置,不通过全局bitmap管理所有可写区域。因此外来者无法知道哪个区域是有效可写入的,即使强行写入,其内容也不会被其它存储单元承认。
保障只读为整个系统的设计带来了很多好处,由于数据空间大小已经事先确定,文件系统可以消除直接inode/间接inode这样的设计,也省略掉了inode bitmap和block bitmap(记录空的block)这种区域来节省空间。直接把每个文件压缩后的数据顺序储存,然后保留压缩后每个簇对应的原始数据范围作为元数据即可。这样一来对文件的顺序访问变成了顺序读取,性能得到了很大提升。EROFS磁盘层数据结构示意图如下:
实现细节上,EROFS的inode table是变长的,里面包含了inode结构体和少量的内联文件数据。xattr和压缩特性都是可选的,未选择的情况下inode table空间将进一步缩小。