深刻理解Linux VFS和Page Cache

 戳藍字「TopCoder」關注咱們哦!html

編者注:在分析完 Linux inode 基礎概念 以後,讓咱們看下inode在內存中對應的文件系統抽象VFS,而後分析下關於 磁盤操做 中Page Cache的回寫策略。node

VFS(虛擬文件系統層)

VFS是虛擬文件系統層(進程與文件系統之間的抽象層),與它相關的數據結構只存在於物理內存當中。其目的是屏蔽下層具體文件系統操做的差別,爲上層的操做提供一個統一接口,正是因爲VFS的存在,Linux中容許多個不一樣的文件系統共存。web

VFS中包含着向物理文件系統轉換的一系列數據結構,如VFS超級塊、VFS的Inode、各類操做函數的轉換入口等。Linux中VFS依靠四個主要的數據結構來描述其結構信息,分別爲超級塊、索引結點、目錄項和文件對象,這些數據結構大都會與磁盤上的對應上。算法

  • 超級塊(Super Block):超級塊對象表示一個文件系統。它存儲一個已安裝的文件系統的控制信息,包括文件系統名稱(好比Ext2)、文件系統的大小和狀態、塊設備的引用和元數據信息(好比空閒列表等等)。超級塊與磁盤上文件系統的超級塊對應。緩存

  • 索引結點(Inode):索引結點對象存儲了文件的相關元數據信息,例如:文件大小、設備標識符、用戶標識符、用戶組標識符等等。Inode分爲兩種:一種是VFS的Inode,一種是具體文件系統的Inode。前者在內存中,後者在磁盤中。因此每次實際上是將磁盤中的Inode調進填充內存中的Inode,這樣纔是算使用了磁盤文件Inode。當建立一個文件的時候,就給文件分配了一個Inode。一個Inode只對應一個實際文件,一個文件也會只有一個Inode(Unix/Linux系統中目錄也是一種文件,打開目錄實際上就是打開目錄文件。目錄文件的結構很是簡單,就是一系列目錄項(dirent)的列表。每一個目錄項,由兩部分組成:所包含文件的文件名,以及該文件名對應的inode號碼)。微信

  • 目錄項(Dentry):引入目錄項對象的概念主要是出於方便查找文件的目的。不一樣於前面的兩個對象,目錄項對象只存在於內存中,實際對應的是磁盤的目錄innode對象。VFS在查找的時候,根據一層一層的目錄項找到對應的每一個目錄項的Inode,那麼沿着目錄項進行操做就能夠找到最終的文件。數據結構

  • 文件對象(File):文件對象描述的是進程已經打開的文件。由於一個文件能夠被多個進程打開,因此一個文件能夠存在多個文件對象,但多個文件對象其對應的索引節點和目錄項對象確定是唯一的,關係以下圖:app

因爲進程中File對象有獨立的文件偏移量(current file offset),所以多個進程能夠讀寫文件的不一樣位置的數據,可是通常不建議這樣玩,由於系統不保證該狀況下的寫的原子性,多進程能夠經過文件鎖實現對文件內容的寫保護。函數

PageCache

Page cache是經過將磁盤中的數據緩存到內存中,從而減小磁盤I/O操做,從而提升性能。此外,還要確保在page cache中的數據更改時可以被同步到磁盤上,後者被稱爲page回寫(page writeback)。一個inode對應一個page cache對象,一個page cache對象包含多個物理page。性能

當內核發起一個讀請求時(例如進程發起read()請求),首先會檢查請求的數據是否緩存到了page cache中,若是有,那麼直接從內存中讀取,不須要訪問磁盤,這被稱爲cache命中(cache hit)。若是cache中沒有請求的數據,即cache未命中(cache miss),就必須從磁盤中讀取數據。而後內核將讀取的數據緩存到cache中,這樣後續的讀請求就能夠命中cache了。page能夠只緩存一個文件部分的內容,不須要把整個文件都緩存進來。

當內核發起一個寫請求時(例如進程發起write()請求),一樣是直接往cache中寫入,此時不會當即同步到磁盤,而是將寫入的page設置爲髒頁,並將其加入dirty list中,內核會負責按期同步到磁盤保持兩者一執行。

page cache另外一個主要工做是回收page釋放內存空間,此時會選擇合適的page進行釋放,若是是髒頁會先同步到磁盤而後釋放。此時是如何選擇cache頁的呢?Linux使用的策略是基於LRU改進的Two-List策略:

Two-List策略維護了兩個list,active list 和 inactive list。在active list上的page被認爲是hot的,不能釋放。只有inactive list上的page能夠被釋放的。首次緩存的數據的page會被加入到inactive list中,已經在inactive list中的page若是再次被訪問,就會移入active list中。兩個鏈表都使用了僞LRU算法維護,新的page從尾部加入,移除時從頭部移除,就像隊列同樣。若是active list中page的數量遠大於inactive list,那麼active list頭部的頁面會被移入inactive list中,從而位置兩個表的平衡。

觸發髒頁回寫到磁盤時機以下:

  • 用戶進程調用sync() 和 fsync()系統調用;

  • 空閒內存低於特定的閾值(threshold);

  • Dirty數據在內存中駐留的時間超過一個特定的閾值。

注意這裏的page cache的髒頁回寫機制能夠和mmap的髒頁回寫機制作下對比,mmap會在必定時間後系統自動回寫髒頁面到磁盤,也就是說mamp中修改過的髒頁面並不會當即更新迴文件中,而是有一段時間的延遲,能夠調用msync()來強制同步, 這樣所寫的內容就能當即保存到文件裏了。


 推薦閱讀 


歡迎小夥伴 關注【TopCoder】 閱讀更多精彩好文。

本文分享自微信公衆號 - TopCoder(gh_12e4a74a5c9c)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索