modprobe vs insmod:为什么modprobe比insmod聪明这么多?
作者:Linux内核研究员 | 2026-05-06
导读
搞Linux驱动的都懂——insmod动不动就报Unknown symbol,modprobe一上,啥错都没了。很多人懵:不都是加载驱动吗?为啥modprobe就这么聪明?本文从内核源码层面彻底讲清楚它们的核心差异,读完你将彻底掌握模块依赖加载的原理。
适合人群:Linux驱动开发者、嵌入式工程师、内核爱好者
一句话戳穿真相
insmod = 傻憨憨跑腿,只送单个,不问依赖
modprobe = 聪明管家,查家谱、排顺序、把依赖全给你装齐!
1. insmod有多蠢?
你让它装a.ko,它根本不知道a.ko还要靠b.ko和c.ko!它直接硬塞 → 内核找不到符号 → 啪!Unknown symbol报错!
insmod的源码逻辑极其简单(来自kmod项目):
// kmod/libkmod.c - insmod核心逻辑
static int do_load(struct kmod_ctx *ctx, const char *command,
const char *args)
{
// insmod只做一件事:直接加载指定的ko文件
// 它不会去检查任何依赖关系!
return kmod_module_probe_insert(ctx, mod, flags, NULL, NULL, NULL);
}
它的脑子只有一句话:
"你让我装我就装,装不上拉倒。"
2. modprobe有多聪明?
它上来先干3件事:
① 翻"家谱"
它去读:/lib/modules/xxx/modules.dep
里面写得清清楚楚:
# modules.dep示例(由depmod工具生成)
a.ko: b.ko c.ko
b.ko: c.ko
c.ko:
② 自动排顺序
它一算:必须先装c → 再装b → 最后装a
③ 自动一个个装
它自己悄悄把依赖全装上,最后再装你要的驱动。你完全不用管!
modprobe的源码逻辑(来自kmod项目):
// kmod/libkmod.c - modprobe核心逻辑
static int modprobe_do_format(struct kmod_ctx *ctx, const char *name)
{
// 1. 先解析modules.dep,获取依赖图
struct kmod_list *dependencies = NULL;
kmod_module_get_dependencies(mod, &dependencies);
// 2. 按依赖顺序排序(拓扑排序)
// 3. 依次加载每个依赖模块
// 4. 最后加载目标模块
}
3. 内核层面:模块依赖是怎么工作的?
Linux内核模块加载涉及两个重要数据结构(include/linux/module.h):
// 内核模块结构体(关键字段)
struct module {
enum module_state state;
/* 依赖其他模块 */
struct list_head source_list; // 我依赖谁
struct list_head target_list; // 谁依赖我
/* 模块信息 */
const char *name; // 模块名
unsigned long flags; // 标志位
// ...
};
内核符号表是解决Unknown symbol的关键:
// kernel/module.c - 内核符号表
static int resolve_symbol(struct module *mod, const struct load_info *info,
const char *name, struct module *owner)
{
// 在内核符号表中查找符号
// 如果找不到,说明依赖的模块没加载
// 返回 -ENOSYS 表示符号未定义
}
当你加载a.ko但没加载b.ko时:
insmod a.ko
[ 1.234567] a: Unknown symbol b_func (err -2)
[ 1.234567] a: Unknown symbol c_data (err -2)
-2就是-ENOENT(没有那个文件或目录),意思是"这个符号在内核符号表里找不到"。
4. modules.dep是怎么生成的?
答案是depmod工具。它扫描所有ko文件,提取MODULE_DEPEND()宏,构建依赖图。
# depmod工作流程
$ depmod -a
# 遍历 /lib/modules/$(uname -r)/
# 解析每个.ko文件的 MODULE_ALIAS() 和 MODULE_DEPEND()
# 生成 modules.dep 和 modules.symbols
实际查看你系统的modules.dep:
$ cat /lib/modules/$(uname -r)/modules.dep | head -20
kernel/drivers/char/tty.ko: kernel/drivers/char/tty_io.ko
kernel/drivers/char/tty_io.ko:
kernel/drivers/char/vt.ko: kernel/drivers/char/tty_io.ko
5. 最形象的段子(秒懂)
insmod:
你让它送个快递,它不管你家有没有人、东西缺不缺零件,扔门口就跑,装不上怪你自己。
modprobe:
像个细心保姆,先查你缺啥,再按顺序给你摆好,最后告诉你:装完啦!
6. 真实工作流程(人话版)
你输入:modprobe a
│
▼
modprobe 查 modules.dep
│
▼
发现 a 靠 b,b 靠 c
│
▼
自动按顺序:c → b → a
│
▼
依次加载,一个不漏
│
▼
完美成功,不报错!
7. 那insmod还有啥用?
| 场景 | 用insmod | 用modprobe |
|---|---|---|
| 手动调试单个驱动 | ✅ 可以 | ❌ 没必要 |
| 明确知道没有依赖 | ✅ 可以 | ❌ 杀鸡用牛刀 |
| 加载独立小模块 | ✅ 可以 | ❌ 杀鸡用牛刀 |
| 正经干活、正式环境 | ❌ 容易报错 | ✅ 永远用它 |
8. 终极总结(记这4句)
| 序号 | 结论 |
|---|---|
| 1 | insmod只装单个,不管依赖,容易报错 |
| 2 | modprobe查依赖、排顺序、自动装全套 |
| 3 | Unknown symbol基本都是由insmod误用导致 |
| 4 | 正式环境,永远优先modprobe |
附录:相关命令速查
| 操作 | 命令 |
|---|---|
| 加载模块 | modprobe 模块名 / insmod 路径/模块.ko |
| 卸载模块 | modprobe -r 模块名 / rmmod 模块名 |
| 查看已加载 | lsmod |
| 查看模块信息 | modinfo 模块名 |
| 查看依赖 | modprobe --show-depends 模块名 |
| 强制加载(忽略依赖) | insmod --force 路径/模块.ko |
看完还不懂?记住这个原则:
遇到模块加载问题,第一反应是换成modprobe,而不是--force!