linux内核奇遇记之md源代码解读之七阵列同步一
转载请注明出处:http://blog.csdn.net/liumangxiong
阵列同步在md_do_sync,那么入口在哪里呢?就是说阵列同步触发点在哪里呢?听说过md_check_recovery吧,但这还不是同步的入口点。那raid5d函数是入口点吧?如果要认真分析起来还不算是。
真正的同步入口点在do_md_run函数,就是在运行阵列run函数之后,有这么一行:
是这一行把raid5d唤醒的,raid5d函数如下:
4832行,顾名思义就是检查同步,说明这里只是同步的检查点,不是真正处理同步的地方。
raid5d剩余部分是处理数据流的地方先不看,跟进md_check_recovery,先看注释:
这个函数通常由阵列主线程调用,用于处理同步和超级块更新等事件。没有主线程的阵列不需要调用(如线性/raid0),因为这些阵列不需要重建或更新超级块。
这个函数并不做具体事宜,只是按需启动阵列同步线程。
当阵列需要同步时,设置MD_RECOVERY_RUNNING标志,并创建同步线程。
当同步线程结束时设置MD_RECOVERY_DONE标志,并唤醒主线程回收同步线程并结束同步。
这个线程还用于移除坏盘(当nr_pending==0时)。
这个函数处理过程如下:
1、需要时更新超级块
2、同步线程运行时就返回
3、同步线程结束时,回收资源,如果是重建完成则激活热备盘
4、移除坏盘
5、对降级阵列添加热备盘
6、有热备盘但阵列还不是同步状态,则启动同步线程
看完了以上的注释,我已经泪流满面了,因为写代码的哥们太敬业了,把所有精华都已经说出来了,害得像我这种写个博文已经没有什么可写的了。还好我写博文只是自娱自乐,如果是拿这个当饭碗还不早就喝西北风了。
说归说,还是得一行行阅读代码:
7696行,检查阵列是否挂起。阵列挂起是一个管理命令,挂起时可以将IO流hold住。
7699行,bitmap清理操作,等bitmap小节再讲。
7702行,接收到信号,进入safemode。
7711行,只读阵列并且未设置检查标志则返回。
7713行,只要一个条件满足,就继续检查,否则返回。
7714行,阵列状态发生改变,则继续检查。
7715行,设置了需要检查标志,则继续检查。
7716行,同步完成,则继续检查。
7717行,安全模式且非external,则继续检查。
7718行,safemode为2有两种情况,一是系统重启时,二是7768行接收到信号时,第一种情况时in_sync为1,第二种情况可以触发更新超级块,根据in_sync标志写回磁盘resync_offset等等。
7723行,对mddev加锁,这里用trylock是因为这里是raid5主线程调用,如果直接用lock会导致主线程休眠,IO流阻塞。
7746行,external表示超级块存储位置,为0表示存储在阵列所在磁盘上。默认值为0,也许好奇的你会问那可不可以既存储在外面又存储在阵列所在磁盘上呢?那只能怪你想像力太丰富了,不过我就是这么干的,原代码是不支持的需要自己修改代码支持这个特性。这个特性的重要性跟数据的重要性成正比。试想为什么市面上那么多数据恢复软件,为什么会丢数据?根本原因就是metadata丢了,metadata就是宝藏的藏宝图,再回头想想就很有必要啦。
7749行,这个判断就是刚刚7718行的判断,分支里代码也就验证了之前的说明,这个判断主要目的是用来更新超级块的。至于这里更新超级块的重要性理解了in_sync的功能就知道了。
7753行,设置in_sync标志。
7754行,设置阵列改变标识。
7755行,设置mddev改变标志。
7757行,设置safemode为0。尽管前面已经讲解了安全模式了,这里再从另外一个角度说一下,safemode标志就像软件看门狗,在阵列写数据时设置为0,然后需要在写完成时喂狗,如果不喂狗那么阵列为脏需要重新启动同步,喂狗程序就是safemode_timer定时器。
7760行,更新mddev的sysfs下状态。
7764行,更新阵列超级块。
7767行,同步线程正在工作,就没有必要再去凑热闹了。
7773行,同步已完成。
7774行,回收同步线程。
继续md_check_recovery函数:
7780行,设置同步运行状态。同步状态有如下:
* NEEDED: 需要启动同步线程
* RUNNING: 准备启动或已经有同步线程有运行
* SYNC: 做同步操作
* RECOVER: 尝试或已经在重建操作
* INTR: 同步中断
* DONE: 同步完成
* REQUEST: 用户请求同步
* CHECK: 用户请求检查
* RESHAPE: reshape操作
* RUNNING: 准备启动或已经有同步线程有运行
* SYNC: 做同步操作
* RECOVER: 尝试或已经在重建操作
* INTR: 同步中断
* DONE: 同步完成
* REQUEST: 用户请求同步
* CHECK: 用户请求检查
* RESHAPE: reshape操作
这里有必要解释一下同步线程的意思,这里的同步是指广义的sync,包括狭义的同步和重建,因为同步和重建实际上做的是同一件事情就是把数据从一个地方拷贝到另一个地方。sync是包括syncing和recovery,所以不要一看到同步线程就以为是做同步操作。
正是这些标志指定同步线程下一步该怎么做,而我们一看到这些标志的时候心里必须要明白此时线程在做什么或者应该做什么。
7804行,这个if分支用于启动重建操作。
7809行,这个分支用于启动同步操作。
7812行,既不同步也不重建那就没有什么可以做的。
7816行,对于没有同步线程的阵列来说,就没什么事情了。
7824行,启动同步线程。
7838行,唤醒同步线程。
7839行,更新同步状态。
这时主线程调用md_check_recovery函数就已经结束了,启动的同步线程来做同步的具体事宜。那么为什么主线程自己不做同步而另起一个线程做同步呢?不妨想想现在事情都放在主线程里做有什么负面影响?当主线程在同步的时候是不是就不能很及时响应正常数据流了。而且同步和数据流本来就是两件差异很大的事情。
本小节只是介绍到同步入口,同步过程在下一小节开始阅读。
转载请注明出处:http://blog.csdn.net/liumangxiong