RAID5 IO处理之写请求代码详解( 二 )

2.3 计算新校验函数调用关系:
raid5_end_read_request() \_ handle_stripe()\_ analyse_stripe()\_ handle_stripe_dirtying()\_ schedule_reconstruction()\_ raid_run_ops()\_ ops_run_prexor5()\_ ops_run_biodrain()\_ ops_run_reconstruct5()由上轮次下发读请求的回调出发本轮次处理 。
本轮次中 , 再次进入 handle_stripe_dirtying() 后因为读请求的完成,上轮次中需要读的条带/设备都设置了 R5_UPTODATE 标记,所以一方面 rmw 变量等于0,另一方面在不需要下发请求 s->locked 等于0,因此满足条件进入到schedule_reconstruction() 中 。
static voidschedule_reconstruction(struct stripe_head *sh, struct stripe_head_state *s,int rcw, int expand){ if (!rcw) {/* RAID6不支持读改写 */BUG_ON(level == 6);BUG_ON(!(test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags) ||test_bit(R5_Wantcompute, &sh->dev[pd_idx].flags)));/* 遍历所有条带/设备 */for (i = disks; i--; ) {struct r5dev *dev = &sh->dev[i];/* 跳过校验 */if (i == pd_idx)continue;/* 有写请求的条带/设备设置相关标记 */if (dev->towrite &&(test_bit(R5_UPTODATE, &dev->flags) ||test_bit(R5_Wantcompute, &dev->flags))) {/* 将数据从bio中拷贝到dev->page中 */set_bit(R5_Wantdrain, &dev->flags);/* 给条带/设备上锁表明正在进行IO */set_bit(R5_LOCKED, &dev->flags);/* 清除标记表明当前条带/设备的page中的数据不可直接试用 */clear_bit(R5_UPTODATE, &dev->flags);/* locked计数 */s->locked++;}}/* 设置条带重构状态 */sh->reconstruct_state = reconstruct_state_prexor_drain_run;/* 设置条带需要进行异或运算 */set_bit(STRIPE_OP_PREXOR, &s->ops_request);/* 设置条带需要“抽干”数据 */set_bit(STRIPE_OP_BIODRAIN, &s->ops_request);/* 设置条带需要计算校验 */set_bit(STRIPE_OP_RECONSTRUCT, &s->ops_request); } /* 给校验值所在条带/设备上锁表明正在进行IO */ set_bit(R5_LOCKED, &sh->dev[pd_idx].flags); /* 清除标记表明当前条带/设备的page中的数据不可直接试用 */ clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags); /* locked计数 */ s->locked++;}static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request){ /* 先使用旧数据和旧校验进行异或运算获得中间状态的校验 */ if (test_bit(STRIPE_OP_PREXOR, &ops_request))tx = ops_run_prexor(sh, percpu, tx); /* 将新数据拷贝从bio中拷贝到dev中 */ if (test_bit(STRIPE_OP_BIODRAIN, &ops_request))tx = ops_run_biodrain(sh, tx); /* 计算最终的校验值 */ if (test_bit(STRIPE_OP_RECONSTRUCT, &ops_request)) {if (level < 6)ops_run_reconstruct5(sh, percpu, tx);elseops_run_reconstruct6(sh, percpu, tx); }}static struct dma_async_tx_descriptor *ops_run_prexor(struct stripe_head *sh, struct raid5_percpu *percpu,struct dma_async_tx_descriptor *tx){ /* 将校验值的page设置为第一个源数据和目标数据 */ struct page *xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page; /* 遍历所有条带/设备 */ for (i = disks; i--; ) {struct r5dev *dev = &sh->dev[i];/* 需要“抽干”数据的dev即包含新数据的dev , 将其page依次设置为源数据 */if (test_bit(R5_Wantdrain, &dev->flags))xor_srcs[count++] = dev->page; } /* 进行异或运算 */ init_async_submit(&submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_DROP_DST, tx,ops_complete_prexor, sh, to_addr_conv(sh, percpu)); tx = async_xor(xor_dest, xor_srcs, 0, count, STRIPE_SIZE, &submit); return tx;}static struct dma_async_tx_descriptor *ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx){ /* 遍历所有条带/设备 */ for (i = disks; i--; ) {/* 处理所有需要“抽干”数据的dev */if (test_and_clear_bit(R5_Wantdrain, &dev->flags)) {struct bio *wbi;spin_lock_irq(&sh->stripe_lock);/* 将bio从towrite转移到written表明开始调度 */chosen = dev->towrite;dev->towrite = NULL;BUG_ON(dev->written);wbi = dev->written = chosen;spin_unlock_irq(&sh->stripe_lock);/* 将bio中本条带范围内的所有数据拷贝到dev的page中 */while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) {tx = async_copy_data(1, wbi, dev->page, dev->sector, tx);wbi = r5_next_bio(wbi, dev->sector);}} } return tx;}static voidops_run_reconstruct5(struct stripe_head *sh, struct raid5_percpu *percpu,struct dma_async_tx_descriptor *tx){ /* check if prexor is active which means only process blocks* that are part of a read-modify-write (written)*/ if (sh->reconstruct_state == reconstruct_state_prexor_drain_run) {prexor = 1;/* 将校验值的page设置为第一个源数据和目标数据 */xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page;/* 所有包含需要写请求的条带/设备依次设置为源数据 */for (i = disks; i--; ) {struct r5dev *dev = &sh->dev[i];if (dev->written)xor_srcs[count++] = dev->page;} } /* 1/ if we prexor'd then the dest is reused as a source* 2/ if we did not prexor then we are redoing the parity* set ASYNC_TX_XOR_DROP_DST and ASYNC_TX_XOR_ZERO_DST* for the synchronous xor case*/ flags = ASYNC_TX_ACK |(prexor ? ASYNC_TX_XOR_DROP_DST : ASYNC_TX_XOR_ZERO_DST); atomic_inc(&sh->count); /* 进行异步异或运算,完成后进入回调函数ops_complete_reconstruct */ init_async_submit(&submit, flags, tx, ops_complete_reconstruct, sh, to_addr_conv(sh, percpu)); tx = async_xor(xor_dest, xor_srcs, 0, count, STRIPE_SIZE, &submit);}

推荐阅读