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; }}

经验总结扩展阅读