linux 缓存机制页,Linux缓存机制之块缓存

块缓存实现

块患处不仅仅用作页面缓存的附加功能,对以块而不是页面进行处理的对象来说,块缓存是一个独立的缓存。

数据结构

块缓冲区头

structbuffer_head {

unsignedlongb_state;/* buffer state bitmap (see above) */

structbuffer_head *b_this_page;/* circular list of page's buffers */

structpage *b_page;/* the page this bh is mapped to */

sector_t b_blocknr;/* start block number */

size_tb_size;/* size of mapping */

char*b_data;/* pointer to data within the page */

structblock_device *b_bdev;

bh_end_io_t *b_end_io;/* I/O completion */

void*b_private;/* reserved for b_end_io */

structlist_head b_assoc_buffers;/* associated with another mapping */

structaddress_space *b_assoc_map;/* mapping this buffer is

associated with */

atomic_t b_count;/* users using this buffer_head */

};

操作

内核必须提供一组操作,使得其余代码能够轻松有效地利用缓冲区的功能。切记:这些机制对内存中实际缓存的数据没有贡献。

在使用缓冲区之前,内核首先必须创建一个buffer_head结构实例,而其余的函数则对该结构进行操作。因为创建新缓冲头是一个频繁重现的任务,他应该尽快执行。这是一种很经典的情形,可使用slab缓存解决。

切记:内核源代码确实提供了一些函数,可用作前端,来创建和销毁缓冲头。alloc_buffer_head生成一个新的缓冲头,而free_buffer_head销毁一个显存的缓冲头。

/*分配buffer_head*/

structbuffer_head *alloc_buffer_head(gfp_t gfp_flags)

{

/*从slab中分配空间*/

structbuffer_head *ret = kmem_cache_alloc(bh_cachep, gfp_flags);

if(ret) {

/*初始化*/

INIT_LIST_HEAD(&ret->b_assoc_buffers);

get_cpu_var(bh_accounting).nr++;

recalc_bh_state();

put_cpu_var(bh_accounting);

}

returnret;

}

页缓存和块缓存的交互

一页划分为几个数据单元,但缓冲头保存在独立的内存区中,与实际数据无关。与缓冲区的交互没有改变的页的内容,缓冲区只不过为页的数据提供了一个新的视图。

为支持页与缓冲区的交互,需要使用struct page的private成员。其类型为unsigned long,可用作指向虚拟地址空间中任何位置的指针。

Private成员还可以用作其他用途,根据页的具体用途,可能与缓冲头完全无关。但其主要的用途是关联缓冲区和页。这样的话,private指向将页划分为更小单位的第一个缓冲头。各个缓冲头通过b_this_page链接为一个环形链表。在该链表中每个缓冲头的b_this_page成员指向下一个缓冲头,而最后一个缓冲头的b_this_page成员指向第一个缓冲头。这使得内核从page结构开始,可以轻易地扫描与页关联的所有buffer_head实例。

内核提供cteate_empty_buffers函数关联page和buffer_head结构之间的关联:

/*

* We attach and possibly dirty the buffers atomically wrt

* __set_page_dirty_buffers() via private_lock.  try_to_free_buffers

* is already excluded via the page lock.

*/

voidcreate_empty_buffers(structpage *page,

unsignedlongblocksize, unsignedlongb_state)

{

structbuffer_head *bh, *head, *tail;

head = alloc_page_buffers(page, blocksize, 1);

bh = head;

/*遍历所有缓冲头,设置其状态,并建立一个环形链表*/

do{

bh->b_state |= b_state;

tail = bh;

bh = bh->b_this_page;

}while(bh);

tail->b_this_page = head;

spin_lock(&page->mapping->private_lock);

/*缓冲区的状态依赖于内存页面中数据的状态*/

if(PageUptodate(page) || PageDirty(page)) {

bh = head;

do{/*设置相关标志*/

if(PageDirty(page))

set_buffer_dirty(bh);

if(PageUptodate(page))

set_buffer_uptodate(bh);

bh = bh->b_this_page;

}while(bh != head);

}

/*将缓冲区关联到页面*/

attach_page_buffers(page, head);

spin_unlock(&page->mapping->private_lock);

}

staticinlinevoidattach_page_buffers(structpage *page,

structbuffer_head *head)

{

page_cache_get(page);/*递增引用计数*/

/*设置PG_private标志,通知内核其他部分,page实例的private成员正在使用中*/

SetPagePrivate(page);

/*将页的private成员设置为一个指向环形链表中第一个缓冲头的指针*/

set_page_private(page, (unsignedlong)head);

}0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值