📄 035_fs_buffer_c.html
字号:
<html lang="zh-CN" xmlns:gdoc=""> <head> <meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <style type="text/css">/* default css */table { font-size: 1em; line-height: inherit;}div, address, ol, ul, li, option, select { margin-top: 0px; margin-bottom: 0px;}p { margin: 0px;}body { margin: 0px; padding: 0px; font-family: Verdana, sans-serif; font-size: 10pt; background-color: #ffffff;}h6 { font-size: 10pt }h5 { font-size: 11pt }h4 { font-size: 12pt }h3 { font-size: 13pt }h2 { font-size: 14pt }h1 { font-size: 16pt }blockquote {padding: 10px; border: 1px #DDD dashed }a img {border: 0}div.google_header, div.google_footer { position: relative; margin-top: 1em; margin-bottom: 1em;}/* end default css */ /* default print css */ @media print { body { padding: 0; margin: 0; } div.google_header, div.google_footer { display: block; min-height: 0; border: none; } div.google_header { flow: static(header); } /* used to insert page numbers */ div.google_header::before, div.google_footer::before { position: absolute; top: 0; } div.google_footer { flow: static(footer); } /* always consider this element at the start of the doc */ div#google_footer { flow: static(footer, start); } span.google_pagenumber { content: counter(page); } span.google_pagecount { content: counter(pages); } } @page { @top { content: flow(header); } @bottom { content: flow(footer); } } /* end default print css */ /* custom css *//* end custom css */ /* ui edited css */ body { font-family: Verdana; font-size: 10.0pt; line-height: normal; background-color: #ffffff; } .documentBG { background-color: #ffffff; } /* end ui edited css */</style> </head> <body revision="dcbsxfpf_14fb53b3:591"> <div align=center>
<table align=center border=0 cellpadding=0 cellspacing=0 height=5716 width=802>
<tbody>
<tr>
<td height=5716 valign=top width=802>
<pre>2007-11-14<br>先拷贝一段以前的分析:<br><br></pre>
<div style=TEXT-ALIGN:center>
<b>buffer cache vs page cache(page cache的演化)</b><br>
<br>
</div>
<pre><font color=#006600>在2.2x时期,page cache和buffer cache是两套cache系统,之间有同步.但是linux不保证每个版本都如此.<br>如果现在/dev/hda1是根,如果hda1上有文件a.txt用dd dump /dev/hda1能够得到和open a.txt一样的结果.<br>到了2.4.x事情已经变得不是这样了,dd if=/dev/hda1 从buffer cache中获取数据,open打开的普通文件缓冲到page cache,两者没<br>有任何同步机制(meta data还是一致的). 合适的次序下,得到的结果不能保证正确性.<br><br> 当然dump一个已经mount的,"live file system"是个愚蠢的做法,我们只是拿来讨论问题.<br>到了2.5,文件的meta data也移到了page cache,事情进一步复杂了.在2.6的内核中page cache和buffer cache进一步结合,从此<br>buffer cache 消失,只有page cache了. buffer cache退化为一个纯粹的io entry.随了linus的心愿.<br><br>可以看看linus的讨论<br><br><a href=http://groups.google.com/group/fa.linux.kernel/browse_thread/thread/3d1be60ca2980479/0ca4533f7d0b73e4?hl=zh-CN& target=_blank>http://groups.google.com/group/fa.linux.kernel/browse_thread/thread/3d1be60ca2980479/0ca4533f7d0b73e4?hl=zh-CN&</a> <br><br>在2.4中buffer cache自己维护了一套类似page cache和lru队列的机制,对buffer cache做lru 缓冲处理,的确不是一个什么好东西.</font><br><br>这个文件的主要目的是维护buffer cache,大致分成几大块,先看一个简图吧,简单示意一下buffer_head struct page 和真实的<br>物理缓冲区的关系:(这三个合起来才是一个完整的buffer)<br><br> <br> struct page <br> +-------+ <br> | | +-----------+ +-----------+ +-----------+ <br> |buffers--------| | | | | | <br> | | |b_this_page----|b_this_page-----|b_this_page| <br> | | | b_data | | b_data | | b.data | <br> | | +------,----+ +----.------+ +-.`--------+ <br> | | / ` ,' <br> | | / ,' ,' <br> | | ' ` ,- <br> +-------+ ,' ,' - <br> / ` ,' <br> -------------`-----------`----------+------------------- <br> real | | | | <br> page | | | | <br> | | | | <br> | | | | <br> +-----------+-----------+-----------+-------------------- <br> <br><br>然后来看看buffer cache 最基础的几个部分:<br><br></pre>
<div>
<div style=TEXT-ALIGN:center>
<b>0)buffer head 和buffer 的free 链</b><br>
</div>
<b><br>
</b>
<div style=TEXT-ALIGN:left>
从图中以及代码各个角落可以知道,buffer_head 是buffer
cache的一个handler,拿到bh就可以进行io操作了,但是buffer head 也需要从内存中分配和释放<br>
</div>
</div>
<pre><br>/* SLAB cache for buffer_head structures */<br>kmem_cache_t *bh_cachep; <b>//作为buffer cache 的龙头, buffer_head 本身的分配是一个slab,不巧却定义在dcache.c</b><br><br>static struct buffer_head * <font color=#006600>unused_list</font>;<br>static int <font color=#006600>nr_unused_buffer_heads</font>;<br>static spinlock_t <font color=#006600>unused_list_lock</font> = SPIN_LOCK_UNLOCKED;<br><br>static __inline__ void <font color=#006600>__put_unused_buffer_head</font>(struct buffer_head * bh)<br>static struct buffer_head * <font color=#006600>get_unused_buffer_head</font>(int async)<br>从这两个函数可以知道,unused_list 作为一个buffer_head的free链表来使用,在kmem_cache 之上又有一个缓冲。其重要的作用之一<br>就是预存一定量的buffer_head, 以便在内存拮据的时候还能正常的进行操作。预存量是<font color=#006600> NR_RESERVED</font>。<br></pre>
<b>free list</b>是是buffer 的另外一个重要部分,那些用完的buffer, 但是( buffer_head, struct
page, data
buffer)的关系已经建立完成了,暂时缓存在这个链表中,只是他们已经不存在于hash表和lru队列中了,下次使用就不用在费时初始化(
buffer_head, struct page, data buffer)之间的关系了。<br>
<br>
static DECLARE_WAIT_QUEUE_HEAD(<font color=#006600>buffer_wait</font>);<br>
static struct bh_free_head
<font color=#006600>free_list</font>[NR_SIZES];<br>
<font color=#006600><font color=#000000>static void</font>
__remove_from_free_list(struct buffer_head * bh, int index)
//纯粹的链表操作<br>
<font color=#000000>static void</font> put_last_free(struct buffer_head
* bh)</font><font color=#006600>//纯粹的链表操作</font><br>
<font color=#006600><font color=#000000>void</font> init_buffer(struct
buffer_head *bh, bh_end_io_t *handler, void *private) //初始化buffer<br>
<font color=#000000>void</font> set_bh_page<font color=#000000> (struct
buffer_head *bh, struct page *page, unsigned long offset)</font>
//建立buffer的数据缓冲区<br>
<br>
</font><font color=#006600><b>对比一下unused list 分配出来的是buffer
head这个东西而已,而free_list中是一个完整的buffer。<br>
<br>
<br>
</b></font><br>
<br>
<div style=TEXT-ALIGN:center>
<b>1)既然是cache,就有一个hash结构</b><br>
</div>
hash的索引是(dev,block),这个dev是kdev_t,不是那个blkdev,block_device。。。kdev_t 到block
device的映射以后再谈吧。<b>值得说明的是只有加入了这个hash表的buffer才能叫做进入了buffer cache。</b><br>
这个部分包括hash表的hash算法,hash链表的维护(add delete 。。。),<br>
static unsigned int <font color=#006600>bh_hash_mask</font>;<br>
static unsigned int <font color=#006600>bh_hash_shift;</font><br>
static struct buffer_head **<font color=#006600>hash_tabl</font>e;<br>
static rwlock_t<font color=#006600> hash_table_lock</font> =
RW_LOCK_UNLOCKED;<br>
<br>
#define _hashfn(dev,block) 。。。<br>
#define <font color=#006600>hash</font>(dev,block)
hash_table[(_hashfn(HASHDEV(dev),block) & bh_hash_mask)]<br>
<br>
static __inline__ void <font color=#006600>__hash_link</font>(struct
buffer_head *bh, struct buffer_head **head)<br>
static __inline__ void <font color=#006600>__hash_unlink</font>(struct
buffer_head *bh)<br>
<br>
static inline struct buffer_head *<font color=#006600>
__get_hash_table</font>(kdev_t dev, int block, int size)<br>
struct buffer_head * <font color=#006600>get_hash_table</font>(kdev_t
dev, int block, int size)<br>
<br>
<div style=TEXT-ALIGN:center>
<b>2)缓存就要考虑数据老化,缓存回收的问题,所以有个lur list</b><br>
</div>
static struct buffer_head *<font color=#006600>lru_list</font>[NR_LIST];<br>
static spinlock_t<font color=#006600> lru_list_lock</font> =
SPIN_LOCK_UNLOCKED;<br>
static int <font color=#006600>nr_buffers_type</font>[NR_LIST];<br>
static unsigned long
<font color=#006600>size_buffers_type</font>[NR_LIST];<br>
<br>
呵呵,没有进行啥包装,整个struct 多好。列一下buffer的各种lru队列。<br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -