linux内核md源代码解读 十三 raid5重试读

上节我们讲到条块内读失败,在回调函数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内核源代码,以便于您获取更多的相关知识。

时间: 2024-10-30 06:40:27

linux内核md源代码解读 十三 raid5重试读的相关文章

linux内核md源代码解读 十 raid5数据流之同步数据流程

上一节讲到在raid5的同步函数sync_request中炸土豆片是通过handle_stripe来进行的.从最初的创建阵列,到申请各种资源,建立每个阵列的personality,所有的一切都是为了迎接数据流而作的准备.就像我们寒窗苦读就是为了上大学一样.数据流的过程就像大学校园一样丰富多彩并且富有挑战性,但只要跨过了这道坎,内核代码将不再神秘,剩下的问题只是时间而已. 首先看handle_stripe究竟把我们的土豆片带往何处: 3379 static void handle_stripe(s

linux内核md源代码解读 二 md模块初始化

在编译完成linux内核源代码的时候,drivers/md目录下会生成多个ko文件,那么这些内核模块哪一个先加载,哪一个后加载的呢?例如md-mod.ko, raid5.ko, raid10.ko,这些模块是一起加载的呢,还是有先后顺序呢?如果熟悉linux内核编程的话,知道有一个request_module函数,这个函数用于请求加载一个模块,但这个函数并不能说明一个模块对另一个模块的依赖关系.准确的信息还是来自于Kconfig,这里只抽取Kconfig中相关的部分: config BLK_DE

linux内核md源代码解读 一

最近花了一段时间认真地学习了一下md代码,并且在原代码的基础上开发了一系列的新功能,这些新功能让md更完善.更适合于企业大容量存储,通过增加阵列缓存和bitmap优化大大提升了存储速度,提高了数据的可靠性,在任何掉电的情况下保证数据一致性,超级块异常情况下完全不影响阵列使用,完全控制了踢盘问题,简化了用户操作.简单地概括一下,就是让存储不再有门槛.说了这么多,其实想表达的意思就是md的学习之路并非十分顺利,特此写此博文与所有兄弟姐妹们共享一下我的学习经验,如果您看完之后能有所收获,那就不枉费我下

linux内核md源代码解读 十二 raid读写

我们都知道,对一个linux块设备来说,都有一个对应的请求队列.注册在这个请求队列上的请求就是该块设备的请求入口.对于raid来说,分配struct mddev时就已经设置好了,在函数md_alloc中有这样的代码: 4846 blk_queue_make_request(mddev->queue, md_make_request); 4847 blk_set_stacking_limits(&mddev->queue->limits); 虽然全国的PM一直保持着稳健的增长,但丝

linux内核md源代码解读 十一 raid5d

正是有了上一篇的读写基础,我们才开始看raid5d的代码.raid5d不是读写的入口,也不是读写处理的地方,只是简简单单的中转站或者叫做交通枢纽.这个枢纽具有制高点的作用,就像美国在新加坡的基地,直接就控制了太平洋和印度洋的交通枢纽. 4626 /* 4627 * This is our raid5 kernel thread. 4628 * 4629 * We scan the hash table for stripes which can be handled now. 4630 * Du

linux内核md源代码解读 八 阵列同步二:同步过程

在上一小节里讲到启动同步线程: 7824 mddev->sync_thread = md_register_thread(md_do_sync, 7825 mddev, 7826 "resync"); md_register_thread函数如下: 6697 struct md_thread *md_register_thread(void (*run) (struct mddev *), struct mddev *mddev, 6698 const char *name) 6

linux内核md源代码解读 三 阵列创建的过程

这一节我们阅读阵列的创建过程. 按照常理出牌,我们到ioctl中找阵列创建命令,md对应的ioctl函数是md_ioctl,当找对应的cmd命令字时,却完全没有类似CREATE_ARRAY的命令,那么就说明md设备并不是通过ioctl函数来创建的.其实如果我们仔细阅读一下md_ioctl函数的原型就会发现其实创建md设备根本就不在这个地方,函数原型如下: 6303 static int md_ioctl(struct block_device *bdev, fmode_t mode, 6304

linux内核md源代码解读 七 阵列同步一 :介绍阵列同步

阵列同步在md_do_sync,那么入口在哪里呢?就是说阵列同步触发点在哪里呢?听说过md_check_recovery吧,但这还不是同步的入口点.那raid5d函数是入口点吧?如果要认真分析起来还不算是. 真正的同步入口点在do_md_run函数,就是在运行阵列run函数之后,有这么一行: 5171         md_wakeup_thread(mddev->thread); 是这一行把raid5d唤醒的,raid5d函数如下: 4823 static void raid5d(struct

linux内核md源代码解读 四 命令字RUN_ARRAY的处理过程

运行阵列意味着阵列经历从无到有,建立了作为一个raid应有的属性(如同步重建),并为随后的读写做好的铺垫.那么运行阵列的时候到底做了哪些事情,让原来的磁盘像变形金刚一样组成一个新的巨无霸.现在就来看阵列运行处理流程: 5158 static int do_md_run(struct mddev *mddev) 5159 { 5160 int err; 5161 5162 err = md_run(mddev); 5163 if (err) 5164 goto out; 5165 err = bi