上一節講到在raid5的同步函數sync_request中炸馬鈴薯片是通過handle_stripe來進行的。從最初的建立陣列,到申請各種資源,建立每個陣列的personality,所有的一切都是為了迎接資料流而作的準備。就像我們寒窗苦讀就是為了上大學一樣。資料流的過程就像大學校園一樣豐富多彩並且富有挑戰性,但只要跨過了這道坎,核心代碼將不再神秘,剩下的問題只是時間而已。
首先看handle_stripe究竟把我們的馬鈴薯片帶往何處:
3379 static void handle_stripe(struct stripe_head *sh) 3380 { 3381 struct stripe_head_state s; 3382 struct r5conf *conf = sh->raid_conf; 3383 int i; 3384 int prexor; 3385 int disks = sh->disks; 3386 struct r5dev *pdev, *qdev; 3387 3388 clear_bit(STRIPE_HANDLE, &sh->state); 3389 if (test_and_set_bit_lock(STRIPE_ACTIVE, &sh->state)) { 3390 /* already being handled, ensure it gets handled 3391 * again when current action finishes */3392 set_bit(STRIPE_HANDLE, &sh->state); 3393 return; 3394 } 3395 3396 if (test_and_clear_bit(STRIPE_SYNC_REQUESTED, &sh->state)) { 3397 set_bit(STRIPE_SYNCING, &sh->state); 3398 clear_bit(STRIPE_INSYNC, &sh->state); 3399 } 3400 clear_bit(STRIPE_DELAYED, &sh->state); 3401 3402 pr_debug("handling stripe %llu, state=%#lx cnt=%d, "3403 "pd_idx=%d, qd_idx=%d\n, check:%d, reconstruct:%d\n", 3404 (unsigned long long)sh->sector, sh->state, 3405 atomic_read(&sh->count), sh->pd_idx, sh->qd_idx, 3406 sh->check_state, sh->reconstruct_state); 3407 3408 analyse_stripe(sh, &s);
這個函數代碼比較長先貼第一部分,分析條帶。分析的作用就是根據條帶的狀態做一些預先處理,根據這些狀態再來判斷下一步應該做什麼具體操作。比如說同步,那麼首先會讀資料盤,等讀回來之後,再校正,然後再寫校正值。但是這些步驟又不是一次性在handle_stripe裡就完成的,因為跟磁碟IO都是非同步,所以必要要等上一次磁碟請求回調之後再次調用handle_stripe,通常每個資料流都會多次進入handle_stripe,而每一次進入經過的代碼流程是不大一樣的。
struct stripe_head有很多狀態,這些狀態決定條帶應該怎麼處理,所以必須非常小心處理這些標誌,這些標誌很多,現在先簡單地過一下。
enum { STRIPE_ACTIVE, // 正在處理 STRIPE_HANDLE, // 需要處理 STRIPE_SYNC_REQUESTED, // 同步請求 STRIPE_SYNCING, // 正在處理同步 STRIPE_INSYNC, // 條帶已同步 STRIPE_PREREAD_ACTIVE, // 預讀 STRIPE_DELAYED, // 延遲處理 STRIPE_DEGRADED, // 降級 STRIPE_BIT_DELAY, // 等待bitmap處理 STRIPE_EXPANDING, // STRIPE_EXPAND_SOURCE, // STRIPE_EXPAND_READY, // STRIPE_IO_STARTED, /* do not count towards 'bypass_count' */ // IO已下發 STRIPE_FULL_WRITE, /* all blocks are set to be overwritten */ // 滿寫 STRIPE_BIOFILL_RUN, // bio填充,就是將page頁拷貝到bio STRIPE_COMPUTE_RUN, // 運行計算 STRIPE_OPS_REQ_PENDING, // handle_stripe排隊用 STRIPE_ON_UNPLUG_LIST, // 批量release_stripe時標識是否加入unplug鏈表 };
3388行,清除需要處理標誌。
3389行,設定正在處理標誌。
3392行,如果已經在處理則設定下次處理標誌並返回。
3396行,如果是同步請求。
3397行,設定正在處理同步標誌。
3398行,清除已同步標誌。
3400行,清除延遲處理標誌。
3408行,分析stripe,這個函數很長分幾段來說明: