linux内核奇遇记之md源代码解读之二

本文深入探讨了Linux内核中的MD模块加载顺序及其内部实现原理。通过分析Kconfig配置,揭示了不同RAID模式模块之间的依赖关系,并详细解读了md.c中的module_init函数,为理解MD设备的工作机制奠定了基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

linux内核奇遇记之md源代码解读之二
转载请注明出处:http://blog.youkuaiyun.com/liumangxiong
在编译完成linux内核源代码的时候,drivers/md目录下会生成多个ko文件,那么这些内核模块哪一个先加载,哪一个后加载的呢?例如md-mod.ko, raid5.ko, raid10.ko,这些模块是一起加载的呢,还是有先后顺序呢?如果熟悉linux内核编程的话,知道有一个request_module函数,这个函数用于请求加载一个模块,但这个函数并不能说明一个模块对另一个模块的依赖关系。准确的信息还是来自于Kconfig,这里只抽取Kconfig中相关的部分:
config BLK_DEV_MD
     tristate "RAID support"
config MD_RAID10
     tristate "RAID-10 (mirrored striping) mode"
     depends on BLK_DEV_MD
config MD_RAID456
     tristate "RAID-4/RAID-5/RAID-6 mode"
     depends on BLK_DEV_MD
从这里我们可以看出,raid5.ko, raid10.ko都是依赖于md-mod.ko的,这就决定了我们的阅读方向是从md-mod.ko中开始的。
那么md-mod.ko中又是从哪个文件开始的呢?这就要找module_init函数,这个函数在md.c中定义的,那么就从这里入手。
   
  1. 8416 static int __init md_init(void)  
  2. 8417 {  
  3. 8418         int ret = -ENOMEM;  
  4. 8419   
  5. 8420         md_wq = alloc_workqueue("md", WQ_MEM_RECLAIM, 0);  
  6. 8421         if (!md_wq)  
  7. 8422                 goto err_wq;  
  8. 8423   
  9. 8424         md_misc_wq = alloc_workqueue("md_misc", 0, 0);  
  10. 8425         if (!md_misc_wq)  
  11. 8426                 goto err_misc_wq;  
  12. 8427   
  13. 8428         if ((ret = register_blkdev(MD_MAJOR, "md")) < 0)  
  14. 8429                 goto err_md;  
  15. 8430   
  16. 8431         if ((ret = register_blkdev(0, "mdp")) < 0)  
  17. 8432                 goto err_mdp;  
  18. 8433         mdp_major = ret;  
  19. 8434   
  20. 8435         blk_register_region(MKDEV(MD_MAJOR, 0), 1UL<<MINORBITS, THIS_MODULE,  
  21. 8436                             md_probe, NULL, NULL);  
  22. 8437         blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE,  
  23. 8438                             md_probe, NULL, NULL);  
  24. 8439   
  25. 8440         register_reboot_notifier(&md_notifier);  
  26. 8441         raid_table_header = register_sysctl_table(raid_root_table);  
  27. 8442   
  28. 8443         md_geninit();  
  29. 8444         return 0;  
  30. 8445   
  31. 8446 err_mdp:  
  32. 8447         unregister_blkdev(MD_MAJOR, "md");  
  33. 8448 err_md:  
  34. 8449         destroy_workqueue(md_misc_wq);  
  35. 8450 err_misc_wq:  
  36. 8451         destroy_workqueue(md_wq);  
  37. 8452 err_wq:  
  38. 8453         return ret;  
  39. 8454 }  
模块的初始化过程看起来异常地简单,这就像有些人表面看起来十分普通,内心里却无比地强大,所以不要只看外表,还要听其言观其行。内在的美丽比外表的荣华更具吸引力和持久性。
8420和8424行,分别创建了工作队列,md_wq是用于flush命令的,另一个md_misc_wq,misc是miscellaneous的简写,是杂项的意思,用于处理一些零零碎碎的事情。
8428和8431行,创建了两个块设备,刚开始我只注意md的设备,压根没在意mdp,搜索变量mdp_major,在函数autorun_devices中使用了这个变量:
   
  1. 5474                 if (part) {  
  2. 5475                         dev = MKDEV(mdp_major,  
  3. 5476                                     rdev0->preferred_minor << MdpMinorShift);  
  4. 5477                         unit = MINOR(dev) >> MdpMinorShift;  
  5. 5478                 } else {  
  6. 5479                         dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);  
  7. 5480                         unit = MINOR(dev);  
  8. 5481                 }  
5474行,变量part是函数传入参数,表示磁盘第几个分区,那么就知道mdp_major中字母p是表示part的意思,而mdp_major就表示用磁盘分区创建的阵列。
8435和8437行,创建了两个region,这两个函数的作用是在用户态创建了一个/dev/md*设备时,内核态就会对应调用md_probe创建一个mddev结构体,之后在用户态对/dev/md*的操作到内核态就相应地对mddev的操作了。
8440行,注册关机回调函数,主要作用是停止阵列线程,刷数据操作。
8441行,注册sysctl函数,用于控制阵列最小和最大的sync速度。
8443行,注册proc函数,于是有了目录/proc/mdstat,该目录的显示由函数md_seq_show控制。
md初始化代码就这样轻松地完成了,可是回到我们的初衷,仍然对md设备一无所知。那么md设备是如何创建的呢?创建的过程又是怎么的呢?一个阵列拥有哪些资源?下一节我们直入核心,开始阅读阵列创建的过程。
转载请注明出处:http://blog.youkuaiyun.com/liumangxiong
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值