md模块浅谈(一)加载和卸载
来源:互联网 发布:淘宝付款人数多久更新 编辑:程序博客网 时间:2024/05/22 14:40
先找到模块的入口和出口是哪个函数。
这个很简单,找到下面的代码,就一目了然了。
subsys_initcall(md_init);module_exit(md_exit)
入口
static int __init md_init(void){if (register_blkdev(MD_MAJOR, "md"))return -1;if ((mdp_major=register_blkdev(0, "mdp"))<=0) {unregister_blkdev(MD_MAJOR, "md");return -1;}blk_register_region(MKDEV(MD_MAJOR, 0), 1UL<<MINORBITS, THIS_MODULE, md_probe, NULL, NULL);blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE, md_probe, NULL, NULL);register_reboot_notifier(&md_notifier);raid_table_header = register_sysctl_table(raid_root_table);md_geninit();return 0;}
register_blkdev函数:用来注册一个新的块设备。
第一次用来注册主设备。其中"md”是设备名,宏MD_MAJOR的值是9,这个宏在"major.h"文件中有定义,代表第9号块设备。在Documentation/devices.txt文件中,我们可以找到该设备的说明。
9 blockMetadisk (RAID) devices 0 = /dev/md0First metadisk group 1 = /dev/md1Second metadisk group ...The metadisk driver is used to span afilesystem across multiple physical disks.
第二次用来注册patition。最多63个patition。
blk_register_region函数:用来创建块的必要结构
register_reboot_notifier函数:是把md_notifier这个结构体加到reboot_notifier_list链表中。md_notifier在md模块载入时被初始化成下面的摸样。
static struct notifier_block md_notifier = {.notifier_call= md_notify_reboot,.next= NULL,.priority= INT_MAX, /* before any real devices */};
这样,系统重启时,将会执行刚注册进去的md_notify_reboot函数,而且执行顺序早于其他真实设备。
kernel/notifier.c文件中定义了register_reboot_notifier函数。
int register_reboot_notifier(struct notifier_block *nb){return blocking_notifier_chain_register(&reboot_notifier_list, nb);}EXPORT_SYMBOL(register_reboot_notifier);
blocking_notifier_chain_register函数定义如下:
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,struct notifier_block *n){int ret;/* * This code gets used during boot-up, when task switching is * not yet working and interrupts must remain disabled. At * such times we must not call down_write(). */if (unlikely(system_state == SYSTEM_BOOTING))return notifier_chain_register(&nh->head, n);down_write(&nh->rwsem);ret = notifier_chain_register(&nh->head, n);up_write(&nh->rwsem);return ret;}EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);
顺便说一下notifier chain。通过notifier_chain_register、notifier_chain_unregister、notifier_call_chain三个函数实现对重启链上的结点的追加、删除和执行。
- atomic是通过自旋锁的方式对notifier chain进行保护(使用spin_lock_irqsave、spin_unlock_irqrestore函数)
- blocking是通过阻塞的方式对notifier chain进行保护(使用write_up、write_down函数)
- raw是以共享方式访问notifier chain
- srcu是通过互斥锁的方式对notifier chain进行保护(使用mutex_lock、mutex_unlock函数)
锁的重量级raw<atocmic<srcu<blocking
翻过头来,看看刚刚注册的md_notify_reboot函数吧,它在机器重启或关机时执行,代码如下:
static int md_notify_reboot(struct notifier_block *this, unsigned long code, void *x){ struct list_head *tmp; mddev_t *mddev; if ((code == SYS_DOWN) || (code == SYS_HALT) || (code == SYS_POWER_OFF)) { printk(KERN_INFO "md: stopping all md devices.\n"); for_each_mddev(mddev, tmp) if (mddev_trylock(mddev)) { /* Force a switch to readonly even array * appears to still be in use. Hence * the '100'. */ do_md_stop(mddev, 1, 100); mddev_unlock(mddev); } /* * certain more exotic SCSI devices are known to be * volatile wrt too early system reboots. While the * right place to handle this issue is the given * driver, we do want to have a safe RAID driver ... */ mdelay(1000*1); } return NOTIFY_DONE;}
register_sysctl_table函数:按照raid_root_table的定义来创建sysctl文件及目录。
- 在/proc/sys/目录下创建dev目录
- 在/proc/sys/dev/目录下创建raid目录
- 最后在/proc/sys/dev/raid目录下创建两个文件speed_limit_max和speed_limit_min,内容分别为200000和1000
md_geninit函数:创建一个proc文件/proc/mdstat。并注册一些回调函数
static const struct file_operations md_seq_fops = {.owner= THIS_MODULE,.open = md_seq_open,.read = seq_read,.llseek = seq_lseek,.release= seq_release_private,.poll= mdstat_poll,};
出口
static __exit void md_exit(void){mddev_t *mddev;struct list_head *tmp;blk_unregister_region(MKDEV(MD_MAJOR,0), 1U << MINORBITS);blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS);unregister_blkdev(MD_MAJOR,"md");unregister_blkdev(mdp_major, "mdp");unregister_reboot_notifier(&md_notifier);unregister_sysctl_table(raid_table_header);remove_proc_entry("mdstat", NULL);for_each_mddev(mddev, tmp) {export_array(mddev);mddev->hold_active = 0;}}
基本上是入口的逆过程,这里不再详细描述。
- md模块浅谈(一)加载和卸载
- md模块浅谈(二)md事件
- 模块加载和卸载
- 模块(加载函数和卸载函数)
- 模块加载和卸载函数
- 内核模块的加载和卸载
- linux 编译和加载卸载模块
- .ko模块的加载和卸载
- linux模块加载和模块卸载时出现的问题
- Linux内核模块的编译、加载和卸载
- 内核模块编写,编译,加载和卸载过程
- Linux内核模块的“加载”和“卸载”函数
- 【原创】Tiny6410驱动模块的构建、加载和卸载
- Andorid linux模块编译和加载(一)
- 向内核加载/卸载模块
- linux模块加载与卸载
- 8.模块加载与卸载
- 使用模块(20160812).md
- 使用mysql dump 导入与导出的方法
- 使用JQuery结合HIghcharts实现从后台获取JSON实时刷新图表
- C#截取字符串中英文逗号隔开 以及 冒泡排序
- StarUML学习笔记----基本概念
- C#学习之基础篇(File、FileInfo、Directory、DirectoryInfo区别)
- md模块浅谈(一)加载和卸载
- Gallery is deprecated『Android系列十』
- Oracle 11g 新特性:Oracle11g 后台进程概述
- struts中ActionForward 使用mapping.findForward如何传递get参数
- ODS 状态修复加个人理解
- NULL 访问的内存地址为 0x0
- VC为控件加ToolTip工具提示方法总结
- 打开摄像头 拍照 存储拍照图片
- Google Maps API申请 之 Android Maps API (2012-5-15新发布可解决网页打不开的问题)