知识屋:更实用的电脑技术知识网站
所在位置:首页 > 操作系统 > linux

MD模块之处理读写过程分析-4

发布时间:2014-09-05 17:07:30作者:知识屋

 

MD在处理读写错误时是不一样的。写数据发生错误时处理较简单,读发生错误时会比较麻烦,它会把读不出来的数据通过计算出来,然后在重新写回磁盘上。首先先看看如何处理写错误的。

1、写数据时发生错误

     如果写发生错误,那么回调函数raid5_end_write_request()中bio的BIO_UPTODATE位无效,调用md_error函数将相应的rdev置为Faulty,清除掉In_sync标志,degreded++。唤醒raid5守护进程,如果有spare盘,则进行recovery。这个过程以后再说。设置该条带STRIPE_HANDLE位,继续处理该条带。

     在handle_stripe5函数中,首先会统计失效盘的个数failed。对于raid5来说,它是允许一个盘失效的。如果failed>1的话,那么阵列也就失效了。在handle_stripe5中会看到相应的处理-----即满足if (failed > 1 && to_read+to_write+written),对条带中的所有命令均返回失败。

     如果只有一个盘失效的话,并且该失效rdev上有非满块的写请求,那么必须读出其他盘上的数据。为什么这样做呢?其实仔细想想就知道了。因为在写数据时要计算校验盘的数据,要保证校验盘数据的正确性,对于失效盘上的非满块写,我们必须知道它的缓冲区中原来的数据,然后再将一部分数据更新到缓冲区中。这样才能保证在写数据的过程中失效盘中缓冲区数据是正确的。而失效盘上的数据需要根据其它盘上的数据计算得到,故要先读取其他盘上的数据。

    如果不是非满块写的话,那么我们没必要预读出其他未失效盘上的数据。这时会走到判断做rmw还是rcw的流程中。而对于有失效盘的情况,做rmw显示是不切合实际的。因为做rmw首先要读取有写请求的盘上的数据,而失效盘上的数据又要通过预读其他盘上的数据计算而来,所以这里直接将rmw值置为2*disks。rcw值也为2*disks,这样做的目的是选择rcw做写数据方式。

    之后对于非满块写会根据compute_block()计算出失效盘的数据,而满块写则根据rcw方式读出了相应的数据,这时数据都已经准备好了,满足了

 

if (locked == 0 && (rcw == 0 ||rmw == 0) &&   

 !test_bit(STRIPE_BIT_DELAY, &sh->state))   

判定式,然后compute_parity5计算校验盘信息,将数据写到磁盘上。这里可能会有个疑问,失效盘数据怎么写上去啊?在handle_stripe的末尾,会有如下判断

 

rcu_read_lock();   

rdev = rcu_dereference(conf->disks[i].rdev);   

if (rdev && test_bit(Faulty, &rdev->flags))   

    rdev = NULL;   

if (rdev)   

    atomic_inc(&rdev->nr_pending);   

rcu_read_unlock();  

 

 

 

 

这个rcu锁很重要,有兴趣的人可以研究研究。这段代码就会根据rdev的状态设置rdev指针值,如果它是NULL的话就不会下发具体的命令到物理磁盘上。这样写数据发生错误的时候就处理完毕了,下面我们来看看读发生错误的时候。

2、读数据发生错误

 

     和写发生错误一样,读发生错误首先也会在raid5_end_read_request()函数中体现,只不过会重试命令。重试命令之前会做一些检查,比如阵列已经处于降级状态,那么我们没有重试该命令了,这时阵列已经坏了。又比如该设备的发生太多的读取错误,则也不做重试。如果不做重试,则会调用md_error。否则将rdev的状态置为R5_ReadError,重新处理这个条带。

     在handle_stripe5函数中,如果是失效盘上有读请求,依旧还是要通过读出其他盘上的数据来计算出该失效盘上的数据。当其他盘数据都读出来的时候,调用compute_block()计算失效盘上的数据,之后便满足

if (failed == 1 && ! conf->mddev->ro &&   

        test_bit(R5_ReadError, &sh->dev[failed_num].flags)   

        && !test_bit(R5_LOCKED, &sh->dev[failed_num].flags)   

        && test_bit(R5_UPTODATE, &sh->dev[failed_num].flags)   

        )  

 

 判定式,将rdev状态位R5_ReWrite置为有效,将失效盘数据重新写回磁盘上。

 

     如果rewrite成功,则将数据重新写回磁盘成功,否则想处理写请求失败的情况下处理。

(免责声明:文章内容如涉及作品内容、版权和其它问题,请及时与我们联系,我们将在第一时间删除内容,文章内容仅供参考)
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜