RAID5 IO處理之寫請求代碼詳解( 三 )

2.4 下發寫請求函數調用關系:
ops_complete_reconstruct() \_ handle_stripe()\_ analyse_stripe()\_ ops_run_io()代碼邏輯如下:
static void ops_complete_reconstruct(void *stripe_head_ref){ /* 遍歷所有條帶/設備 */ for (i = disks; i--; ) {/* 普通寫請求沒有如下標記 */fua |= test_bit(R5_WantFUA, &sh->dev[i].flags);sync |= test_bit(R5_SyncIO, &sh->dev[i].flags);discard |= test_bit(R5_Discard, &sh->dev[i].flags); } for (i = disks; i--; ) {struct r5dev *dev = &sh->dev[i];if (dev->written || i == pd_idx || i == qd_idx) {if (!discard)/* 設置R5_UPTODATE標記表明條帶/設備中的數據為最新可用的 */set_bit(R5_UPTODATE, &dev->flags);} } /* 設置條帶重構狀態 */ if (sh->reconstruct_state == reconstruct_state_prexor_drain_run)sh->reconstruct_state = reconstruct_state_prexor_drain_result; /* 將條帶推入狀態機 */ set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh);}static void handle_stripe(struct stripe_head *sh){ /* 解析條帶狀態 */ analyse_stripe(sh, &s); prexor = 0; /* 條件成立 */ if (sh->reconstruct_state == reconstruct_state_prexor_drain_result)prexor = 1; if (sh->reconstruct_state == reconstruct_state_drain_result ||sh->reconstruct_state == reconstruct_state_prexor_drain_result) {sh->reconstruct_state = reconstruct_state_idle;for (i = disks; i--; ) {struct r5dev *dev = &sh->dev[i];/* 所有設置R5_LOCKED的條帶/設備如果其是校驗或有寫請求 */if (test_bit(R5_LOCKED, &dev->flags) &&(i == sh->pd_idx || i == sh->qd_idx ||dev->written)) {/* 為條帶/設備設置R5_Wantwrite標記表明需要下發寫請求 */set_bit(R5_Wantwrite, &dev->flags);/* 讀改寫跳過下面重構寫的相關邏輯判斷 */if (prexor)continue;/* 如果是重構寫此時條帶處于一致狀態設置相關標記 */if (!test_bit(R5_Insync, &dev->flags) ||((i == sh->pd_idx || i == sh->qd_idx)&&s.failed == 0))set_bit(STRIPE_INSYNC, &sh->state);}} } /* 下發寫請求 */ ops_run_io(sh, &s);}static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s){ /* 遍歷所有條帶/設備 */ for (i = disks; i--; ) {/* 所有設置了R5_Wantwrite標記的條帶/設備下發寫請求 */if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags)) {rw = WRITE;} elsecontinue;rcu_read_lock();rdev = rcu_dereference(conf->disks[i].rdev);rcu_read_unlock();if (rdev) {bio_reset(bi);bi->bi_bdev = rdev->bdev;bi->bi_rw = rw;bi->bi_end_io = raid5_end_write_request;bi->bi_private = sh;atomic_inc(&sh->count);if (use_new_offset(conf, sh))bi->bi_sector = (sh->sector + rdev->new_data_offset);elsebi->bi_sector = (sh->sector + rdev->data_offset);if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags))bi->bi_rw |= REQ_FLUSH;bi->bi_vcnt = 1;bi->bi_io_vec[0].bv_len = STRIPE_SIZE;bi->bi_io_vec[0].bv_offset = 0;bi->bi_size = STRIPE_SIZE;/* 提交寫請求 */generic_make_request(bi);} }}2.5 向上返回函數調用關系:
raid5_end_write_request() \_ handle_stripe()\_ analyse_stripe()\_ handle_stripe_clean_event()代碼邏輯如下:
static void handle_stripe(struct stripe_head *sh){ /* 解析條帶狀態,本輪次最主要設置s->written計數 */ analyse_stripe(sh, &s); /* 有已經完成調度的寫且校驗值已經更新完成說明IO整體完成 */ pdev = &sh->dev[sh->pd_idx]; if (s.written &&(s.p_failed || ((test_bit(R5_Insync, &pdev->flags)&& !test_bit(R5_LOCKED, &pdev->flags)&& (test_bit(R5_UPTODATE, &pdev->flags) ||test_bit(R5_Discard, &pdev->flags))))))/* 將寫完成的IO保存到return_bi中 */handle_stripe_clean_event(conf, sh, disks, &s.return_bi); /* 向上返回 */ return_io(s.return_bi);}static void handle_stripe_clean_event(struct r5conf *conf, struct stripe_head *sh, int disks, struct bio **return_bi){ /* 遍歷所有條帶/設備 */ for (i = disks; i--; )/* 處理所有已調度寫請求的條帶/設備 */if (sh->dev[i].written) {dev = &sh->dev[i];/** 無R5_LOCKED標記表明IO處理結束* 有R5_UPTODATE標記表明IO處理成功*/if (!test_bit(R5_LOCKED, &dev->flags) &&(test_bit(R5_UPTODATE, &dev->flags) ||test_bit(R5_Discard, &dev->flags))) {/* We can return any write requests */struct bio *wbi, *wbi2;/* 將所有處理完成的bio掛載到return_bi中 */wbi = dev->written;dev->written = NULL;while (wbi && wbi->bi_sector <dev->sector + STRIPE_SECTORS) {wbi2 = r5_next_bio(wbi, dev->sector);if (!raid5_dec_bi_active_stripes(wbi)) {md_write_end(conf->mddev);wbi->bi_next = *return_bi;*return_bi = wbi;}wbi = wbi2;}}}}static void return_io(struct bio *return_bi){ struct bio *bi = return_bi; /* 通過bi_next遍歷bio調用bio_endio結束io并通知上層 */ while (bi) {return_bi = bi->bi_next;bi->bi_next = NULL;bi->bi_size = 0;bio_endio(bi, 0);bi = return_bi; }}

推薦閱讀