RAID-5(十一)stripe_head的管理

这些文章已经写了好几年了,可能已经过时了。在MSN space和QQzone几经辗转之后,我想也许这些技术文章还是放在搞技术的博客中更能帮助人。于是做了一个艰难的决定,把这些文章一篇篇搬过来!绝对是原创的。

 

前面其实我们已经看到了一些stripe_head管理的结构,比如handle_list,delayed_list。我们知道,stripe_head是在RAID-5开始运行的时候开辟的缓冲区,这是个有限的资源,那么除了要在数据处理过程中需要调度以外,还需要一套完整的机制去使得这些有限的资源能够满足数据情求的处理所需。

 

在RAID-5开始运行的时候,为所有的stripe_head分配了内存(通过grow_stripes函数)。通过看代码能发现,linux源码中最大的stripe_head数量是256,但是你完全可以通过在代码中调整这个值来调整RAID-5的内容,因为这个数量是跟性能有关。一开始的时候,所有的stripe_head都被放到了inactive_list. inactive_list和handle_list、delayed_list是在I/O处理时最重要的三个链表。除了这些链表,RAID-5为了更好的管理这些stripe_head还为建立了一个hash表来提高通过sector来查找stripe_head的速度,至于hash表是如何使用的,这应该不用多介绍了。

 

一切都是从头开始的,在RAID-5开始运行之初,所有的stripe_head(下面都用简写sh)都在inactive_list中,而hash表中也没有记录任何sh。最初的变化发生在make_request调用get_active_stripe以后。那就来看看get_active_stripe干了些什么。

 

get_active_stripe中首先调用find_stripe在hash表中找找看指定sector的stripe是否已经存在了?如果存在的话,那说明这个sh刚有人用过,我们可以直接拿来用,可以省去初始化的动作。但是这个sh可能已经处于handle_list或者delayed_list中的一个,此时我们必须要先从这个list中删除。如果hash表中不存在,那么就调用get_free_stripe从inactive_list中取出一个sh来,也就是说从 inactive_list中删除。这时取出来的sh就必须进行初始化了,初始化的工作由init_stripe负责。但是sh既然是紧缺资源,那总会有用光的一天,这也就是说,通过find_stripe和get_free_stripe都找不到sh来使用。这种情况下我们能怎么办呢?没办法,那就等吧。于是我们在get_active_stripe中看到了wait_event_lock_irq调用的代码。这个看似函数东西其实是个宏定义,由于他是在md中定义,在RAID-1456中都有广泛使用,所以我想稍微提一提。这个宏的作用是,如果条件不满足,调用make_request的线程就会被加入到一个等待队列(此时为wait_for_stripe队列),但是在放弃CPU之前,这个函数还会执行一个cmd(此时是 unplug_slaves(conf->mddev)),这通常就是个敦促其他线程去赶紧处理,使得等待的条件(event)尽早满足。在 get_active_stripe这个要等待的event有些特别:

!list_empty(&conf->inactive_list) &&

    (atomic_read(&conf->active_stripes)< (conf->max_nr_stripes *3/4)

为什么说他特别呢?因为这个等待并不是只要inactive_list不空就能结束等待,而是要等到active的sh的数量低于所有sh数量的 3/4(256*3/4=192)。这个3/4是如何得出的我无从知晓,但是可以肯定的是,如果只要inactive_list不空就结束等待性能是很差的。由于有这样一个等待,我们就可以看看何时去唤醒这个等待队列的。我想只要搜索wait_for_stripe应该就能明白,所以我也不必多说。看完这个函数,我们就知道get_active_stripe最终一定能(除了readahead外)取得一个active的sh,而且这个sh游离于任何list之外。

 

如果sh处于游离状态,说明它需要被handle_stripe处理。处理完后,就需要将它再放入某个list,这个工作总是通过 release_stripe函数来完成。所以在调用handle_stripe之后,我们总能看到release_stripe的调用。但是 release_stripe并不是都在handle_stripe之后,搜索一下就能知道。在end_read_request和 end_write_request的最后也会调用release_stripe,我们观察一下release_stripe的代码就知道,他必须等到 sh->count减到0为止,才重新决定sh的位置。而我们也可以看到,sh->count除了在get_active_stripe出来以后会加1以外,在handle_stripe中如果有读写要往下送,sh->count也会增加,而每次减少就是又release_stripe来做,直到减到0,release_stripe就要重新决定sh该放到哪个list中。

 

走入release_stripe内部…如果sh->count已经减到0,那就首先看它有没有置STRIPE_HANDLE位。如果没有,那么说明这个sh已经处理完毕,应该放回inactive_list中,这时如果有人在等待空闲的stripe_head就把它唤醒。如果sh置了STRIPE_HANDLE位,那么再根据它是否置了STRIPE_DELAYED或STRIPE_BIT_DELAY位来确定是要把它放入 delayed_list还是bitmap_list。如果这两个位都为0,那么就放入handle_list。最后就是唤醒raid5d准备处理。所以整个sh的生命周期是从inactive_list开始,处理时在handle_list和delayed_list之间切换,处理完以后又被放回 inactive_list。


下一篇会讨论一下RAID-5中的resync和recovery :)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值