明白了,我给你整理一份 “Linux 卸载驱动模块导致内核崩溃的排查与调试实践记录”,包括操作步骤、常见问题、调试工具和排查思路,适合做笔记或技术记录。
Linux 驱动模块卸载导致内核崩溃 — 排查调试记录
一、问题背景
在 Linux 系统中,有时需要卸载内核模块(Driver Module)进行更新或调试,例如:
sudo modprobe -r my_driver
# 或
sudo rmmod my_driver
在执行时,系统可能出现:
- 内核 oops / panic
- 系统卡死或重启
- dmesg 出现
BUG: unable to handle kernel NULL pointer
目的:分析内核崩溃原因并排查解决。
二、前期准备
- 安装调试工具
sudo apt install linux-tools-$(uname -r) linux-headers-$(uname -r) gdb crash
- 开启内核日志持久化
sudo dmesg -n 7 # 将所有日志打印到控制台
sudo journalctl -f
- 保留内核 panic 日志
- 如果崩溃导致重启,可以开启 kdump:
sudo apt install kdump-tools
sudo systemctl enable kdump
sudo systemctl start kdump
- 配置 /etc/kdump.conf,保存 crash dump。
三、卸载模块的安全流程
1. 查看模块依赖
lsmod | grep my_driver
modinfo my_driver
确认模块没有被其他模块依赖,否则卸载会失败或导致依赖模块崩溃。
2. 停用使用该模块的资源
- 关闭使用设备的应用程序
- 卸载文件系统 / 断开网卡 / 停止硬件操作
3. 卸载模块
sudo modprobe -r my_driver
避免直接
rmmod
可能引发依赖问题。
四、出现崩溃后的排查
1. 查看内核日志
dmesg | tail -50
journalctl -k -n 100
常见信息:
- NULL pointer dereference
- use-after-free / memory corruption
- driver BUG 触发
oops
2. 收集内核 oops 信息
sudo cat /var/log/kern.log | grep -i my_driver
- 记录函数调用栈、错误地址
- 注意
Call Trace
部分,是关键线索
3. 使用 crash 工具分析 dump
假设已配置 kdump 并生成 vmcore:
sudo crash /usr/lib/debug/boot/vmlinux-$(uname -r) /var/crash/2025-10-13/vmcore
在 crash shell 内:
bt # 查看堆栈回溯
ps # 查看进程状态
mod # 查看模块信息
分析崩溃是由于模块未正确释放资源,还是内核 bug。
五、调试与解决策略
问题类型 | 解决策略 |
---|---|
模块仍被使用 | 确认设备关闭 / 依赖模块卸载 |
内存释放错误 | 检查 module_exit() 是否正确释放所有内核资源(task, memory, irq) |
内核访问 NULL / 野指针 | 查看模块源码,确认 exit 函数中没有访问已释放结构体 |
多线程 / IRQ 相关 | 禁用中断或停止 worker thread 后再卸载模块 |
建议做法:
- 添加调试日志:
printk(KERN_INFO "my_driver: exiting module\n");
- 使用
CONFIG_DEBUG_KERNEL
/CONFIG_DEBUG_KMEMLEAK
编译内核,检查内存泄漏。 - 模拟卸载流程:
- 关闭所有设备使用
- 停止 kernel thread / worker thread
- 再执行
modprobe -r
六、最佳实践
- 避免直接 rmmod,推荐
modprobe -r
,自动处理依赖。 - 内核线程先 stop,再 free memory,避免野指针访问。
- 多线程驱动使用锁(spinlock / mutex)防止卸载时竞态。
- 测试环境先模拟,避免生产环境 panic。
- 开启内核 crash dump,方便分析 post-mortem。
七、记录示例(调试笔记模板)
时间: 2025-10-13 14:32
操作: modprobe -r my_driver
现象: 系统 panic, call trace:
[ 1234.567890] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010
[ 1234.567895] CPU: 2 PID: 567 Tainted: G
[ 1234.567899] Call Trace:
[ 1234.567901] my_driver_exit+0x34/0x50 [my_driver]
...
分析: module_exit() 中访问了已释放内存
解决: 修复 exit 函数,先 stop worker,再释放资源
发表回复