MD模組之處理讀寫過程分析 2

2021-04-24 14:03:57 字數 2693 閱讀 1333

這一節講述raid5模組中處理讀寫流程。這個過程很複雜,最關鍵的函式就是handle_stripe,處理一次讀或寫都會多次呼叫這個函式才能完成。當然,這個函式也是raid5模組的乙個核心函式,他還負責同步,重建,以及擴充套件的實現。在分析之前,我們需要準備一些預備知識:

一、條帶:我們知道,raid5是以條帶為基本單位來訪問資料的。如下圖所示:

raid5還有其它中資料分布方式,這裡只列出一種。圖中的block0,block1,block2等這些資料塊在邏輯上是連續的。

值得注意的是,md中raid5處理資料的最小單位是乙個由大小4kb組成的小條帶,即乙個頁大小,並不是一次處理乙個block大小的條帶。以後出現的條帶均指的是這個由4kb組成的小條帶。這個資料結構如下:

其中主要欄位的意義:

hash:條帶在緩衝中hash表項。

lru:條帶所處在那個鍊錶中

sector:條帶所處的扇區號,這個扇區號是從單個磁碟的起始位址算起的乙個偏移量。

state:條帶的狀態位

r5dev:條帶中描述每個裝置的緩衝區,這個結構體是處理io的最小單位,命令經計分解算之後,會被加入相應條帶中相應r5dev中的鍊錶中,也就是結構體中toread,towrite鍊錶中(通過bio->bi_next連線起來)。在這個結構體中字段req代表請求bio,vec代表bio中的段,sector的意義說該r5dev在陣列中的邏輯扇區號。flags欄位代表裝置緩衝區的狀態。這些狀態可以在raid5.h中找到.

二、條帶中裝置緩衝區的狀態

前面所說的r5dev中的flags欄位,其中兩位很重要,即

#define r5_uptodate 0 /* page contains current data */

#define r5_locked 1 /* io has been submitted on "req" */

這兩位可以代表緩衝區的4中狀態,依次是:empty (!r5_uptodate  !r5_locked )表明緩衝區為空

want (r5_locked  !r5_uptodate  )表明緩衝區要請求資料

clean (!r5_locked  r5_uptodate  )表明緩衝區中的資料與磁碟上的一致。

dirty(r5_locked  r5_uptodate  )表明緩衝區有有新的資料要寫入磁碟中。

在資料的讀寫過程中,緩衝區的狀態會伴隨著改變,這些將會在以後中體現。

接下來我們看看make_request函式,它的功能是實現了請求的重新分發,確定了bio會加入到那個條帶的那個裝置讀寫鍊錶中。具體過程如下:

(先略過**段,這段意義以後在說)

a、呼叫md_write_start函式,該函式判斷是否需要更新元資料。由於一些raid演算法帶有冗餘特性,比如raid1,raid5,那麼開始寫資料時,就要進行更新元資料,這防止寫資料不成功導致資料不正確,在陣列再次啟動時就會發起同步操作。寫完之後還要更新元資料。md是通過in_sync欄位來判斷的。如果in_sync=1,說明陣列是同步的。這時就有乙個疑問,不能來一次寫請求就更新二次元資料吧?確實,md為了防止這樣事情發生,引入了乙個定時器,即200ms內沒有連續的寫請求發過來就更新元資料。這個功能通過safemode值的過載來完成。

b、計算bio的起始邏輯扇區號logical_sector和最後扇區號last_sector,這裡的logical_sector計算方式為logical_sector = bi->bi_sector & ~((sector_t)stripe_sectors-1);其意義是將bio的起始扇區號對齊到條帶,即如果bi_sector=6的話,那麼logical_sector=0.

d、通過函式raid5_compute_sector計算logical_sector所在磁碟相對於開始位置的偏移量new_sector, 同時這個函式還確定了logical_sector所在條帶的裝置號dd_index和校驗盤號pd_index.

e、根據第三步計算的new_sector的值來獲取條帶,函式get_active_stripe首先判斷該條帶是否在條帶緩衝區中,如果在的話直接返回。否則試圖從inactive_list中尋找不活動的條帶,如果找到則呼叫init_stripe來初始化,否則休眠。這個函式的第三個引數代表是否通過非阻塞方式來獲取活動條帶。對於讀寫,我們發現第3個引數為(bi->bi_rw&rwa_mask),即處理讀寫時使用的阻塞的方式來獲取條帶,即保證了在讀寫的時一定要能獲取到條帶。如果找到了符合條件的條帶,如果在陣列在擴充套件中會判斷是否需要重試這個條帶。因為在獲取條帶的過程中可能引起休眠,就會導致原來logical_sector>expand_prograss變成了logical_sector

f、之後通過add_stripe_bio將這個bio插入到條帶中,注意,bio會被插入到多個條帶中,當每個條帶均處理完成時,這個bio也就處理完了,這個計數器是由bi_phys_segments來維護的。當bio插入到乙個條帶中bi_phys_segments++,當處理完乙個條帶bi_phys_segments--。這個函式還會判斷要插入的bio是否覆蓋整個r5dev,即是否為滿寫,這個判斷在處理寫請求(以rcw方式)時有用。

g、此時,我們已經把bio加入到了該加入的條帶中,之後就要處理這個條帶。這個功能由handle-stripe函式來完成。由於這個函式很複雜,我會在下一節中單獨做分析。

h、handle_stripe函式結束之後,會release_stripe函式,這個函式的功能就是根據條帶的狀態將調到加入到不同的鍊錶中以便之後繼續使用。

下一節我會以一次簡單的讀寫來分析handle_stripe函式。讀比較簡單,寫過程較麻煩,涉及到了延遲寫。

MD模組之處理讀寫過程分析 3

這節我們來分析神奇而又nb的handle stripe,2.6.21版本的處理raid5和raid6分別用handle stripe5和handle stripe6這兩個函式,我們這裡主要說handle stripe5,handle stripe6和handle stripe5其實差不多,只要你理解...

HDFS讀寫過程

讀過程 1 初始化filesystem,然後客戶端 client 用filesystem的open 函式開啟檔案 2 filesystem用rpc呼叫元資料節點,得到檔案的資料塊資訊,對於每乙個資料塊,元資料節點返回儲存資料塊的資料節點的位址。3 filesystem返回fsdatainputstr...

Hbase讀寫過程

補充 布隆過濾器引數型別有2種 row row col 細節描述 hbase使用memstore和storefile儲存對錶的更新。資料在更新時首先寫入log wal log 和記憶體 memstore 中,memstore中的資料是排序的,當memstore累計到一定閾值時,就會建立乙個新的mem...