上节我们讲到条块内读失败,在回调函数raid5_align_endio中将请求加入阵列重试链表,在唤醒raid5d线程之后,raid5d线程将该请求调用retry_aligned_read函数进行重试读:
4539static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio) 4540{ 4541 /* We may not be able to submit a whole bio at once as there 4542 * may not be enough stripe_heads available. 4543 * We cannot pre-allocate enough stripe_heads as we may need 4544 * more than exist in the cache (if we allow ever large chunks). 4545 * So we do one stripe head at a time and record in 4546 * ->bi_hw_segments how many have been done. 4547 * 4548 * We *know* that this entire raid_bio is in one chunk, so 4549 * it will be only one 'dd_idx' and only need one call to raid5_compute_sector. 4550 */
如果没有足够的struct stripe_head结构,我们没能把请求一次性提交。我们也不能提前预留足够的struct stripe_head结构,所以我们一次提交一个struct stripe_head,并将已提交记录在bio->bi_hw_segments字段里。
由于是条块内读,所以raid_bio请求区间都在一个条块内的,所以我们只需要调用一次raid5_compute_sector来计算对应磁盘下标dd_idx。
看完了以上的注释部分,我们就知道这里复用了bio->bi_hw_segment字段,用于记录已经下发的struct stripe_head数,那具体是怎么用的呢?我们来继续看代码:
4558 logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1); 4559 sector = raid5_compute_sector(conf, logical_sector, 4560 0, &dd_idx, NULL); 4561 last_sector = raid_bio->bi_sector + (raid_bio->bi_size>>9);
4558行,计算请求开始扇区对应的stripe扇区,因为读操作的基本单位是stripe大小,即一页大小
4559行,计算对应磁盘下标dd_idx,磁盘中偏移sector
4561行,请求结束扇区
4563 for (; logical_sector < last_sector; 4564 logical_sector += STRIPE_SECTORS, 4565 sector += STRIPE_SECTORS, 4566 scnt++) { 4567 4568 if (scnt < raid5_bi_processed_stripes(raid_bio)) 4569 /* already done this stripe */ 4570 continue; 4571 4572 sh = get_active_stripe(conf, sector, 0, 1, 0); 4573 4574 if (!sh) { 4575 /* failed to get a stripe - must wait */ 4576 raid5_set_bi_processed_stripes(raid_bio, scnt); 4577 conf->retry_read_aligned = raid_bio; 4578 return handled; 4579 } 4580 4581 if (!add_stripe_bio(sh, raid_bio, dd_idx, 0)) { 4582 release_stripe(sh); 4583 raid5_set_bi_processed_stripes(raid_bio, scnt); 4584 conf->retry_read_aligned = raid_bio; 4585 return handled; 4586 } 4587 4588 set_bit(R5_ReadNoMerge, &sh->dev[dd_idx].flags); 4589 handle_stripe(sh); 4590 release_stripe(sh); 4591 handled++; 4592 }
4563行,对于条块内的每一个stripe进行操作,比如说条块为64KB,stripe为4KB,请求为整个条块,那么这里就需要循环16次。4568行,如果是已经下发请求的stripe,那么就跳过去。在上面注释里我们已经讲过,利用了bio->bi_hw_segments来表示一个请求中已经下发的stripe数量。比如说一次只下发了8个stripe,有了这里的continue那么下次再进来这个函数就继续下发后面8个stripe。4572行,获取sector对应的stripe_head4574行,如果没有申请到stripe_head,那么保存已经下发的stripe数量,将请求raid_bio保存到阵列retry_read_aligned指针里,下次唤醒raid5d里直接从该指针中获取bio,并继续下发stripe请求。4578行,返回已下发stripe个数4581行,将bio添加到stripe_head请求链表中
4582行,如果添加失败,释放stripe_head,记录下发stripe数量,保存重试读请求
4588行,设置块层不需要合并标志
4589行,处理stripe
4590行,递减stripe计数
4591行,增加处理stripe数
以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索struct
, raid
linux bio raid
linux内核源代码分析、linux内核源代码下载、linux内核源代码、linux内核源代码导读、freebsd内核源代码,以便于您获取更多的相关知识。