linux下buffer與cache的區別
如文中我有理解錯誤的地方也請各位及時指出,如轉載請註明出處。
(本文所有截圖來自《深入理解linux內核-第三版》 DANIEL P.BOVET & MARCO
CESATE著 陳莉君 張瓊聲 張宏偉 譯 中國電力出版社)提前需了解的內容, VFS, inode,address_space,radix_tree之前關聯 :(可參考之前的一個回答https://www.zhihu.com/question/52639327/answer/134434918)
先說總結:
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:
緩衝區首部(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:
對於截圖3中說的第一種情況,這裡舉個例子,如下面圖中,如果該頁屬於同一個文件,且文件所在的文件系統的 block size 為1k, 頁面中的4個block如果在磁碟上都不連續,那麼這個頁面就成為buffer page,且有與頁中4個block相關的buffer_head結構:
對於截圖3中所說的第二種情況:
由些可見,從磁碟讀出來的文件在file system上的inode(ext3_inode ?)信息是放在buffer page里的,但是,這種page的所有者(如果一個cache頁面是某文件的內容,那麼我們說這個文件是此頁面的所有都,或者屬主)是哪個文件呢?往下看截圖7的第二段:
,感謝知友 @賈斯特度 在評論區發出的疑問,我又查了關於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的相關函數內容(原文件鏈接:https://github.com/liuyangc3/note-book/blob/master/kernel/Cache%20and%20Buffer.md):
buffer:
從 free 命令的代碼里(項目地址 http://procps.sourceforge.net)
可以得知命令的數值實際上是 從 /proc/meminfo 來的,而 meminfo 的數值是從系統調用 sysinfo 來的。具體詳情 http://blog.csdn.net/lux_veritas/article/details/19231993
文章里提到了一個函數 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 的描述:
英文版:
推薦閱讀:
※生產伺服器的高危操作有哪些?
※什麼是LFS,作為一個初學者應該先學習什麼才能初步了解LFS?
※Linux下編寫腳本Shell和Python的區別?
※空閑伺服器能用來做什麼?你有什麼使用伺服器的有趣經歷嘛?
※女生去馬哥培訓學linux運維怎麼樣?