Page Cache

Page Cache

page cache,又稱pcache,其中文名稱為頁高速緩衝存儲器,簡稱頁高緩。在從外存的一頁到內存的一頁的映射過程中,page cache與buffer cache、swap cache共同實現了高速緩存功能。

正文


一、page cache簡介
page cache,又稱pcache,其中文名稱為頁高速緩衝存儲器,簡稱頁高緩。page cache的大小為一頁,通常為4K。在linux讀寫文件時,它用於緩存文件的邏輯內容,從而加快對磁碟上映像和數據的訪問。
二、page cache的功能詳解
在從外存的一頁到內存的一頁的映射過程中,page cache與Buffer Cache、swap cache共同實現了高速緩存功能,以下是其簡單映射圖,
外存的一頁(分解為幾塊,可能不連續)
|
|
物理磁碟的磁碟塊
|
|
內存的buffer cache
|
|
內存的一頁(由一個頁框劃分的幾個連續buffer cache構成)
|
|
頁高緩系統
在這個過程中,內存管理系統和VFS與page cache交互,內存管理系統負責維護每項page cache的分配和回收,同時在使用memory map方式訪問時負責建立映射;VFS負責page cache與用戶空間的數據交換。
三、page cache的管理
Linux內核中,文件的每個數據塊最多只能對應一個page cache項,它通過兩個數據結構來管理這些cache項,一個是radix tree,另一個是雙向鏈表
Radix tree是一種搜索樹,Linux內核利用這個數據結構,快速查找髒的(dirty)和回寫的(writeback)頁面,得到其文件內偏移,從而對page cache進行快速定位。圖1是radix tree的一個示意圖,該radix tree的分叉為4(22),樹高為4,用來快速定位8位文件內偏移。
另一個數據結構是雙向鏈表,Linux內核為每一片物理內存區域(zone)維護active_list和 inactive_list兩個雙向鏈表,這兩個list主要用來實現物理內存的回收。這兩個鏈表上除了文件Cache之外,還包括其它匿名 (Anonymous)內存,如進程堆棧等。
四、page cache相關API及其實現
Linux內核中與文件Cache操作相關的API有很多,按其使用方式可以分成兩類:一類是以拷貝方式操作的相關介面,如read/write/sendfile等,其中sendfile在2.6系列的內核中已經不再支持;另一類是以地址映射方式操作的相關介面,如mmap等。
第一種類型的API在不同文件的Cache之間或者Cache與應用程序所提供的用戶空間buffer之間拷貝數據,其實現原理如圖2所示。
第二種類型的API將Cache項映射到用戶空間,使得應用程序可以像使用內存指針一樣訪問文件,Memory map訪問Cache的方式在內核中是採用請求頁面機制實現的,其工作過程如圖3所示。
首先,應用程序調用mmap(圖中1),陷入到內核中后調用do_mmap_pgoff(圖中2)。該函數從應用程序的地址空間中分配一段區域作為映射的內存地址,並使用一個VMA(vm_area_struct)結構代表該區域,之後就返回到應用程序(圖中3)。當應用程序訪問mmap所返回的地址指針時(圖中4),由於虛實映射尚未建立,會觸發缺頁中斷(圖中5)。之後系統會調用缺頁中斷處理函數(圖中6),在缺頁中斷處理函數中,內核通過相應區域的 VMA結構判斷出該區域屬於文件映射,於是調用具體文件系統的介面讀入相應的Page Cache項(圖中7、8、9),並填寫相應的虛實映射表。經過這些步驟之後,應用程序就可以正常訪問相應的內存區域了。

加入/離開page cache還涉及到如下幾個函數:


add_page_to_hash_queue
add_page_to_inode_queue
remove_page_from_inode_queue
remove_page_from_hash_queue
__remove_inode_page
remove_inode_page
add_to_page_cache_locked
__add_to_page_cache
僅羅列函數add_page_to_hash_queue,以示完整:
color=green>
static void add_page_to_hash_queue(struct page * page, struct page **p)
{
struct page *next = *p;
*p = page;
page->next_hash = next;
page->pprev_hash = p;
if (next)
next->pprev_hash = &page->next_hash;
if (page->buffers)
PAGE_BUG(page);
atomic_inc(&page_cache_size);
}

page cache 和 inode


page cache 在代碼中又稱 inode page cache, 足以顯示page cache 和inode緊密關聯。加入page cache 和加入inode cache是同一個意思。加入page cache意味著同時加入page cache hash表和inode queue(也建立了page和addr sapce的關係). 見函數add_to_page_cache_locked,__add_to_page_cache即可取證。從page cache 刪除在程序中叫__remove_inode_page,再次顯示inode 和page cache的"一體化".