Linux内核学习——模块机制
Linux 内核源码版本:6.6LTS
模块是内核中非常重要的机制,它为Linux内核向外提供了一个接口,其全称为动态可加载内核模块(Loadable Kernel Module)。Linux内核之所以提供模块机制,是因为它本身是一个单内核(monolithic kernel)。单内核的最大有点是效率高,其缺点是扩展性和维护性相对较差,模块机制就是为了弥补这一缺点。
模块是具有独立功能的程序,他可以被单独编译但是不能单独运行。他在运行时被连接进内核作为内核的一部分在内核空间运行。模块通常是由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。
模块的加载
手动加载
使用insmod和modprobe命令
自动加载
通过内核线程kmod来实现,而kmod通过调用modprobe来实现模块的加载
模块的加载过程
insmod原理
insmod程序和ld有些类似,他将模块的代码和数据装入内核,然后使用内核的符号表解析模块中任何未解析的符号。然而,与链接器不同,内核不会修改模块的磁盘文件,而仅仅是修改内存中的副本。
以insmod为例
- insmod首先通过系统调用query_module遍历模块链表来获得系统中的所有符号及其在内存中的物理地址,然后利用得到的符号表修正模块中引用到的外部符号,在次过程中记录下该模块所要用到的模块。由于是直接用这些符号在内存中的物理地址进行更正,所以模块内核空间的地址引用是正确的,如果该模块还有一些符号的地址未知,则该模块不能被加载
- insmod填写模块module_ref表,其中dep指向本模块所使用的模块,即在修正本模块使用到的外部符号过程中标记过的模块,这些模块在内存中的物理地址也是通过系统调用query_module得到的。由于别的模块可能要使用本模块提供的服务,所哟还需要提供本模块的输出符号表,此部分工作也由insmod完成
- insmod发出系统调用create_module,由该系统调用为模块分析足够的内存空间,并初始化位于该空间起始处的struct module结构体,然后insmod通过系统调用init_module让系统完成余下工作。
modprobe
和insmod类似,modprobe也用来将模块装载入内核。他和insmod的区别在于:他会考虑要装载的模块是否引用了一些当前内核不存在的符号。如果有这类引用,modprobe会在当前模块搜索路径中查找定义了这些符号的其他模块。如果找到,他会同时将这些模块加载进去。如果这种情况下使用insmod,命令会返回失败,并输出unresolved symbols错误消息。
模块的卸载
手动卸载
使用rmmod命令
自动卸载
通过kerneld或kmod自动卸载
模块的卸载过程
以rmmod为例
在系统找到要卸载的模块之后,根据其引用链表检查是否有别的模块要使用本模块,如果有则打印出错误信息并停止卸载;否则调用delete_module函数完成卸载。该函数将调用free_module函数完成:
- 释放系统分配给模块的资源
- 修改模块所依赖的所有模块的引用链表,将该模块从链表中删除
- 将该模块从系统的模块链表中删除
- 释放分配给该模块的核心内存
内核符号表
上面提到insmod会使用内核符号表来解析模块中为定义的符号。公共内核符号表中包含了所有的全局内核项(即函数和变量)的地址,这是实现模块化驱动程序所必需的。当模块被装载入内核后,它所导出的任何符号都会变成内核符号表的一部分。

浙公网安备 33010602011771号