上節我們講到條塊內讀失敗,在回呼函數raid5_align_endio中將請求加入陣列重試鏈表,在喚醒raid5d線程之後,raid5d線程將該請求調用retry_aligned_read函數進行重試讀:
4539static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio) 4540{ 4541 /* We may not be able to submit a whole bio at once as there 4542 * may not be enough stripe_heads available. 4543 * We cannot pre-allocate enough stripe_heads as we may need 4544 * more than exist in the cache (if we allow ever large chunks). 4545 * So we do one stripe head at a time and record in 4546 * ->bi_hw_segments how many have been done. 4547 * 4548 * We *know* that this entire raid_bio is in one chunk, so 4549 * it will be only one 'dd_idx' and only need one call to raid5_compute_sector. 4550 */
如果沒有足夠的struct stripe_head結構,我們沒能把請求一次性提交。我們也不能提前預留足夠的struct stripe_head結構,所以我們一次提交一個struct stripe_head,並將已提交記錄在bio->bi_hw_segments欄位裡。
由於是條塊內讀,所以raid_bio請求區間都在一個條塊內的,所以我們只需要調用一次raid5_compute_sector來計算對應磁碟下標dd_idx。
看完了以上的注釋部分,我們就知道這裡複用了bio->bi_hw_segment欄位,用於記錄已經下發的struct stripe_head數,那具體是怎麼用的呢?我們來繼續看代碼:
4558 logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1); 4559 sector = raid5_compute_sector(conf, logical_sector, 4560 0, &dd_idx, NULL); 4561 last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9);
4558行,計算請求開始扇區對應的stripe扇區,因為讀操作的基本單位是stripe大小,即一頁大小
4559行,計算對應磁碟下標dd_idx,磁碟中位移sector
4561行,請求結束扇區
4563 for (; logical_sector < last_sector; 4564 logical_sector += STRIPE_SECTORS, 4565 sector += STRIPE_SECTORS, 4566 scnt++) { 4567 4568 if (scnt < raid5_bi_processed_stripes(raid_bio)) 4569 /* already done this stripe */4570 continue; 4571 4572 sh = get_active_stripe(conf, sector, 0, 1, 0); 4573 4574 if (!sh) { 4575 /* failed to get a stripe - must wait */4576 raid5_set_bi_processed_stripes(raid_bio, scnt); 4577 conf->retry_read_aligned = raid_bio; 4578 return handled; 4579 } 4580 4581 if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) { 4582 release_stripe(sh); 4583 raid5_set_bi_processed_stripes(raid_bio, scnt); 4584 conf->retry_read_aligned = raid_bio; 4585 return handled; 4586 } 4587 4588 set_bit(R5_ReadNoMerge, &sh->dev[dd_idx].flags); 4589 handle_stripe(sh); 4590 release_stripe(sh); 4591 handled++; 4592 }
4563行,對於條塊內的每一個stripe進行操作,比如說條塊為64KB,stripe為4KB,請求為整個條塊,那麼這裡就需要迴圈16次。4568行,如果是已經下發請求的stripe,那麼就跳過去。在上面注釋裡我們已經講過,利用了bio->bi_hw_segments來表示一個請求中已經下發的stripe數量。比如說一次只下發了8個stripe,有了這裡的continue那麼下次再進來這個函數就繼續下發後面8個stripe。4572行,擷取sector對應的stripe_head4574行,如果沒有申請到stripe_head,那麼儲存已經下發的stripe數量,將請求raid_bio儲存到陣列retry_read_aligned指標裡,下次喚醒raid5d裡直接從該指標中擷取bio,並繼續下發stripe請求。4578行,返回已下發stripe個數4581行,將bio添加到stripe_head請求鏈表中
4582行,如果添加失敗,釋放stripe_head,記錄下發stripe數量,儲存重試讀請求
4588行,設定塊層不需要合并標誌
4589行,處理stripe
4590行,遞減stripe計數
4591行,增加處理stripe數