參考





《Linux内核设计与实现》





*******************************************





页快速缓存是linux内核实现的一种主要磁盘缓存,它主要用来降低对磁盘的IO操作,详细地讲,是通过把磁盘中的数据缓存到物理内存中,把对磁盘的訪问变为对物理内存的訪问。为什么要这么做呢?一,速度;二暂时局部原理。有关这两个概念,相信熟悉操作系统的我们不会太陌生。页快速缓存是由RAM中的物理页组成的,缓存中的每一页都相应着磁盘中的多个块。每当内核開始运行一个页IO操作时,就先到快速缓存中找。这样就能够大大降低磁盘操作。

      一个物理页可能由多个不连续的物理磁盘块组成。也正是因为页面中映射的磁盘块不一定连续,所以在页快速缓存中检測特定数据是否已被缓存就变得不那么easy了。另外linux页快速缓存对被缓存页的范围定义的很宽。缓存的目标是不论什么基于页的对象,这包括各种类型的文件和各种类型的内存映射。为了满足普遍性要求,linux使用定义在linux/fs.h中的结构体address_space结构体描写叙述页快速缓存中的页面,例如以下:

struct address_space {
struct inode *host; /* owning inode */
struct radix_tree_root page_tree; /* radix tree of all pages */
spinlock_t tree_lock; /* page_tree lock */
unsigned int i_mmap_writable; /* VM_SHARED ma count */
struct prio_tree_root i_mmap; /* list of all mappings */
struct list_head i_mmap_nonlinear; /* VM_NONLINEAR ma list */
spinlock_t i_mmap_lock; /* i_mmap lock */
atomic_t truncate_count; /* truncate re count */
unsigned long nrpages; /* total number of pages */
pgoff_t writeback_index; /* writeback start offset */
struct address_space_operations *a_ops; /* operations table */
unsigned long flags; /* gfp_mask and error flags */
struct backing_dev_info *backing_dev_info; /* read-ahead information */
spinlock_t private_lock; /* private lock */
struct list_head private_list; /* private list */
struct address_space *assoc_mapping; /* associated buffers */
};

当中的i_mmap字段是一个优先搜索树,它的搜索范围包括了在address_sapce中私有的和共享的页面。nrpages反应了address_space空间的大小。address_space结构往往会和某些内核对象关联。通常情况下,会与一个索引节点(inode)关联,这时host域就会指向该索引节点。假设关联对象不是一个索引节点的话,比方address_space和swapper关联时,这是host域会被置为NULL。a_ops域指向地址空间对象中的操作函数表,这与VFS对象及其操作函数表关系类似,操作函数表定义在linux/fs.h中,由address_space_operations表示,例如以下:

struct address_space_operations {
int (*writepage)(struct page *, struct writeback_control *);
int (*readpage) (struct file *, struct page *);
int (*sync_page) (struct page *);
int (*writepages) (struct address_space *, struct writeback_control *);
int (*set_page_dirty) (struct page *);
int (*readpages) (struct file *, struct address_space *,struct list_head *, unsigned);
int (*prepare_write) (struct file *, struct page *, unsigned, unsigned);
int (*commit_write) (struct file *, struct page *, unsigned, unsigned);
sector_t (*bmap)(struct address_space *, sector_t);
int (*invalidatepage) (struct page *, unsigned long);
int (*releasepage) (struct page *, int);
int (*direct_IO) (int, struct kiocb *, const struct iovec *,loff_t, unsigned long);
};

background-color: rgb(255, 255, 255);">这里面最重要的两个就是readpage()与writepage()了。对于readpage()方法而言,首先,一个address_space对象和一个偏移量会被传给该方法,这两个參数用来在页快速缓存中搜素须要的数据:

page = find_get_page(mapping, index);

mapping是指定的地址空间,index是文件里的指定位置。假设要搜索的页并没在快速缓存中,那么内核将分配一个新页面,然后将其增加到页快速缓存中,例如以下
int error; cached_page = page_cache_alloc_cold(mapping);
if (!cached_page)
/* error allocating memory */
error = add_to_page_cache_lru(cached_page, mapping, index, GFP_KERNEL);
if (error)
/* error adding page to page cache */

最后,须要的数据从磁盘被读入,再被增加页快速缓存,然后返回给用户:error = mapping->a_ops->readpage(file,page);

      写操作和读操作有少许不同。对于文件映射来说,当页被改动了,VM只须要调用:setPageDirty(page);内核晚些时候通过writepage()方法把页写出。对特定文件的写操作会比較复杂----它的代码在文件mm/filemap.c中,通常写操作路径基本上要包括一下各步:

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);
status = a_ops->commit_write(file, page, offset, offset+bytes);

首先,在页快速缓存中搜索须要的页,假设须要的页不在快速缓存中,那么内核在快速缓存中新分配一空暇项;下一步,prepare_write()方法被调用,创建一个写请求;接着数据被从用户空间复制到内核缓冲;最后通过commit_write()函数将数据写入磁盘。





由于在不论什么页IO操作前内核都要检查页是否已经在页快速缓存中了,所以这样的检查必须迅速,高效。否则得不偿失了。前边已经说过,也快速缓存通过两个參数address_space对象和一个偏移量进行搜索。每一个address_space对象都有唯一的基树(radix tree),它保证在page_tree结构体中。基树是一个二叉树,仅仅要指定了文件偏移量,就能够在基树中迅速检索到希望的数据,页快速缓存的搜索函数find_get_

page()要调用函数radix_tree_lookup(),该函数会在指定基树中搜索指定页面。基树核心代码的通用形式能够在文件lib/radix-tree.c中找到,另外想要使用基树,须要包括头文件linux/radix_tree.h.





      在内存中累积起来的脏页必须被写回到磁盘,在一下两种情况下,脏页会被写会到磁盘:





1.在空暇内存低于一个特定的阈值时,内核必须将脏页写回磁盘,以便释放内存。

2.当脏页在内存中驻留超过一定的阈值时,内核必须将超时的脏页写会磁盘,以确保脏页不会无限期地驻留在内存中。

      如今你仅仅需知道,2.6内核中,使用pdflush后台回写例程来完毕这个工作。那么详细是怎么实现的呢:





首先,pdflush线程在系统中的空暇内存低于一个特定的阈值时,将脏页刷新回磁盘。该后台回写例程的目的在于在可用物理内存过低时,释放脏页以又一次获得内存。上面提到的特定的内存阈值能够通过dirty_background_ratio系统调用设置。一旦空暇内存比这个指小时,内核便会调用函数wakeup_bdflush() 唤醒一个pdflush线程,随后pdflush线程进一步调用函数background_writeout()開始将脏页写会到磁盘,函数background_writeout()须要一个长整型參数,该參数指定试图写回的页面数目。函数background_writeout会连续地写会数据,直到满足一下两个条件:





1.已经有指定的最小数目的页被写回到磁盘。

2.空暇内存页已经回升,超过了阈值dirty_background_ration.

      pdflush线程(实如今mm/pdflush.c中,回写机制的实现代码在文件mm/page-writeback.c和fs/fs-writeback.c中)周期地被唤醒而且把超过特定期限的脏页写回磁盘。系统管理员能够在/proc/sys/vm中设置回写相关的參数,也能够通过sysctl系统调用来设置它们。下表给出了能够设置的量:

Linux页快速缓存与回写机制分析的更多相关文章

  1. linux下数据同步、回写机制分析

    一.前言在linux2.6.32之前,linux下数据同步是基于pdflush线程机制来实现的,在linux2.6.32以上的版本,内核彻底删掉了pdflush机制,改为了基于per-bdi线程来实现 ...

  2. linux块设备的IO调度算法和回写机制

    ************************************************************************************** 參考: <Linux ...

  3. CDN 的缓存与回源机制解析

    CDN的缓存与回源机制解析 CDN (Content Delivery Network,即内容分发网络)指的是一组分布在各个地区的服务器.这些服务器存储着数据的副本,因此服务器可以根据哪些服务器与用户 ...

  4. Linux 3.2中回写机制的变革

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://alanwu.blog.51cto.com/3652632/1109952 wri ...

  5. rabbitMQ的简单实例——amqp协议带数据回写机制

    rabbitMQ是一种高性能的消息队列,支持或者说它实现了AMQP协议(advanced message queue protocol高级消息队列协议). 下面简单讲一讲一个小例子.我们首先要部署好r ...

  6. 《Linux内核设计与实现》读书笔记(十六)- 页高速缓存和页回写

    好久没有更新了... 主要内容: 缓存简介 页高速缓存 页回写 1. 缓存简介 在编程中,缓存是很常见也很有效的一种提高程序性能的机制. linux内核也不例外,为了提高I/O性能,也引入了缓存机制, ...

  7. Linux内核设计与实现 总结笔记(第十六章)页高速缓存和页回写

    页高速缓存是Linux内核实现磁盘缓存.磁盘告诉缓存重要源自:第一,访问磁盘的速度要远远低于访问内存. 第二,数据一旦被访问,就很有可能在短期内再次被访问到.这种短时期内集中访问同一片数据的原理称作临 ...

  8. 聊聊高并发(三十四)Java内存模型那些事(二)理解CPU快速缓存的工作原理

    在上一篇聊聊高并发(三十三)从一致性(Consistency)的角度理解Java内存模型 我们说了Java内存模型是一个语言级别的内存模型抽象.它屏蔽了底层硬件实现内存一致性需求的差异,提供了对上层的 ...

  9. linux页缓存

    2017-04-25 本节就聊聊页缓存这个东西…… 一.概述 页缓存是一个相对独立的概念,其根本目的是为了加速对后端设备的IO效率,比如文件的读写.页缓存顾名思义是以页为单位的,目前我能想到的在两个地 ...

随机推荐

  1. STL 清除模板容器 clear.h

    #pragma once #include "GeometricMacro.h" #include "GeometricEnum.h" #include &qu ...

  2. (一)IE8以下background不起作用

    最近遇到了些小bug,在这里做个记录分享下.低版本的浏览器不支持新属性或者说对代码的解析方式不一样,导致最后解析出来的结果五花八门,各种浏览器之间的兼容的确是一个令开发人员头疼的事情,不过有时候换一个 ...

  3. 7 Ways to earn money on programming(转)

    英文原文:7 Ways to earn money on programming 几个星期前,当我收到一个自称 Someone712 的人发给我的一条消息时,我决定要写一篇如何用编程赚钱的博客文章.S ...

  4. 在 Windows Server 2008 R2 上安装 IIS 7.5

    原文 在 Windows Server 2008 R2 上安装 IIS 7.5 默认情况下,Windows Server(R) 2008 R2 上不安装 IIS 7.5.可以使用服务器管理器中的“添加 ...

  5. Notepad++ 经常使用快捷键 (MEMO)

    最近的一项研究Lua,使用Notepad++ 作为编译器. 今天早上无意中按下 Ctrl+D ,.突然认为Notepad++ 这东西非常奇妙. 网上查找了Notepad++的快捷键,尝试 Ctrl+Q ...

  6. ABP应用层——权限验证

    ABP应用层——权限验证 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ABP的官方网站:http://www.aspnetboilerpla ...

  7. thinkphp学习笔记2—入口文件

    原文:thinkphp学习笔记2-入口文件 在thinkphp中有两个入口文件,一个是项目的入口文件,是index.php在主目录里面,还有一个是thinkphp框架的的入口文件,放在框架目录下面如: ...

  8. Python的print中国输出对齐问题

    问题叙述性说明: 在使用Python内置函数print当输出英语,应用格输出类型可以对齐很好: s1 = 'I am a long sentence.' s2 = 'I\'m short.' prin ...

  9. 读取xml文件"分析 EntityName 时出错"的解决方案

    在涉及到xml与xslt编程的过程中,经常会碰到"分析 EntityName 时出错"的提示,这个不是程序错误,是因为xml文件中使用了一些特殊符号导致的.    XML 节点中不 ...

  10. Alice&#39;s Chance

    id=1698" style="background-color:rgb(51,255,51)">主题链接 意甲冠军: 爱丽丝要拍电影.有n部电影,规定爱丽丝第i部 ...