insmod,rmmod一个驱动模块,会执行模块中的哪个函数?在设计上要注意哪些问题?
参考回答
在执行insmod
(插入模块)和rmmod
(移除模块)时,内核会分别调用驱动模块中的init
和exit
函数。
insmod
(插入模块):- 当执行
insmod
时,内核会调用模块中的初始化函数(init
函数),该函数用于初始化模块并完成资源的分配和设备的注册。
- 当执行
rmmod
(移除模块):- 当执行
rmmod
时,内核会调用模块中的退出函数(exit
函数),该函数用于清理资源、注销设备以及进行必要的卸载工作。
- 当执行
详细讲解与拓展
- 模块初始化函数(
init
函数):init
函数是在模块加载时调用的,主要目的是进行设备驱动的初始化工作。例如,初始化设备、分配内存、注册设备等。module_init()
宏会标记该函数为模块的初始化函数,确保在模块加载时自动调用。
常见的初始化工作:
- 设备注册:例如使用
register_chrdev()
注册字符设备。 - 内存分配:如使用
kmalloc()
分配内存,或者映射物理地址到虚拟内存。 - 中断处理程序的注册:如使用
request_irq()
注册中断。 - 设备文件的创建:使用
udev
来动态创建设备文件。
例如:
- 模块退出函数(
exit
函数):exit
函数在模块卸载时被调用,主要用于清理在初始化时分配的资源,注销设备等操作。module_exit()
宏用于标记该函数为模块的退出函数,确保在卸载模块时自动调用。
常见的退出工作:
- 注销设备:如使用
unregister_chrdev()
注销设备。 - 释放资源:如调用
kfree()
释放内存,或者使用free_irq()
释放中断。 - 关闭设备文件:确保与设备相关的文件被正确关闭。
例如:
- 设计上要注意的问题:
-
错误处理:在初始化函数中需要注意对错误的处理,尤其是在分配资源或注册设备时。如果遇到错误,应该适当释放已经分配的资源,并返回错误码。例如,在注册字符设备失败时,应该先调用
unregister_chrdev()
等函数清理已完成的工作。 -
同步问题:如果模块中涉及到多线程或中断处理程序,应该确保在模块卸载时,不会有正在使用该模块的操作。可以通过锁或条件变量进行同步,避免在模块卸载过程中出现竞态条件。
-
模块依赖:如果模块依赖其他模块(例如,某些硬件驱动可能依赖于其他内核模块),在设计时需要明确列出这些依赖关系,确保在模块加载时相关模块已经加载。
-
内存管理:确保在
exit
函数中释放在init
函数中分配的内存。如果分配了动态内存(如使用kmalloc
),要记得调用kfree
释放。如果使用了ioremap
映射的物理地址,在卸载时要调用iounmap
。 -
中断处理:如果模块使用了中断处理程序(如调用
request_irq
),在卸载模块时必须调用free_irq()
来释放中断,避免内核无法正常响应中断。
-
实例:
一个简单的模块可能包括以下部分:该模块会在加载时打印”Driver loaded”,在卸载时打印”Driver unloaded”。
总结
在insmod
和rmmod
执行时,内核会分别调用模块中的init
和exit
函数。init
函数负责初始化资源和注册设备,而exit
函数负责清理资源和注销设备。在设计驱动时,需要特别注意错误处理、资源管理和同步问题,以确保模块的稳定性和系统的正确性。