linux内核md源代码解读 十一 raid5d - Linux系统
正是有了上一篇的读写基础,我们才开始看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 * During the scan, completed stripes are saved for us by the interrupt 4631 * handler, so that they will not have to wait for our next wakeup. 4632 */ 4633 static void raid5d(struct mddev *mddev) 4634 { 4635 struct r5conf *conf = mddev->private; 4636 int handled; 4637 struct blk_plug plug; 4638 4639 pr_debug("+++ raid5d activen"); 4640 4641 md_check_recovery(mddev); 4642 4643 blk_start_plug(&plug); 4644 handled = 0; 4645 spin_lock_irq(&conf->device_lock); 4646 while (1) { 4647 struct bio *bio; 4648 int batch_size; 4649 4650 if ( 4651 !list_empty(&conf->bitmap_list)) { 4652 /* Now is a good time to flush some bitmap updates */ 4653 conf->seq_flush++; 4654 spin_unlock_irq(&conf->device_lock); 4655 bitmap_unplug(mddev->bitmap); 4656 spin_lock_irq(&conf->device_lock); 4657 conf->seq_write = conf->seq_flush; 4658 activate_bit_delay(conf); 4659 } 4641行,md_check_recovery这个函数前面看过了,用来检查触发同步 4643行,blk_start_plug和4688行blk_finish_plug是一对,用于合并请求。 4646行,这里为什么要来个大循环呢?刚开始看4629行注释可能有点迷糊,可是看到这个循环就知道原来讲的是这里,4629行注释说我们不必等到下次唤醒raid5线程,可以继续处理stripes,因为可能有stripes已经在中断处理函数里处理完成返回了。 4651行,判断阵列对应的bitmap_list是否为空,如果这个链表不为空则进入分支。bitmap跟条带处理有什么关系呢?这个问题就比较有历史性了。对于raid5阵列来说,最可怕的事情莫过于在写的过程中异常掉电,这就意味阵列不知道哪些数据是一致的,哪些是不一致的?这就是safemode干的事情,用来记录阵列数据是否一致。然而数据不一致导致的代码是全盘同步,这个是raid5最头疼的问题。好了,现在有bitmap了可以解决这个问题啦,太happy啦。那bitmap是如何解决这个问题的呢?bitmap说你写每个条带的时候我都记录一下,写完成就清除一下。如果异常掉电就只要同步掉电时未写完成的条带就可以啦。娃哈哈太happy了!!!但是请别高兴的太早,bitmap也不是一个好侍候的爷,bitmap必须要在写条带之前写完成,这里的写完成就是要Write Through即同步写。这下悲催了,bitmap的写过程太慢了,完全拖垮了raid5的性能。于是有了这个的bitmap_list,raid5说,bitmap老弟你批量写吧,有点类似bio的合并请求。但是这也只能部分弥补bitmap带来的负面性能作用。 4655行,下发bitmap批量写请求。 4658行,将等待bitmap写的条带下发。 4660 raid5_activate_delayed(conf); 4660行,看函数名就是激活延迟条带的意思。那么为什么要延迟条带的处理呢?按照块设备常用的手段,延迟处理是为了合并请求,这里也是同样的道理。那么条带什么时候做延迟处理呢?我们跟进raid5_activate_delayed函数: 3691static void raid5_activate_delayed(struct r5conf *conf) 3692{ 3693 if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) { 3694 while (!list_empty(&conf->delayed_list)) { 3695 struct list_head *l = conf->delayed_list.next; 3696 struct stripe_head *sh; 3697 sh = list_entry(l, struct stripe_head, lru); 3698 list_del_init(l); 3699 clear_bit(STRIPE_DELAYED, &sh->state); 3700 if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) 3701 atomic_inc(&conf->preread_active_stripes); 3702 list_add_tail(&sh->lru, &conf->hold_list); 3703 } 3704 } 3705} 3693行,这里控制预读数量。 3694行,遍历阵列延迟处理链表 3695行,获取阵列延迟处理链表表头 3697行,获取阵列延迟处理链表第一个条带 3698行,从阵列延迟处理链表取出一个条带 3700行,设置预读标志 3702行,添加到预读链表中
(编辑:应用网_镇江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |