Linux驱动开发:内核模块堆叠(1)
本文档简单说明内核模块堆叠的基本信息。
在Linux中内核模块的堆叠(module stacking)是指一个模块对另一个模块的依赖情况。
模块堆叠有利于模块间的代码复用和功能扩展:一个设备驱动可能依赖于一个提供通用功能的模块。
内核模块堆叠的关键点:
- 模块依赖关系:
- 模块A可以使用模块B导出的符号(函数、变量等)
- 当加载模块A时,内核会自动加载模块B(如果尚未加载)
- 当模块B被卸载时,内核会检查是否有其他模块依赖于它,如果有则不允许卸载(除非使用强制卸载)
- 导出符号:
- 模块可以通过EXPORT_SYMBOL()或EXPORT_SYMBOL_GPL()导出符号,供其他模块使用
- 只有导出的符号才能被其他模块访问
- 模块引用计数:
- 每个模块都有一个引用计数,记录当前有多少其他模块正在使用它
- 当引用计数不为零时,模块不能被卸载
- 自动加载:
- 可以通过request_module()函数在运行时自动加载另一个模块
- 模块堆叠的注意事项:
- 避免循环依赖
- 注意模块加载顺序:卸载时,必须先卸载依赖其他模块的模块,然后才能卸载被依赖的模块
- 查看模块依赖关系:
- 使用lsmod命令可以查看已加载模块的依赖关系
- 模块别名和软依赖:
- 可以在模块中使用MODULE_SOFTDEP()声明软依赖,提示在加载该模块之前先加载其他模块
示例:
假设我们有两个模块:module_a和module_b,其中module_a依赖于module_b导出的一个函数
module_b.c通过EXPORT_SYMBOL(module_b_exported_function);导出module_b_exported_function
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init module_b_init(void)
{
printk(KERN_INFO "Module B initialized\n");
return 0;
}
static void __init module_b_exit(void)
{
printk(KERN_INFO "Module B exiting\n");
}
// 导出一个函数
void module_b_exported_function(void)
{
printk(KERN_INFO "Module B exported function called\n");
}
EXPORT_SYMBOL(module_b_exported_function);
module_init(module_b_init);
module_exit(module_b_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Module B providing a function for other modules");
module_a.c使用module_b的功能 extern void module_b_exported_function(void);
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
// 声明来自module_b的函数
extern void module_b_exported_function(void);
static int __init module_a_init(void)
{
printk(KERN_INFO "Module A initialized\n");
// 调用module_b导出的函数
module_b_exported_function();
return 0;
}
static void __init module_a_exit(void)
{
printk(KERN_INFO "Module A exiting\n");
}
module_init(module_a_init);
module_exit(module_a_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Module A using Module B's function");
使用时,可使用insmod/modprobe加载module_a;使用modprobe时会自动处理依赖关系
浙公网安备 33010602011771号