1. 引言:模块化——Linux 的灵动之魂
Linux 内核如同一个巨型乐高城堡,内核模块(Kernel Module) 就是那些可以随时增减的功能积木。想象一下:当你插入一块新的显卡,系统能自动加载对应驱动;当你挂载一个陌生文件系统,内核能动态扩展支持能力——这一切都归功于内核模块的魔法。
为什么需要内核模块?
- 动态扩展:无需重启即可添加硬件驱动或新功能
- 资源节约:按需加载,避免冗余代码占用内存
- 开发便捷:无需重新编译整个内核即可测试新功能
2. 内核模块的本质与架构
2.1 模块的二进制本质
- 文件格式:
.ko
(Kernel Object) - 运行特权:在 Ring 0 级直接操作硬件
- 典型大小:从几KB(简单驱动)到几MB(复杂GPU驱动)
通过 modinfo
查看模块信息:
$ modinfo ext4
filename: /lib/modules/5.15.0-78-generic/kernel/fs/ext4/ext4.ko
license: GPL
description: Fourth Extended Filesystem
depends: mbcache,jbd2
2.2 模块与内核的共生关系
内核维护的模块链表结构(简化版):
struct module {
char name[MODULE_NAME_LEN]; // 模块名称
struct list_head list; // 链表节点
void *module_core; // 代码段地址
unsigned int init_size; // 初始化内存大小
// ...其他关键字段
};
3. 模块生命周期全流程剖析
3.1 加载过程(insmod)
- 文件读取:将
.ko
从磁盘加载到内存 - 符号解析:绑定未定义符号到内核导出表
- 内存分配:通过
vmalloc
分配模块空间 - 初始化执行:调用
module_init()
函数 - 注册到系统:加入内核模块链表
实战观察加载过程:
# 查看实时日志
sudo dmesg -w &
sudo insmod hello.ko
# 输出示例
[ 253.716333] hello: loading out-of-tree module taints kernel.
[ 253.716987] Hello, Kernel World!
3.2 卸载过程(rmmod)
- 引用计数检查:确保无其他模块依赖
- 清理函数调用:执行
module_exit()
- 资源释放:释放内存、关闭设备
- 链表移除:从内核模块列表删除
强制卸载危险操作(仅用于调试):
sudo rmmod -f hello # 可能引发系统不稳定!