RAID5 IO处理之条带读代码详解( 四 )

2.2.2 执行异或运算函数调用关系如下:
raid5_end_read_request() \_ handle_stripe()\_ analyse_stripe()\_ handle_stripe_fill()\_ fetch_block()\_ raid_run_ops()\_ ops_run_compute5()各函数执行的代码逻辑如下:
static void raid5_end_read_request(struct bio * bi, int error){ int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); if (uptodate) {/* 设置R5_UPTODATE标记给读成功的dev */set_bit(R5_UPTODATE, &sh->dev[i].flags); } rdev_dec_pending(rdev, conf->mddev); /* 清除已经完成IO的dev的R5_LOCKED标记 */ clear_bit(R5_LOCKED, &sh->dev[i].flags); /* 将条带推入状态机处理 */ set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh);}static void handle_stripe(struct stripe_head *sh){ /* 解析条带状态 */ analyse_stripe(sh, &s); /* 满足s.to_read条件进入handle_stripe_fill */ if (s.to_read || s.non_overwrite|| (conf->level == 6 && s.to_write && s.failed)|| (s.syncing && (s.uptodate + s.compute < disks))|| s.replacing|| s.expanding)handle_stripe_fill(sh, &s, disks); /* 在fetch_block中设置了s.ops_request进入raid_run_ops执行raid相关操作 */ if (s.ops_request)raid_run_ops(sh, s.ops_request);}static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s){ rcu_read_lock(); for (i = disks; i--; ) {/* 统计读成功的dev */if (test_bit(R5_UPTODATE, &dev->flags))s->uptodate++;/* 统计有读请求的dev */if (dev->toread)s->to_read++;/* 清除条带/设备数据最新的标记 */clear_bit(R5_Insync, &dev->flags);if (!test_bit(R5_Insync, &dev->flags)) {/* 记录异常磁盘索引 */if (s->failed < 2)s->failed_num[s->failed] = i;/* 统计异常的磁盘 */s->failed++;} } rcu_read_unlock();}static void handle_stripe_fill(struct stripe_head *sh,struct stripe_head_state *s,int disks){ int i; /* 当前条带状态没有设置标记,满足条件判断进入if */ if (!test_bit(STRIPE_COMPUTE_RUN, &sh->state) && !sh->check_state &&!sh->reconstruct_state)for (i = disks; i--; )if (fetch_block(sh, s, i, disks))break; set_bit(STRIPE_HANDLE, &sh->state);}static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s,int disk_idx, int disks){ if (!test_bit(R5_LOCKED, &dev->flags) &&/* 已经完成读请求的dev设置了R5_UPTODATE标记不会进入if */!test_bit(R5_UPTODATE, &dev->flags) &&/* 异常磁盘toread为真进入if */dev->toread) {/* 除异常磁盘外其他都读成功,此时s.uptodate满足条件 */if ((s->uptodate == disks - 1) &&/* disk_idx为异常磁盘索引时满足条件 */(s->failed && (disk_idx == s->failed_num[0] ||disk_idx == s->failed_num[1]))) {/* 标记条带需要进行计算操作 */set_bit(STRIPE_COMPUTE_RUN, &sh->state);set_bit(STRIPE_OP_COMPUTE_BLK, &s->ops_request);/* 标记需要计算的条带/设备 */set_bit(R5_Wantcompute, &dev->flags);/* 标记需要计算的条带/设备索引 */sh->ops.target = disk_idx;sh->ops.target2 = -1; /* no 2nd target */s->req_compute = 1;/* 增加同步计数 */s->uptodate++;return 1;} } return 0;}static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request){ /* 调用计算函数 */ if (test_bit(STRIPE_OP_COMPUTE_BLK, &ops_request)) {if (level < 6)tx = ops_run_compute5(sh, percpu); }}static struct dma_async_tx_descriptor *ops_run_compute5(struct stripe_head *sh, struct raid5_percpu *percpu){ /* 设置完成回调函数为Ops_complete_compute */ init_async_submit(&submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_ZERO_DST, NULL,ops_complete_compute, sh, to_addr_conv(sh, percpu)); /* 通过异步接口进行异或运算 */ tx = async_xor(xor_dest, xor_srcs, 0, count, STRIPE_SIZE, &submit); return tx;}2.2.3 拷贝数据到BIOstatic void ops_complete_compute(void *stripe_head_ref){ /* 调用mark_target_uptodate函数设置dev状态为uptodate */ mark_target_uptodate(sh, sh->ops.target); mark_target_uptodate(sh, sh->ops.target2); /* 计算工作完成清除STRIPE_COMPUTE_RUN标记 */ clear_bit(STRIPE_COMPUTE_RUN, &sh->state); /* 将条带推入状态机处理 */ set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh);}

经验总结扩展阅读