3.2 计算校验函数调用关系:
handle_stripe() \_ analyse_stripe() \_ handle_stripe_fill()\_ fetch_block() \_ raid_run_ops()\_ ops_run_compute5()\_ ops_complete_compute()\_ mark_target_uptodate()
代码逻辑如下:
static void handle_stripe(struct stripe_head *sh){ /* 解析条带状态 */ analyse_stripe(sh, &s); /* s.syncing为真,此时s.compute为0,s.uptodate == disks-1,满足if条件 */ 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中设置了STRIPE_COMPUTE_RUN不进入if */ if (sh->check_state ||(s.syncing && s.locked == 0 &&!test_bit(STRIPE_COMPUTE_RUN, &sh->state) &&!test_bit(STRIPE_INSYNC, &sh->state))) {if (conf->level == 6)handle_parity_checks6(conf, sh, &s, disks);elsehandle_parity_checks5(conf, sh, &s, disks); } /* 计算校验值 */ 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 = &sh->dev[i];/* 在raid5_end_read_request中清除了R5_LOCKED标记,所以此时不自增locked */if (test_bit(R5_LOCKED, &dev->flags))s->locked++;/* 读成功自增uptodate */if (test_bit(R5_UPTODATE, &dev->flags))s->uptodate++;if (!test_bit(R5_Insync, &dev->flags)) {/* 保存异常磁盘索引 */if (s->failed < 2)s->failed_num[s->failed] = i;s->failed++;if (rdev && !test_bit(Faulty, &rdev->flags))do_recovery = 1;} } rcu_read_unlock();}static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s,int disk_idx, int disks){ /* 此时只有异常磁盘没有下发读所以未设置R5_UPTODATE标记,只有遍历到该成员磁盘时进入if */ if (!test_bit(R5_LOCKED, &dev->flags) &&!test_bit(R5_UPTODATE, &dev->flags) &&(dev->toread ||(dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||s->syncing || s->expanding ||(s->replacing && want_replace(sh, disk_idx)) ||(s->failed >= 1 && fdev[0]->toread) ||(s->failed >= 2 && fdev[1]->toread) ||(sh->raid_conf->level <= 5 && s->failed && fdev[0]->towrite &&!test_bit(R5_OVERWRITE, &fdev[0]->flags)) ||(sh->raid_conf->level == 6 && s->failed && s->to_write))) {/* we would like to get this block, possibly by computing it,* otherwise read it if the backing disk is insync*/BUG_ON(test_bit(R5_Wantcompute, &dev->flags));BUG_ON(test_bit(R5_Wantread, &dev->flags));/* raid5重构时除热备盘外其他都读成功时满足第一个条件 *//* 该成员磁盘是统计的异常(未同步)磁盘时满足第二个条件 */if ((s->uptodate == disks - 1) &&(s->failed && (disk_idx == s->failed_num[0] ||disk_idx == s->failed_num[1]))) {/* 设置条带状态为开始计算流程后续不会再进入fetch_block */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;/* 自增uptodate,自增之后不会再进入handle_stripe_fill函数 */s->uptodate++;return 1;} } return 0;}static void raid_run_ops(struct stripe_head *sh, unsigned long ops_request){ cpu = get_cpu(); percpu = per_cpu_ptr(conf->percpu, cpu); if (test_bit(STRIPE_OP_COMPUTE_BLK, &ops_request)) {/* 进行重构计算 */tx = ops_run_compute5(sh, percpu);/* terminate the chain if reconstruct is not set to be run */if (tx && !test_bit(STRIPE_OP_RECONSTRUCT, &ops_request))async_tx_ack(tx); } put_cpu();}static struct dma_async_tx_descriptor *ops_run_compute5(struct stripe_head *sh, struct raid5_percpu *percpu){ int disks = sh->disks; struct page **xor_srcs = percpu->scribble; int target = sh->ops.target; struct r5dev *tgt = &sh->dev[target]; struct page *xor_dest = tgt->page; int count = 0; struct dma_async_tx_descriptor *tx; struct async_submit_ctl submit; int i; pr_debug("%s: stripe %llu block: %d\n",__func__, (unsigned long long)sh->sector, target); BUG_ON(!test_bit(R5_Wantcompute, &tgt->flags)); /* 统计源数据个数,重构流程中只设置了热备盘为target其他均为源,所以count大于1 */ for (i = disks; i--; )if (i != target)xor_srcs[count++] = sh->dev[i].page; atomic_inc(&sh->count); /* 设置回调函数 */ init_async_submit(&submit, ASYNC_TX_FENCE|ASYNC_TX_XOR_ZERO_DST, NULL,ops_complete_compute, sh, to_addr_conv(sh, percpu)); /* count大于1执行async_xor异步进行异或运算 */ if (unlikely(count == 1))tx = async_memcpy(xor_dest, xor_srcs[0], 0, 0, STRIPE_SIZE, &submit); elsetx = async_xor(xor_dest, xor_srcs, 0, count, STRIPE_SIZE, &submit); return tx;}static void ops_complete_compute(void *stripe_head_ref){ struct stripe_head *sh = stripe_head_ref; /* 设置target执行dev的标记 */ mark_target_uptodate(sh, sh->ops.target); mark_target_uptodate(sh, sh->ops.target2); /* 计算完成清除条带计算状态 */ clear_bit(STRIPE_COMPUTE_RUN, &sh->state); /* 此时没有进行check流程,不满足if判断 */ if (sh->check_state == check_state_compute_run)sh->check_state = check_state_compute_result; /* 设置条带状态推入状态机 */ set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh);}static void mark_target_uptodate(struct stripe_head *sh, int target){ /* 参数检查 */ if (target < 0)return; tgt = &sh->dev[target]; /* 设置dev包含最新数据状态 */ set_bit(R5_UPTODATE, &tgt->flags); BUG_ON(!test_bit(R5_Wantcompute, &tgt->flags)); /* 清除dev需要标记 */ clear_bit(R5_Wantcompute, &tgt->flags);}
经验总结扩展阅读
- RAID5 IO处理之写请求代码详解
- RAID5 IO处理之replace代码详解
- Linux Block模块之deadline调度算法代码解析
- Linux Block模块之IO合并代码解析
- 电视剧伪钞者之末路剧情介绍?
- 电视剧伪钞者之末路结局是什么?
- 【强烈推荐】用glob库的一行命令显著加速批量读取处理数据
- redis bitmap数据结构之java对等操作
- 一加9r参数_一加9r搭载什么处理器
- 哪些星座情侣配对最容易闹掰