页高速缓存,可以理解为对磁盘中的文件内容进行缓存的一种缓存策略,当然它不仅仅用于磁盘文件。

当对同一磁盘数据反复访问时,缓存数据就是非常必须的了。这就是buffer和 cache这两个概念中的buffer范畴了。

页高速缓存的核心数据结构是address_space结构体,它由inode对象的i_mapping指针指向,我们知道inode对象中记录了一个文件的基本信息,所以每个文件都有一个address_space对象。

每个address_space对象对应一棵radix树,我在文章 radix树 中简单的介绍了这个数据结构,并提出了一些我的疑问。

如果大家不了解radix树的,也没有关系,只需要知道通过一个数据块的索引(0-232),可以在O(1)的时间复杂度内查询到这个数据块所在的页框。

linux所使用的radix树如下所示:

 

基树的节点由struct radix_tree_node实现,它包含三个字段 slots; count; tags

其中slots表示64个指针数组,count是记录非空指针数量,tags是一个二个元素的数组,每个元素是一个64位bit,它的每一位对应这64个指针。含义下面再说。

就像我们在 radix树 中所说,32bit的索引被分成了每6bit一组,从高位到低位,分别对应树的每一层。

上面所说到的tags标记,分别标记了此页的PG_dirty和PG_writeback,表示页是脏的,或页正在被写回磁盘。

如果树中底层某个节点标记了脏标记,那么上层对应的父节点也会被标记为脏,这同样适用于写回标记。

这样我们在扫描脏页面时就不用扫描所有的页框,大大提高了效率。

附:每个页描述符中都包括两个字段mapping和index,mapping指向拥有页的索引节点的address_space对象,而index表示此页在文件内容的地址空间内,以页大小为单位的偏移量。

内核线程pdflush会在某些时机下,例如分配缓冲区页失败时,调用sync时等,将脏页flush到磁盘。