the Page Cache and Page Writeback
page cache: 磁盘cache,减少磁盘IO
page writeback: page cache回写到disk
disk cache的重要性
- 提速
- 局部性原理
缓存手段
page cache:物理内存,对应磁盘的物理块
size动态
称为backing store(后背存储)
内核执行读操作,先检查是否在page cache中
缓存以页为单位,而不是文件
写缓存
- 不缓存nowrite
- 写透缓存write-through,双方都写
- 回写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线程
以下三种情况,脏页写回磁盘:
- 空闲内存低于阈值
- 脏页驻留时间超过阈值
- 用户调用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