linux内核奇遇记之md源代码解读之七阵列同步一

linux内核奇遇记之md源代码解读之七阵列同步一
转载请注明出处:http://blog.csdn.net/liumangxiong
阵列同步在md_do_sync,那么入口在哪里呢?就是说阵列同步触发点在哪里呢?听说过md_check_recovery吧,但这还不是同步的入口点。那raid5d函数是入口点吧?如果要认真分析起来还不算是。
真正的同步入口点在do_md_run函数,就是在运行阵列run函数之后,有这么一行:
   
   
  1. 5171         md_wakeup_thread(mddev->thread);  
是这一行把raid5d唤醒的,raid5d函数如下:
   
   
  1. 4823 static void raid5d(struct md_thread *thread)  
  2. 4824 {  
  3. 4825         struct mddev *mddev = thread->mddev;  
  4. 4826         struct r5conf *conf = mddev->private;  
  5. 4827         int handled;  
  6. 4828         struct blk_plug plug;  
  7. 4829   
  8. 4830         pr_debug("+++ raid5d active\n");  
  9. 4831   
  10. 4832         md_check_recovery(mddev);  
4832行,顾名思义就是检查同步,说明这里只是同步的检查点,不是真正处理同步的地方。
raid5d剩余部分是处理数据流的地方先不看,跟进md_check_recovery,先看注释:
[cpp]  view plain  copy
  1. 7672 /* 
  2. 7673  * This routine is regularly called by all per-raid-array threads to 
  3. 7674  * deal with generic issues like resync and super-block update. 
  4. 7675  * Raid personalities that don't have a thread (linear/raid0) do not 
  5. 7676  * need this as they never do any recovery or update the superblock. 
  6. 7677  * 
  7. 7678  * It does not do any resync itself, but rather "forks" off other threads 
  8. 7679  * to do that as needed. 
  9. 7680  * When it is determined that resync is needed, we set MD_RECOVERY_RUNNING in 
  10. 7681  * "->recovery" and create a thread at ->sync_thread. 
  11. 7682  * When the thread finishes it sets MD_RECOVERY_DONE 
  12. 7683  * and wakeups up this thread which will reap the thread and finish up. 
  13. 7684  * This thread also removes any faulty devices (with nr_pending == 0). 
  14. 7685  * 
  15. 7686  * The overall approach is: 
  16. 7687  *  1/ if the superblock needs updating, update it. 
  17. 7688  *  2/ If a recovery thread is running, don't do anything else. 
  18. 7689  *  3/ If recovery has finished, clean up, possibly marking spares active. 
  19. 7690  *  4/ If there are any faulty devices, remove them. 
  20. 7691  *  5/ If array is degraded, try to add spares devices 
  21. 7692  *  6/ If array has spares or is not in-sync, start a resync thread. 
  22. 7693  */  

这个函数通常由阵列主线程调用,用于处理同步和超级块更新等事件。没有主线程的阵列不需要调用(如线性/raid0),因为这些阵列不需要重建或更新超级块。
这个函数并不做具体事宜,只是按需启动阵列同步线程。
当阵列需要同步时,设置MD_RECOVERY_RUNNING标志,并创建同步线程。
当同步线程结束时设置MD_RECOVERY_DONE标志,并唤醒主线程回收同步线程并结束同步。
这个线程还用于移除坏盘(当nr_pending==0时)。
这个函数处理过程如下:
1、需要时更新超级块
2、同步线程运行时就返回
3、同步线程结束时,回收资源,如果是重建完成则激活热备盘
4、移除坏盘
5、对降级阵列添加热备盘
6、有热备盘但阵列还不是同步状态,则启动同步线程
看完了以上的注释,我已经泪流满面了,因为写代码的哥们太敬业了,把所有精华都已经说出来了,害得像我这种写个博文已经没有什么可写的了。还好我写博文只是自娱自乐,如果是拿这个当饭碗还不早就喝西北风了。
说归说,还是得一行行阅读代码:
   
   
  1. 7694 void md_check_recovery(struct mddev *mddev)  
  2. 7695 {  
  3. 7696         if (mddev->suspended)  
  4. 7697                 return;  
  5. 7698   
  6. 7699         if (mddev->bitmap)  
  7. 7700                 bitmap_daemon_work(mddev);  
  8. 7701   
  9. 7702         if (signal_pending(current)) {  
  10. 7703                 if (mddev->pers->sync_request && !mddev->external) {  
  11. 7704                         printk(KERN_INFO "md: %s in immediate safe mode\n",  
  12. 7705                                mdname(mddev));  
  13. 7706                         mddev->safemode = 2;  
  14. 7707                 }  
  15. 7708                 flush_signals(current);  
  16. 7709         }  
  17. 7710   
  18. 7711         if (mddev->ro && !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))  
  19. 7712                 return;  
  20. 7713         if ( ! (  
  21. 7714                 (mddev->flags & ~ (1<<MD_CHANGE_PENDING)) ||  
  22. 7715                 test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||  
  23. 7716                 test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||  
  24. 7717                 (mddev->external == 0 && mddev->safemode == 1) ||  
  25. 7718                 (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)  
  26. 7719                  && !mddev->in_sync && mddev->recovery_cp == MaxSector)  
  27. 7720                 ))  
  28. 7721                 return;  
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等等。
[cpp]  view plain  copy
  1. 7723         if (mddev_trylock(mddev)) {  
  2. 7724                 int spares = 0;  
  3. ...  
  4. 7746                 if (!mddev->external) {  
  5. 7747                         int did_change = 0;  
  6. 7748                         spin_lock_irq(&mddev->write_lock);  
  7. 7749                         if (mddev->safemode &&  
  8. 7750                             !atomic_read(&mddev->writes_pending) &&  
  9. 7751                             !mddev->in_sync &&  
  10. 7752                             mddev->recovery_cp == MaxSector) {  
  11. 7753                                 mddev->in_sync = 1;  
  12. 7754                                 did_change = 1;  
  13. 7755                                 set_bit(MD_CHANGE_CLEAN, &mddev->flags);  
  14. 7756                         }  
  15. 7757                         if (mddev->safemode == 1)  
  16. 7758                                 mddev->safemode = 0;  
  17. 7759                         spin_unlock_irq(&mddev->write_lock);  
  18. 7760                         if (did_change)  
  19. 7761                                 sysfs_notify_dirent_safe(mddev->sysfs_state);  
  20. 7762                 }  
  21. 7763   
  22. 7764                 if (mddev->flags)  
  23. 7765                         md_update_sb(mddev, 0);  
  24. 7766   
  25. 7767                 if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&  
  26. 7768                     !test_bit(MD_RECOVERY_DONE, &mddev->recovery)) {  
  27. 7769                         /* resync/recovery still happening */  
  28. 7770                         clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);  
  29. 7771                         goto unlock;  
  30. 7772                 }  
  31. 7773                 if (mddev->sync_thread) {  
  32. 7774                         reap_sync_thread(mddev);  
  33. 7775                         goto unlock;  
  34. 7776                 }  

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函数:
[cpp]  view plain  copy
  1. 7777                 /* Set RUNNING before clearing NEEDED to avoid 
  2. 7778                  * any transients in the value of "sync_action". 
  3. 7779                  */  
  4. 7780                 set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);  
  5. 7781                 /* Clear some bits that don't mean anything, but 
  6. 7782                  * might be left set 
  7. 7783                  */  
  8. 7784                 clear_bit(MD_RECOVERY_INTR, &mddev->recovery);  
  9. 7785                 clear_bit(MD_RECOVERY_DONE, &mddev->recovery);  
  10. 7786   
  11. 7787                 if (!test_and_clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||  
  12. 7788                     test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))  
  13. 7789                         goto unlock;  
  14. 7790                 /* no recovery is running. 
  15. 7791                  * remove any failed drives, then 
  16. 7792                  * add spares if possible. 
  17. 7793                  * Spare are also removed and re-added, to allow 
  18. 7794                  * the personality to fail the re-add. 
  19. 7795                  */  
  20. 7796   
  21. 7797                 if (mddev->reshape_position != MaxSector) {  
  22. 7798                         if (mddev->pers->check_reshape == NULL ||  
  23. 7799                             mddev->pers->check_reshape(mddev) != 0)  
  24. 7800                                 /* Cannot proceed */  
  25. 7801                                 goto unlock;  
  26. 7802                         set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);  
  27. 7803                         clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);  
  28. 7804                 } else if ((spares = remove_and_add_spares(mddev))) {  
  29. 7805                         clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);  
  30. 7806                         clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);  
  31. 7807                         clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);  
  32. 7808                         set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);  
  33. 7809                 } else if (mddev->recovery_cp < MaxSector) {  
  34. 7810                         set_bit(MD_RECOVERY_SYNC, &mddev->recovery);  
  35. 7811                         clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery);  
  36. 7812                 } else if (!test_bit(MD_RECOVERY_SYNC, &mddev->recovery))  
  37. 7813                         /* nothing to be done ... */  
  38. 7814                         goto unlock;  

7780行,设置同步运行状态。同步状态有如下:
[cpp]  view plain  copy
  1.      /* recovery/resync flags  
  2.      * NEEDED:   we might need to start a resync/recover 
  3.      * RUNNING:  a thread is running, or about to be started 
  4.      * SYNC:     actually doing a resync, not a recovery 
  5.      * RECOVER:  doing recovery, or need to try it. 
  6.      * INTR:     resync needs to be aborted for some reason 
  7.      * DONE:     thread is done and is waiting to be reaped 
  8.      * REQUEST:  user-space has requested a sync (used with SYNC) 
  9.      * CHECK:    user-space request for check-only, no repair 
  10.      * RESHAPE:  A reshape is happening 
  11.      * 
  12.      * If neither SYNC or RESHAPE are set, then it is a recovery. 
  13.      */  
  14. #define     MD_RECOVERY_RUNNING     0  
  15. #define     MD_RECOVERY_SYNC     1  
  16. #define     MD_RECOVERY_RECOVER     2  
  17. #define     MD_RECOVERY_INTR     3  
  18. #define     MD_RECOVERY_DONE     4  
  19. #define     MD_RECOVERY_NEEDED     5  
  20. #define     MD_RECOVERY_REQUESTED     6  
  21. #define     MD_RECOVERY_CHECK     7  
  22. #define     MD_RECOVERY_RESHAPE     8  
  23. #define     MD_RECOVERY_FROZEN     9  
     * NEEDED:   需要启动同步线程
     * RUNNING:  准备启动或已经有同步线程有运行
     * SYNC:     做同步操作
     * RECOVER:  尝试或已经在重建操作
     * INTR:     同步中断
     * DONE:     同步完成
     * REQUEST:  用户请求同步
     * CHECK:    用户请求检查
     * RESHAPE:  reshape操作
这里有必要解释一下同步线程的意思,这里的同步是指广义的sync,包括狭义的同步和重建,因为同步和重建实际上做的是同一件事情就是把数据从一个地方拷贝到另一个地方。sync是包括syncing和recovery,所以不要一看到同步线程就以为是做同步操作。
正是这些标志指定同步线程下一步该怎么做,而我们一看到这些标志的时候心里必须要明白此时线程在做什么或者应该做什么。
7804行,这个if分支用于启动重建操作。
7809行,这个分支用于启动同步操作。
7812行,既不同步也不重建那就没有什么可以做的。
[cpp]  view plain  copy
  1. 7816                 if (mddev->pers->sync_request) {  
  2. 7817                         if (spares) {  
  3. ...  
  4. 7823                         }  
  5. 7824                         mddev->sync_thread = md_register_thread(md_do_sync,  
  6. 7825                                                                 mddev,  
  7. 7826                                                                 "resync");  
  8. 7827                         if (!mddev->sync_thread) {  
  9. ...  
  10. 7837                         } else  
  11. 7838                                 md_wakeup_thread(mddev->sync_thread);  
  12. 7839                         sysfs_notify_dirent_safe(mddev->sysfs_action);  
  13. 7840                         md_new_event(mddev);  
  14. 7841                 }  
  15. ...  
  16. 7850                 mddev_unlock(mddev);  
  17. 7851         }  

7816行,对于没有同步线程的阵列来说,就没什么事情了。
7824行,启动同步线程。
7838行,唤醒同步线程。
7839行,更新同步状态。
这时主线程调用md_check_recovery函数就已经结束了,启动的同步线程来做同步的具体事宜。那么为什么主线程自己不做同步而另起一个线程做同步呢?不妨想想现在事情都放在主线程里做有什么负面影响?当主线程在同步的时候是不是就不能很及时响应正常数据流了。而且同步和数据流本来就是两件差异很大的事情。
本小节只是介绍到同步入口,同步过程在下一小节开始阅读。
转载请注明出处:http://blog.csdn.net/liumangxiong
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MDLinux内核中的一个模块,可实现磁盘阵列的软件级RAID,它和RAID0、RAID1、RAID4、RAID5、RAID6一样,就是一种磁盘阵列方案。 MD中最主要的部分是驱动程序,它运行在内核态中。它将多个磁盘设备组合在一起,成为一个逻辑设备,该逻辑设备对应着一个块设备文件。在这个逻辑设备上,可实现磁盘阵列的软件级RAID功能。 MD驱动程序的主要源代码是在/drivers/md目录下的md.c文件中,它包括了MD的全部源代码,还有一些其他相关文件,比如raid5.c等。 在这个文件中,最值得学习的是内核的模块化编程思想。模块化编程是一种将代码划分为模块的软件设计方法,通过将代码划分为不同的模块,实现代码的解耦、可重用、可维护性等目标。 在MD.c中我们还可以看到内核中的锁、内存管理等基本的内核技术的应用。通过对MD.c进行源代码解读,能够深入了解Linux内核的实现原理,特别是MD的RAID功能的实现,对于我们进一步学习Linux内核的相关知识和对其进行应用开发具有很大的帮助。 总之,通过对MD.c源代码解读,我们可以学习到Linux内核模块化编程思想、内存管理、锁机制等基本内核技术,进一步掌握Linux内核的实现原理,从而在Linux应用开发中更加熟练娴熟。 ### 回答2: MD(Multiple Devices)是一种常用的软件RAID方案,可以在Linux内核中实现,同时也是Linux内核中最基本的RAID模式之一。MD在实现中使用了驱动程序和用户空间工具,其中驱动程序包含在内核中,因此我们需要对MD源代码进行解读MD源代码是由C语言编写的,主要包含在drivers/md/目录下。在这个目录下,可以看到一些重要的文件和子目录,例如md.c、md.h、raid1.c、raid5.c等。这些文件和子目录定义了MD的基本结构和函数,如磁盘阵列的基本信息结构、磁盘块的操作函数等。 MD的实现思路比较清晰,可以简单地理解为将多个物理磁盘组合在一起,形成一个虚拟的块设备。在这个虚拟的块设备上,可以进行读写等操作,而具体的数据操作则由MD提供的不同RAID模式实现。例如,MD支持的RAID1模式就是将数据同步写入两个物理磁盘,以实现磁盘容错。而MD支持的RAID5模式则是将数据分散写入多个物理磁盘,通过奇偶校验等方式实现磁盘容错。 在MD源代码解读过程中,需要重点关注这些RAID模式的实现方式和相关函数。同时,还需要了解整个MD的插入和移除机制、数据恢复机制等,以便更好地理解和修改MD源代码。 总之,对于想要深入了解Linux内核中RAID相关实现的开发者来说,对MD源代码进行解读是一个非常有价值的学习和探索过程。 ### 回答3: mdlinux内核中的一个重要模块,支持多种存储设备,包括硬盘、闪存和网络存储等。如果想要深入了解linux内核的运行机制,就必须掌握md源代码。下面就对md源代码进行解读md源代码的核心是md.c文件。这个文件中定义了md模块的核心函数,包括md_init()、md_run()和md_stop()等。其中md_init()函数主要负责初始化md模块的各个子系统,包括raid核心、hotplugging、proc文件系统和sysfs文件系统等。md_run()函数则是md模块的主要循环,负责轮询设备状态并执行相应的IO操作。md_stop()函数则是md模块的关闭函数,用于释放模块占用的各种资源。 除了md.c文件外,md模块的代码还包括一些关键性质的文件,例如mddev.c、md.h和md_u.h等。其中,mddev.c文件定义了md设备的数据结构,包括磁盘阵列、线性设备和伪设备等。md.h和md_u.h文件则分别定义了用户空间和内核空间的md控制接口,包括创建和删除设备、添加和删除磁盘等。 在理解md源代码时需要注意的是,md模块涉及到多个子系统,包括块设备、文件系统和RAID等,因此需要对这些子系统的工作原理和相互关系有清晰的理解。同时,由于md模块的代码相当复杂,需要仔细地阅读和调试,才能完成内核的定制和优化工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值