[IO系統]11 回寫機制(writeback)
在Linux-3.2新核心中,page cache和buffer cache的重新整理機制發生了改變。放棄了原有的pdflush機制,改成了bdi_writeback機制。這種變化主要解決原有pdflush機制存在的一個問題:在多磁碟的系統中,pdflush管理了所有磁碟的page/buffer cache,從而導致一定程度的IO效能瓶頸。bdi_writeback機制為每個磁碟都建立一個執行緒,專門負責這個磁碟的pagecache或者buffer cache的資料重新整理工作,從而實現了每個磁碟的資料重新整理程式線上程級的分離,這種處理可以提高IO效能。
1.1 writeback機制模型
writeback機制的基本原理可以描述如下:
在Linux核心中有一個常駐記憶體的執行緒bdi_forker_thread,該執行緒負責為bdi_object建立writeback執行緒,同時檢測如果writeback執行緒長時間處於空閒狀態,bdi_forker_thread執行緒便會將其進行銷燬。bdi_forker_thread在系統中只有一個,其會被定時喚醒,檢查全域性連結串列bdi_list佇列中是否存在dirty的資料需要重新整理到磁碟。如果存在dirty資料並且對應bdi的writeback執行緒還沒有被建立,bdi_forker_thread會為該bdi建立一個writeback的執行緒進行寫回操作。
writeback執行緒被建立之後會處理等待的work。writeback執行緒擁有一個定時器會週期性喚醒這個執行緒處理相應的work。當用戶(page cache/buffer cache)有需要處理的inode時,將inode掛載到writeback->b_dirty連結串列中,然後喚醒writeback執行緒去處理相應的dirty_page。inode連結串列就是writeback執行緒需要處理的資料;work連結串列就是控制處理過程中的一些策略,不同的策略可以定義成不同的任務。
通過上述模型,對於塊裝置或者檔案系統而言,實現dirty page的後臺重新整理主要做如下幾個方面的工作:
1,將自己的bdi註冊到系統的bdi連結串列中,通過bdi_forker_thread實現對bdi物件的管理,從而可以實現writeback執行緒的動態建立、銷燬。每個塊裝置和檔案系統都有自己的bdi物件。Ext3檔案系統在建立的時候會生成superblock物件,系統會將底層塊裝置的backing_device關係到這個superblock物件上(在set_bdev_super函式中完成)。如果是塊裝置的話,在add_disk的時候直接從request_queue中得到bdi物件,然後對其進行初始化。註冊bdi物件使用bdi_register_dev函式,對於ext3之類的檔案系統不需要重新註冊bdi物件,因為其本身就採用了底層塊裝置的bdi物件。
2,將需要重新整理的inode節點掛載到bdi物件所屬的writeback->b_dirty上,如果有特殊的work需要writeback執行緒完成,那麼提交一個work即可;如果是通常的週期性重新整理,writeback執行緒會自動建立相應的work。
3,操作writeback的喚醒定時器延遲喚醒writeback執行緒,或者直接喚醒執行緒,從而使得inode中radix tree上的dirty page重新整理到磁碟。
1.2 bdi物件的註冊
每個塊裝置在建立的時候會註冊bdi物件(參見add_disk函式),這是Linux-3.2核心不同的地方。檔案系統在mount的時候會建立superblock物件,並且通過底層塊裝置的request queue獲取bdi物件(mount_bdev->sget->set_bdev_super)。所以,像ext3之類的檔案系統都不需要重新註冊bdi物件。當然,如果檔案系統重新建立了一個bdi物件,那麼還需要呼叫bdi_register_dev函式註冊bdi物件。
1.3 小結
本文對linux-3.2中的writeback機制模型進行了闡述,後面還會對writeback機制中的關鍵函式進行分析說明。該機制是對老系統(Linux-2.6.23等)中pdflush機制的替代,其最重要的變化是每個塊裝置都分配了writeback執行緒,使得回寫的IO流在各個磁碟之間獨立,從而從機制上提高了IO的吞吐量。
1.4 參考文獻
[部落格] http://alanwu.blog.51cto.com/3652632/1109952