MD模块之处理读写过程分析-4
2011-08-03 17:39
363 查看
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方式读出了相应的数据,这时数据都已经准备好了,满足了
判定式,然后compute_parity5计算校验盘信息,将数据写到磁盘上。这里可能会有个疑问,失效盘数据怎么写上去啊?在handle_stripe的末尾,会有如下判断
这个rcu锁很重要,有兴趣的人可以研究研究。这段代码就会根据rdev的状态设置rdev指针值,如果它是NULL的话就不会下发具体的命令到物理磁盘上。这样写数据发生错误的时候就处理完毕了,下面我们来看看读发生错误的时候。
2、读数据发生错误
和写发生错误一样,读发生错误首先也会在raid5_end_read_request()函数中体现,只不过会重试命令。重试命令之前会做一些检查,比如阵列已经处于降级状态,那么我们没有重试该命令了,这时阵列已经坏了。又比如该设备的发生太多的读取错误,则也不做重试。如果不做重试,则会调用md_error。否则将rdev的状态置为R5_ReadError,重新处理这个条带。
在handle_stripe5函数中,如果是失效盘上有读请求,依旧还是要通过读出其他盘上的数据来计算出该失效盘上的数据。当其他盘数据都读出来的时候,调用compute_block()计算失效盘上的数据,之后便满足
判定式,将rdev状态位R5_ReWrite置为有效,将失效盘数据重新写回磁盘上。
如果rewrite成功,则将数据重新写回磁盘成功,否则想处理写请求失败的情况下处理。
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成功,则将数据重新写回磁盘成功,否则想处理写请求失败的情况下处理。
相关文章推荐
- MD模块之处理读写过程分析-2
- MD模块之处理读写过程分析-3
- MD模块之处理读写过程分析-4
- MD模块之处理读写过程分析-2
- MD模块之处理读写过程分析-1
- MD模块之处理读写过程分析-3
- MD模块之处理读写过程分析-1
- MD模块之处理读写过程分析-2
- MD模块之处理读写过程分析-1
- MD模块之处理读写过程分析-4
- Linux内核分析之简析system_call中断处理过程
- mfc 井字游戏程序分析,描述整个程序处理过程。
- Nginx源码分析 - HTTP模块篇 - ngx_http_optimize_servers函数和TCP连接建立过程
- 分析system_call中断处理过程
- 实验五:分析system_call中断处理过程
- Tomcat 源码分析(二)——Request处理全过程
- Windows XP \Windows 2003启动过程的学习及故障分析处理(二)
- 分析system_call中断处理过程
- 实验5 :分析system_call中断处理过程
- HDFS追本溯源:租约,读写过程的容错处理及NN的主要数据结构