小結:
1. 塊i/o層的資料結構
bio:表示活動的i/o操作
buffer_head:表示塊到頁的對映
request:具體的i/o請求
2. i/o請求的簡單宣告歷程
請求佇列的產生、處理、排程
3. i/o排程程式
linus、deadline、cfq、noop
14.4 請求佇列
14.5 i/o排程程式
塊裝置,系統能夠隨機訪問固定大小資料片(chunks)的硬體裝置,他們基本以檔案系統的方式使用。另一種基本的裝置型別時字元裝置。這兩種裝置的區別在於是否可以隨機訪問資料。核心塊裝置管理比管理字元裝置麻煩得多。
當乙個塊被調入記憶體時(在讀入後或寫出時),它要儲存在乙個緩衝區中,每乙個緩衝區與乙個塊對應,乙個塊包含乙個或多個扇區,但不能超過乙個頁面。由於核心在處理資料時需要一些相關的控制資訊(如塊屬於哪個裝置,塊對應哪個緩衝區等),因此每個緩衝區都有乙個對應的描述符,描述符用buffer_head表示。
struct buffer_head ;
(1). b_state域表示緩衝區的狀態。合法的標識存放在bh_state_bits中
狀態標誌
意義bh_uptodate該緩衝區包含可用資料
bh_dirty該緩衝區是髒的
bh_lock
該緩衝區正在被i/o操作使用,被鎖定以防被併發訪問
bh_req
該緩衝區有i/o請求操作
該緩衝區是對映磁碟塊的可用緩衝區
bh_new
緩衝區是通過get_block()剛剛對映的,尚且不能訪問
bh_async_read
該緩衝區正通過end_buffer_async_read()被非同步i/o讀操作使用
bh_async_write
該緩衝區正通過end_buffer_async_write()被非同步i/o寫操作使用
bh_delay
該緩衝區尚未和磁碟塊關聯
bh_boundary
該緩衝區處於連續塊區的邊界 - 下乙個塊不再連續
bh_wirte_eio
該緩衝區在寫的時候遇到i/o錯誤
bh_ordered
順序寫bh_unwritten
該緩衝區在硬碟上的空間已被申請但是沒有實際的資料寫出
bh_quiet
該緩衝區禁止錯誤
bh_state_bits列表還包含乙個特殊標誌----bh_privatestart,以指明可被其他**使用的起始位。塊i/o層不會使用bh_privatestart或更高位。那麼某個驅動程式希望通過b_state域儲存資訊時就可以安全使用這些位。
(2). b_count
在操作緩衝區頭之前,應先使用get_bh()增加引用,確保該緩衝區頭不會再被分配出去;完成操作之後,put_bh()減少引用計數。
(3). b_blocknr-th是緩衝區對應的磁碟物理塊的邏輯塊號
(4). b_page是緩衝區對應的記憶體物理頁
(5). b_data直接指向響應的塊(位於b_page域所指明的頁面中的某個位置上),塊在記憶體中的起始位置在b_data處,結束在(b_data + b_size) 處。
總之,緩衝區頭的目的在於描述磁碟塊和物理記憶體緩衝區(在特定頁面上的位元組序列)之間的對映關係。這個結構體在核心中只扮演乙個從緩衝區到塊的對映關係的作用。
弊端:(1). 緩衝區頭很大且是不易控制的資料結構
(2). 僅能描述單個緩衝區,當作為i/o容器使用時,將大塊資料的i/o操作分解為對多個buffer head的操作。
目前塊i/o操作的基本容器由bio結構體表示。該結構體代表了正在活動的以segment鍊錶形式組織的塊i/o操作,乙個segment是一小塊連續的記憶體緩衝區,這樣bio可以用多個segment描述分散在記憶體多個位置上的緩衝區。
bio結構體
bio結構體主要是代表正在現場執行的i/o操作,重要的幾個域是bi_io_vecs、bi_vcnt和bi_idx。
bio_io_vec結構體
bio_io_vec結構體陣列指向乙個bio_vec結構體陣列,表示乙個完整的緩衝區。bio_vec結構指明
bi_cnt引用計數
如果該值為0,則撤銷該bio結構體,釋放記憶體。通過:
bio_get(bio)
bio_put(bio)
進行管理,在操作正在活動的bio結構體時,一定要先增加它的引用計數,以免操作時bio被釋放;操作完畢後,減少引用計數。
bi_private
建立者的私有域
意義缺點
優點buffer_head
代表的是乙個緩衝區,描述僅僅磁碟中的乙個塊
關聯的是單獨頁的單獨磁碟塊,會引起不必要的分割,將請求按塊為單位劃分
負責磁碟塊到頁面的對映等緩衝區資訊
bio代表i/o操作,可以包含記憶體中乙個或多個頁
1. bio是輕量級的,僅需包含io操作資訊,不許緩衝區資訊;不需要連續儲存,不需要分割i/o操作。2.bio容易處理高階記憶體,因為它處理的是物理頁而不是直接指標;
總之,核心通過這兩種結構,各司其職,buffer_head負責描述磁碟塊到頁面的對映,bio結構體不含任何和緩衝區相關的狀態資訊,bio描述正在使用的i/o操作資訊。
請求佇列的產生:
塊裝置將他們掛起的塊i/o請求儲存在請求佇列(request_queue)中,通過核心中像檔案系統這樣的高層**將請求插入到佇列,只要請求佇列不為空,佇列對應的塊裝置驅動程式就會從佇列頭獲取請求並送入對應塊裝置。
請求佇列結構:
請求隊列表中的每一項都是乙個單獨的請求,由request表示。因為乙個請求可能要操作多個連續的磁碟塊,所以每個請求可以由多個bio結構組成。(注意,雖然磁碟塊必須連續,但記憶體中這些塊不一定要連續,每個bio結構體可以描述多個片段,片段是記憶體中連續的小區域)
核心中負責提交i/o請求的子系統成為i/o排程程式。io排程程式的工作是管理塊裝置的請求佇列。
(1)如果佇列中已存在乙個對相鄰磁碟扇區操作的請求,那麼新請求將和這個已經存在的請求合併
(2)如果佇列中存在乙個駐留時間過長的請求,那麼新請求將被插入佇列尾部
(3)如果佇列中以扇區方向為序存在合適的插入位置,那麼新請求插入此位置,保證佇列中請求是以被訪問磁碟物理位置為序排列
(4)如果佇列中不存在合適的請求插入位置,插入到佇列尾部。
問題:「年齡」檢測方法改善了等待時間但還是會導致請求飢餓現象的發生
deadline中每個請求都有乙個超時時間,預設情況下讀為500ms,寫為5s。
特點:防止請求飢餓現象;確保寫請求不會堵塞讀請求。
主要改進:請求提交後不直接返會處理其他請求,而是會空閒片刻,使應用程式可以提供其他讀請求 ----任何對相鄰磁碟位置操作的請求都會立刻得到處理。(目的:減少讀請求所帶來的向後再向前定址操作)
**i/o排程能帶來的優勢取決於能否正確**應用程式和檔案系統的行為。
cfq i/o排程程式將進入的i/o請求放入特定的佇列中,佇列是根據引起i/o請求的程序組織的。如foo程序將i/o請求放入foo佇列。
cfq按時間片輪轉
空操作的i/o排程程式只會將任一相鄰的請求合併。專門為隨機訪問裝置而設計。
linux核心之裝置I O塊
為了優化定址操作,核心既不會簡單的按請求接收次序,也不會立即將請求提交給磁碟。相反,核心在提交前,先執行名為合併與排序的預操作,這種預操作可以極大的提高系統的整體效能。在核心中負責提交i o請求的子系統統稱為i o排程程式。i o排程程式將磁碟i o資源分配給系統中掛起的塊i o請求。具體的說,這種...
linux 核心設計與實現相關
有待繼續補充。第一章 linux核心簡介 需要注意 核心開發其實並不難。第二章 從核心出發 核心開發需要注意 1 沒有c庫,c庫太大了 2 沒有記憶體保護機制 3 不要輕易使用浮點數 4 可移植的重要性 5 同步和併發 疑問 編譯和安裝核心?必須在linux下麼?其他機器安裝了gcc編譯器呢?能否編...
Linux核心設計與實現總結。
1.程序管理。本章主要是介紹程序的乙個靜態的狀態,包括系統如何組織程序。建立,啟動,到最後死亡的乙個概念性認識,沒有更加深刻的知識。2.程序排程。本章比較重要。1.搶占式排程策略。2.倆程序間上下文切換 有倆函式 switch mm 和 switch to倆函式完成此功能。具體細節需要閱讀其他書籍 ...