页高速缓存和页回写


the Page Cache and Page Writeback

page cache: 磁盘cache,减少磁盘IO

page writeback: page cache回写到disk

disk cache的重要性

  1. 提速
  2. 局部性原理

缓存手段

page cache:物理内存,对应磁盘的物理块

size动态

称为backing store(后背存储)

内核执行读操作,先检查是否在page cache中

缓存以页为单位,而不是文件

写缓存

  1. 不缓存nowrite
  2. 写透缓存write-through,双方都写
  3. 回写write-back

缓存回收 cache eviction

决定撤销哪些cache的策略

linux:选clean页

clairvoyant algorithm预测算法:无法实现

1 最近最少使用LRU

2 双链策略

活跃链表active list:不可换出

inactive list

两个链表需要维持平衡,解决了LRU算法仅对一次访问的窘境

称为LRU/2,也可扩展到n个链表LRU/n

linux page cache

address_space 对象

page cache中的一夜可以包含多个不连续的物理块

由于不连续性,检查一个数据是否在cache中不容易

不能直接用设备名+块号寻找cache

可以用page cache扩展inode 结构体:会让page cache 局限于文件

为了维持普遍性,采用address_space结构体

是vm_area_struct的物理地址对等体

一个文件可以被10个vm_area_struct标识,但只能被一个addres_space标识

文不对题,应该叫page_cache_entity或physical_pages_of_a_file

定义在<linux/fs.h>

struct address_space{
    struct inode            *host;
    ...
    struct prio_tree_root     i_mmap;
}

i_mmap所有这个address space内的映射的有限搜索树

往往会和一些内核对象关联,通常情况下和一个索引节点关联inode

此时host域指向索引节点

和swapper关联,host域置为NULL

address_space 操作

readpage()和writepage()最重要

读操作包含的步骤:

在页高速缓存找到需要的数据,find_get_page负责完成

page = find_get_page(address_space mapping, offset index)

如果搜索的页不在cache,会返回NULL,并分配新页面加入cache

需要的数据从磁盘中读入,再写到page cache中,然后返回给用户

error = mapping->a_ops_readpage(file, page);

写操作对于mapping只需要

SetPageDirty(page);

晚些时候调用writepage()

// 在page_cahce中搜索页
page = __grab_cache_page(mapping, index, &cached_page, &lru_pvec); 
// 创建写请求
status = a_ops->prepare_write(file, page, offset, offset+bytes); 
// 写数据从用户空间拷贝到内核空间
page_fault = filemap_copy_from_user(page, offset, buf, bytes); 
// page写入磁盘
status = a_ops->commit_write(file, page, offset, offset+bytes);

基树 radix tree

任何页IO操作前,内核都要检查页是否在cache

因此查找必须高效

每个address_space必须有唯一的基树,保存在page_tree结构体

基树是二叉树,只要指定偏移量,就能迅速检索,find_get_page调用radix_tree_lookup()

核心代码在lib/radix-tree.c中

以前的页散列表

维护了系统中所有页的全局散列表

缓冲区高速缓存buffer cache

减少磁盘访问,作为页高速缓存的一部分

缓冲和页高速缓存并非天生统一

2.4前一个磁盘块可以同时在两个缓存中

flusher线程

以下三种情况,脏页写回磁盘:

  1. 空闲内存低于阈值
  2. 脏页驻留时间超过阈值
  3. 用户调用sync和fsync

2.6中a gang of 内核线程,flusher线程完成三个工作

周期性被唤醒,完成前两个工作

/proc/sys/vm中设置回写的相关参数,也可以sysctl系统调用设置

变量 描述
dirty_background_ratio
dirty_expire_interval 超时多久
dirty_ratio
dirty_writeback_interval pdflush运行频率
laptop_mode

laptop mode

让硬盘机械行为最小化,允许硬盘长时间停止,延长电池时间

找准时机,一次写磁盘写很多

要求别的阈值也尽可能大

多数linux会在充电时自动关闭,拔电源时自动开启

bdflush,kupdated和pdflush

2.6前,前两者

基于缓冲,只有一个bdflush

2.6pdflush

面向所有磁盘,容易拥塞

2.6.32后flusher

flusher针对每个磁盘独立执行回写

避免拥塞:多线程

bdflush


文章作者: N1co5in3
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 N1co5in3 !
  目录