linux下buffer與cache的區別

如文中我有理解錯誤的地方也請各位及時指出,如轉載請註明出處。

(本文所有截圖來自《深入理解linux內核-第三版》 DANIEL P.BOVET & MARCO

CESATE著 陳莉君 張瓊聲 張宏偉 譯 中國電力出版社)

提前需了解的內容, VFS, inode,address_space,radix_tree之前關聯 :(可參考之前的一個回答zhihu.com/question/5263

先說總結:

1. Linux2.4.10之前的內核中,分兩種disk cache, 分別為buffer cache和page cache,區別見文章最後兩個截圖(至於具體裡面放什麼結構的數據,我也不知道,還沒看過2.4內核的塊設備和VFS這部分內容)。

2. 大約2.4.10後的內核,buffer cache已經不存在了(或者說換了一種數據存放的方法) 而這種頁面的叫法也變了,叫做 buffer page, 而buffer page放在什麼地主呢? 它放在page cache中。

聽著很繞口, 或者可以這樣講: 2.4.10之後的內核的disk cache 只有 page cache, 而page cache中有些頁面被叫做buffer page的,是因為這些頁面(buffer page)都有與其相關的buffer_head 描述符,也正是這樣頁面被free 統計為 buffer 佔用。如果沒有buffer_head與該頁相關,則被free統計為 cache佔用。 Buffer page 與 buffer_head(下圖中右邊方框里的 緩衝區首部 )的關聯如下 截圖1:

(截圖 1, 書611頁)

緩衝區首部(buffer_head)的結構(include/linux/fs.h):

struct buffer_head {/* First cache line: */struct buffer_head *b_next; /* Hash queue list*/unsigned long b_blocknr; /* block number */unsigned short b_size; /* block size */unsigned short b_list; /* List that this buffer appears */kdev_t b_dev; /* device (B_FREE = free) */atomic_t b_count; /* users using this block */kdev_t b_rdev; /* Real device */……char * b_data; /* pointer to data block (512byte) */struct page *b_page; /* the page this bh is mapped to */void (*b_end_io)(struct buffer_head *bh, intuptodate); /* I/O completion */void *b_private; /* reserved for b_end_io */unsigned long b_rsector; /* Real buffer location on disk */wait_queue_head_t b_wait;struct inode * b_inode;struct list_head b_inode_buffers; /* doublylinked list of inode dirty buffers */};

注意結構中下面的三個欄位:

  • kdev_t b_dev:表示包含該塊的塊設備,通常是一個磁碟或分區
  • unsigned long b_blocknr;存放邏輯塊號,表示塊在磁碟或分區上的邏輯塊號
  • struct page *b_page; 指向包含該塊的頁描述符

buffer_head 結構中以上三個欄位把頁中的內容和磁碟上的塊直接關聯起來。

下面來說說,buffer page裡面放的是什麼

首先我們應該了解何時,內核會分配buffer page:

(截圖2, 書609頁)

(截圖3,書610頁)

對於截圖3中說的第一種情況,這裡舉個例子,如下面圖中,如果該頁屬於同一個文件,且文件所在的文件系統的 block size 為1k, 頁面中的4個block如果在磁碟上都不連續,那麼這個頁面就成為buffer page,且有與頁中4個block相關的buffer_head結構:

(截圖4,書560頁)

(截圖5,書610頁)

對於截圖3中所說的第二種情況:

(截圖6,書610頁)

由些可見,從磁碟讀出來的文件在file system上的inode(ext3_inode ?)信息是放在buffer page里的,但是,這種page的所有者(如果一個cache頁面是某文件的內容,那麼我們說這個文件是此頁面的所有都,或者屬主)是哪個文件呢?往下看截圖7的第二段:

(截圖7-書599頁)

,感謝知友 @賈斯特度 在評論區發出的疑問,我又查了關於bdev文件系統的內容,修正我的理解:

Buffer Page的所有者(即屬主)為被打開的這個設備文件, 且buffer page被插入到設備文件對應的 特殊文件系統(此處為bdev文件系統)的inode->address_space的page_tree中, 即:

  • bdev文件系統中為該設備建立的inode為 設備的 」主inode「.
  • 設備文件自身(如/dev/sdb這個文件)對應的inode為設備的 」次inode「

最後,直接訪問一個設備文件會發生什麼呢?架個虛擬機,啟動一段時間後,待free輸出cache和buffer部分穩定後,再執行下面內容:

#free 記錄輸出中buffer和cache的大小

#cat /proc/slabinfo |grep buffer_head 記錄buffer_head的分配和使用數量

#cat /dev/sdb1 >/dev/null 這條命令執行完成後,再執行free 和cat /proc/slabinfo 查看輸出 並和前面做對比。


最後帖一個linux 統計buffer的相關函數內容(原文件鏈接:github.com/liuyangc3/no):

buffer:

從 free 命令的代碼里(項目地址 http://procps.sourceforge.net)

可以得知命令的數值實際上是 從 /proc/meminfo 來的,而 meminfo 的數值是從系統調用 sysinfo 來的。

具體詳情 blog.csdn.net/lux_verit

文章里提到了一個函數 si_meminfo mm/page_alloc.c

void si_meminfo(struct sysinfo *val) { val->totalram = totalram_pages; val->sharedram = 0; val->freeram = global_page_state(NR_FREE_PAGES); val->bufferram = nr_blockdev_pages(); val->totalhigh = totalhigh_pages; val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; }

可以看到 bufferram 的值是函數 nr_blockdev_pages() 得到的 fs/block_dev.c

long nr_blockdev_pages(void){struct block_device *bdev;long ret = 0;spin_lock(&bdev_lock);list_for_each_entry(bdev,&all_bdevs, bd_list) { ret+= bdev->bd_inode->i_mapping->nrpages;}spin_unlock(&bdev_lock);return ret;}

可以看到這個函數其實就是,遍歷了所有的塊設備,然後把這些設備 bd_inode 上的 pages 數目加起來。這些 page 由內核通過一顆 radix tree 來維護,而 nrpages 記錄了tree pages 的數量。buffer 統計的是所有block device 對應的inode的 address_space的 page的數量。

如何增加 buffers ?

cat /dev/sda1 > /dev/null

所以可以確定的是直接訪問 block 設備產生的 page cache是保存到 block device的 bd_inode 裡面的。


另:關於linux 2.4.10之前內核對buffer和cache 的描述:

(截圖8—書607頁)

英文版:

推薦閱讀:

生產伺服器的高危操作有哪些?
什麼是LFS,作為一個初學者應該先學習什麼才能初步了解LFS?
Linux下編寫腳本Shell和Python的區別?
空閑伺服器能用來做什麼?你有什麼使用伺服器的有趣經歷嘛?
女生去馬哥培訓學linux運維怎麼樣?

TAG:Linux运维 | Linux系统管理 | Linux |