linux文件系统的页高速缓存page cache中的核心数据结构address_space

address_space对象是文件系统中关于内存中页高速缓存的核心数据结构。这篇博客以address_space对象为切入点,分析文件系统的页高速缓存。(这里大部分都是从原作者那里复制过来的,外加上我个人的理解部分,以及结合我要做的事情进行了部分补充)

1背景

在文件系统中,内存中存在着dentry和inode结构,其中其分别的作用可以见我另一篇博客《dentry与inode》。由于这些结构要反复使用,所以内存里开辟了目录项高速缓存以及索引结点高速缓存,提高其访问速度。但这里要提到的是另一种高速缓存:页高速缓存,它是一种对完整的数据页进行操作的磁盘高速缓存,即把磁盘的数据块缓存在页高速缓存中。而address_space对页高速缓存进行管理(address_space是管理page cache的)。考虑到开始从文件系统的细节部分开始转到内存管理部分,后面我会专门总结一下内存中高速缓存的种类和用途(特别是对于ext2和minix的存储blockid的由i_zone数组进行管理的用于多级寻址的block在内存是怎么管理的,因为后面我要修改这一部分)。

2页高速缓存介绍

linux中几乎所有文件的读和写操作都依赖于页高速缓存(页高速缓存与page cache的关系是啥?同一个东西的两种叫法)。只有在O_DIRECT标志置为才会出现意外:此时,I/O数据的传送绕过了页高速缓存而使用了进程用户态地址空间的缓冲区;另外,少量的数据库软件为了采用自己的磁盘高速缓存算法而使用了O_DIRECT标志。

why设计页高速缓存?

答:1.快速定位所有者(这里指的是inode)相关数据页的位置(基树)。2.区分不同所有者页的不同读写操作,如普通文件、块设备文件、交换区文件读一个数据页必须使用不同的方式实现,故内核根据页的不同所有者进行不同的操作。

3address_space对象

每一个所有者(可以理解为一个具体的文件,一个inode指向的文件)对应着一个address_space对象,页高速缓存的多个页可能属于一个所有者,从而可以链接到一个address_space对象。那么一个页(page)怎么和一个address_space产生关联的呢?

page中有两个字段:mapping和index。其中mapping指向该页所有者的address_mapping(内存inode结构有一个i_mapping指向对应address_space对象),index字段表示所有者地址空间中以页大小为单位的偏移量(就是这个页在inode对应的文件中的页号,也就是index)。用这两个字段就能在页高速缓存中查找页。(这里注意一点,一个页中所包含的磁盘块在物理上不一定是相邻的)

address_space中有一个host字段,该字段指向其所属的inode,也就是address_space中的host字段 与 对应inode中的 i_data字段形成互相指向的关系。若为普通文件,那么inode结点和address_space结构的相应指针的指向关系如下图:

linux文件系统的页高速缓存page cache中的核心数据结构address_space_第1张图片

(对于我们要在inode中增加i_index[3]来管理索引数据的需求来说,由于我们想把i_index[3]管理的那些多级间接block放到page cache中,除了增加上图所示的address_space结构来管理i_index[3]的数据之外,还要考虑page 是如何和磁盘上的block对应的,因为索引的数据也是以block的形式存储在磁盘上的。所以要研究address_space和i_zone[10]之间的关系,以此来规划新的address_space和i_index[3]的关系。但是据我目前的知识所知,i_zone[10]所管理的12个直接block,1个间接寻址块以及对应的256个存储blockid的block,以及2级和3级寻址对应的block,都是通过sb_read的方式将block读取内存的,并没有加入到page cache中,这给我们带来了难度)

4基树

linux支持TB级的文件,ext4甚至支持到了PB级文件,访问大文件时,高速缓存中存在着有关该文件太多的页,故设计了基树这个结构来加快查找。一个address_space对象对应一个基树。

address_space中有一个字段(page_tree)指向是基树的根(radix_tree_node)。基树根中的rnode指向基树的最高层节点(radix_tree_node),基树节点都是radix_tree_node结构,节点中存放的都是指针,叶子节点的指针指向页描述符,上层节点指向存放其他节点的指针。一般一个radix_tree_node最多可以有64个指针,字段count表示该radix_tree_node已用节点数。

怎么快速找到所需页在基树中的位置呢?

回顾本科所学知识:分页系统如何利用页表实现线性地址到物理地址的转换?线性地址的最高20位分为两个10为的字段:第一个字段是页目录的偏移,第二个字段是页目录所指向也表的偏移。

在基树中,类比此方法。若基树深度为1,则只能表示从0至63的索引,则页索引(上文提高的index字段)的低6位进行解析,从而对应成radix_tree_node结构中的slot下标,找到对应的页;若基树深度为2,则页索引的低12位分成0~5,6~11两个字段进行解析。分别找到第一层slot字段和第二层slot字段的值。(这种分层查找和分页系统查找页的位置,以及i_zone管理的多级间接寻址类似),原则上讲,对于使用u32表示的一个索引信息,可以解析5层结构,那么就是64^5个page,那是多少呢?大约是2^40个page,大约是1TB*4K=4PB。

linux文件系统的页高速缓存page cache中的核心数据结构address_space_第2张图片

右下角的那个radix_tree_node的count字段应为1,这里写的是2.count字段表示的应当是本机radix_tree_node的slots用掉了几个。

你可能感兴趣的:(文件系统,linux)