module_init 的优先级

本文解析了Linux内核中module_init及其它初始化宏的作用与区别,在不同的编译配置下这些宏的行为变化,以及它们如何影响模块加载过程。

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

在include/linux/module.h 中有如下定义
#ifndef MODULE
/**
 * 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_exit() - driver exit entry point
 * @x: function to be run when driver is removed
 *
 * module_exit() will wrap the driver clean-up code
 * with cleanup_module() when used with rmmod when
 * the driver is a module.  If the driver is statically
 * compiled into the kernel, module_exit() has no effect.
 * There can only be one per module.
 */
#define module_exit(x)    __exitcall(x);

#else /* MODULE */

/*
 * In most cases loadable modules do not need custom
 * initcall levels. There are still some valid cases where
 * a driver may be needed early if built in, and does not
 * matter when built as a loadable module. Like bus
 * snooping debug drivers.
 */
#define early_initcall(fn)        module_init(fn)
#define core_initcall(fn)        module_init(fn)
#define core_initcall_sync(fn)        module_init(fn)
#define postcore_initcall(fn)        module_init(fn)
#define postcore_initcall_sync(fn)    module_init(fn)
#define arch_initcall(fn)        module_init(fn)
#define subsys_initcall(fn)        module_init(fn)
#define subsys_initcall_sync(fn)    module_init(fn)
#define fs_initcall(fn)            module_init(fn)
#define fs_initcall_sync(fn)        module_init(fn)
#define rootfs_initcall(fn)        module_init(fn)
#define device_initcall(fn)        module_init(fn)
#define device_initcall_sync(fn)    module_init(fn)
#define late_initcall(fn)        module_init(fn)
#define late_initcall_sync(fn)        module_init(fn)

#define console_initcall(fn)        module_init(fn)
#define security_initcall(fn)        module_init(fn)

#endif

可见没有定义了MODULE的话,#define module_init(x)    __initcall(x);
#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
所以module_init == device_initcall == __define_initcall(fn, 6)
而一般在buildin的时候在.config 中是没有定义MODULE

MODULE是在kernel 根目录下面的makefile中定义的
KBUILD_AFLAGS_MODULE  := -DMODULE
KBUILD_CFLAGS_MODULE  := -DMODULE

因此如果在build module的时候会定义MODULE。而定了了MODULE的话,则下面的都是同一个优先级
#define early_initcall(fn)        module_init(fn)
#define core_initcall(fn)        module_init(fn)
#define core_initcall_sync(fn)        module_init(fn)
#define postcore_initcall(fn)        module_init(fn)
#define postcore_initcall_sync(fn)    module_init(fn)
#define arch_initcall(fn)        module_init(fn)
#define subsys_initcall(fn)        module_init(fn)
#define subsys_initcall_sync(fn)    module_init(fn)
#define fs_initcall(fn)            module_init(fn)
#define fs_initcall_sync(fn)        module_init(fn)
#define rootfs_initcall(fn)        module_init(fn)
#define device_initcall(fn)        module_init(fn)
#define device_initcall_sync(fn)    module_init(fn)
#define late_initcall(fn)        module_init(fn)
#define late_initcall_sync(fn)        module_init(fn)

#define console_initcall(fn)        module_init(fn)
#define security_initcall(fn)        module_init(fn)

<think>好的,我现在需要帮助用户了解Linux内核模块中module_init和late_initcall的用法及区别。首先,我要回忆一下内核初始化的相关知识。记得内核模块的初始化函数是通过宏来定义的,这些宏决定了函数在内核启动过程中的调用顺序。 用户问的是module_init和late_initcall,所以需要明确这两者的不同之处。可能还有其他类似的宏,比如__initcall,但用户主要关注这两个。首先,我应该解释每个宏的基本用法,然后比较它们的执行顺序和用途差异。 我记得内核的初始化分为多个阶段,不同的初始化宏对应不同的优先级module_init通常用于设备驱动,而late_initcall可能用于那些需要在内核初始化后期执行的模块。需要确认这一点是否正确。例如,module_init对应的初始化级别可能比late_initcall更早,或者更晚? 接下来,我需要查阅内核源码中的相关信息,或者参考内核文档。比如,在include/linux/init.h中,定义了不同级别的初始化宏,如core_initcall、postcore_initcall、arch_initcall、subsys_initcall、fs_initcall、device_initcall、late_initcall等,它们的顺序是依次递增的,即优先级依次降低。而module_init宏会根据模块是否内置到内核还是作为可加载模块来区分:如果是内置的,它等同于device_initcall;如果是可加载模块,则会被标记为模块的初始化函数,在模块加载时由insmod或modprobe调用。 所以,当模块被编译进内核时,module_init对应的初始化函数会在device_initcall阶段执行,而late_initcall则是在更晚的阶段执行。因此,它们的执行顺序不同,导致用途也不同。late_initcall通常用于那些需要等待其他子系统初始化完成后再执行的代码。 需要确保这些信息准确无误,可能需要引用相关的内核文档或书籍。例如,《Linux设备驱动程序》一书中可能提到这些初始化宏的使用方法。另外,应该给出示例代码,说明如何在实际模块中使用这两个宏,以及它们在内核启动时的执行顺序差异。 用户可能还想知道为什么会有不同的初始化宏,以及如何选择合适的宏。这时候需要解释内核初始化的阶段划分,以及不同子系统之间的依赖关系。例如,某些驱动可能依赖于其他子系统已经初始化完成,因此需要将它们的初始化函数放在较晚的阶段。 最后,总结两者的主要区别:执行顺序不同,使用场景不同。同时,提醒用户注意模块是内置还是可加载的情况,因为module_init的行为会有所不同。如果是可加载模块,其初始化函数在模块插入时执行,而内置模块则在对应的初始化阶段执行。 在生成相关问题时,需要考虑用户可能进一步的问题,例如其他初始化宏的区别,或者如何调试初始化顺序问题。这样可以帮助用户更深入地理解内核模块的初始化机制。</think>### module_init和late_initcall的区别与用法 #### 一、基本定义 1. **module_init** 是Linux内核模块最常用的初始化宏,用于声明模块的入口函数。根据模块类型(内置/可加载)有不同的行为: - 当模块**编译进内核**时,初始化函数在`device_initcall`阶段执行(第6级) - 当模块**动态加载**时,初始化函数在`insmod/modprobe`时执行 2. **late_initcall** 属于内核初始化阶段中**最后一级**的初始化宏(第7级),专门用于需要延迟执行的初始化操作[^1] #### 二、执行顺序对比 $$ \begin{array}{|c|c|} \hline \text{初始化阶段} & \text{优先级} \\ \hline core\_initcall & 1 \\ postcore\_initcall & 2 \\ arch\_initcall & 3 \\ subsys\_initcall & 4 \\ fs\_initcall & 5 \\ device\_initcall & 6 \\ late\_initcall & 7 \\ \hline \end{array} $$ #### 三、典型使用场景 1. **module_init** 设备驱动初始化(如注册PCI驱动)、子系统注册等需要较早初始化的操作 ```c // 网络驱动示例 static int __init mynet_init(void) { register_netdev(net_device); } module_init(mynet_init); ``` 2. **late_initcall** 需要等待其他子系统就绪的操作,例如: - 依赖文件系统初始化的模块 - 需要最后初始化的硬件组件 - 系统状态监控模块 ```c // 延迟初始化示例 static int __init late_demo(void) { printk("This runs after all regular initcalls"); } late_initcall(late_demo); ``` #### 四、关键差异总结 | 特性 | module_init | late_initcall | |---------------------|--------------------------------|-----------------------| | 执行阶段 | 第6级(内置模块)或动态加载时 | 第7级 | | 模块类型 | 支持动态和静态模块 | 仅静态编译进内核的模块| | 典型延迟 | 10ms级 | 100ms级 | | 依赖关系处理 | 常规依赖 | 强延迟依赖 | #### 五、调试技巧 1. 查看初始化顺序: ```bash dmesg | grep "initcall" ``` 2. 通过`/sys/module/`查看模块初始化状态: ```bash ls /sys/module/<module_name>/initstate ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值