- 🐚作者简介:花神庙码农(专注于Linux、WLAN、TCP/IP、Python等技术方向)
- 🐳博客主页:花神庙码农 ,地址:https://blog.csdn.net/qxhgd
- 🌐系列专栏:Linux技术
- 📰如觉得博主文章写的不错或对你有所帮助的话,还望大家三连支持一下呀!!! 👉关注✨、点赞👍、收藏📂、评论。
- 如需转载请参考转载须知!!
module_init的执行顺序引起的问题及相应处理
引言
- 最近在调试一个功能,其中一个配置项需要在内核中增加proc文件。类似于这种:
wifi_param_config/special_pkt_process/enable
wifi_param_config/special_pkt_process/interface
其中,wifi_param_config是已有的proc文件目录,本次需要新增special_pkt_process这个目录和enable、interface两个文件。
wifi_param_config和special_pkt_process通过单独的两个函数来建立,并通过module_init来执行的。
- 相关代码如下:
#file name:wifi_param_config.c
static int __init wifi_param_config_init(void)
module_init(wifi_param_config_init);
#file name:special_pkt_process.c
static int __init special_pkt_process_init(void)
module_init(special_pkt_process_init);
file name:Makefile
obj-y += special_pkt_process.o
obj-y += wifi_param_config.o
- 测试发现,建special_pkt_process目录会失败。
分析过程
- 经过分析,怀疑可能和父目录的建立时序有关。通过在init函数中加打印证实了这一点。
关于module_init
- 相关代码如下:
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6)
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)
#define __initcall(fn) device_initcall(fn)
/**
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
*
* module_init() will either be called during do_initcalls() (if
* builtin) or at module insertion time (if a module). There can only
* be one per module.
*/
#define module_init(x) __initcall(x);
- module_init 其实是一个宏,而并非函数,最终都是通过__define_initcall这个调用来实现的。__define_initcall通过其中的参数,可以控制不同__define_initcall的调用顺序。
module_init函数的执行顺序
- 同是module_init的函数,调用顺序没有高与低,但是总有执行的先后。
- 原理分析:
– Linux源码在编译的时候,通过使用module_init告知编译器链接,自定义一个专门用来存放这些初始化函数的地址段,将对应的函数入口统一放在一起;
– 内核启动的时候统一扫描这个段的开始,按照顺序,可以执行所有这些初始化函数;
|-------------------| | .... .... ..... | | .initcall6.init | ---- device_initcall | .... .... ..... | |-------------------|
- 核心源码如下:
static void __init do_initcalls(void)
{
initcall_t *call;
for (call = __initcall_start; call < __initcall_end; call++) {
...
(*call)();
}
}
从中不难看出,__define_initcall中不同等级的的初始化函数,module_init中的同一等级的函数。在底层调用时是一视同仁的,只是按顺序逐个调用,严格来说,是按地址顺序(从低到高)调用的。
两个函数的地址
- 通过System.map(或/proc/kallsyms)可以查看两个init函数的顺序:
linux/System.map
c0888e1c t special_pkt_process_init
c0888e34 t wifi_param_config_init
- 按前面分析,果然吻合,父目录的初始化函数在后,地址较高。
两个函数地址的高低如何确定
- 函数地址的高低实际上是由链接过程(链接顺序)决定的;
- 链接先后顺序,默认以makefile里面文件的先后顺序做依据,否则先后顺序由链接脚本指定。在这里,是由makefile决定的。
解决方案
修改Makefile,先链接父目录对应文件:
obj-y += wifi_param_config.o
obj-y += special_pkt_process.o
修改C文件
- 将special_pkt_process_init移到wifi_param_config_init函数中,不再使用module_init调用。
如本文对你有些许帮助,欢迎大佬加关注、评论、点赞,有关必回关
530

被折叠的 条评论
为什么被折叠?



