熬秃3个驱动工程师总结:Linux驱动开发10大“死亡坑点”,90%的人栽过!
做嵌入式开发,应用层是甜,内核驱动是险。
多少人能轻松写APP、撸业务逻辑,一碰到Linux驱动就头大:
加载就内核崩溃、死机
应用read/write没反应,查不到原因
中断一注册就卡死,卸载直接Oops
地址映射、锁、并发、竞态到处是坑
设备树一配错,驱动直接不工作
Linux驱动不像单片机裸机,错一个点,直接panic、宕机、硬件烧坏,排查半天都找不到根因。
今天这篇,就是Linux驱动开发避坑指南,
全是一线踩坑血泪总结,新手照着少走半年弯路,老手也能查漏补缺。
01 没搞清内核版本,直接瞎编译
这是最入门、最致命的坑。
避坑:
02 指针越界 & 野指针,直接内核Oops
应用程序崩溃只是退出,
内核崩溃是整机卡死。
未判断指针非空就访问
数组越界写坏内核数据结构
释放后再次使用(野指针)
避坑:
所有指针使用前 if (p == NULL)
内核尽量少用复杂指针操作
用 devm 系列托管内存,减少手动free
03 并发/竞态没加锁,驱动“间歇性发疯”
Linux是多任务、多CPU、抢占内核。
不加锁 = 定时炸弹。
全局变量被多个进程同时修改
中断上下文 & 进程上下文抢同一资源
驱动没锁,运行时偶尔正常、偶尔异常
避坑:
04 中断处理函数写太复杂,系统卡死
中断上下文不能休眠、不能拷贝大量数据、不能阻塞!
很多人在中断里:
用 msleep、udelay 长时间延时
调用 copy_from_user 等会休眠函数
打印大量log、处理复杂逻辑
结果:
避坑:
05 设备树(DTS)配错,驱动 probe 永远不进
现在ARM Linux基本全靠设备树。
只要DTS错一点,驱动根本不执行probe。
常见坑:
compatible 字符串不匹配
reg 地址、中断号写错
时钟、pinctrl 没配置
节点名、路径错误
避坑:
06 ioremap 乱用,地址直接访问崩溃
物理地址不能直接用!
必须经过 ioremap 映射成虚拟地址。
坑点:
直接操作硬件物理地址
ioremap 成功后没判断返回值
没加 __iomem 修饰,被编译器优化坏
避坑:
void __iomem *base = ioremap(addr, size);if (!base) return -ENOMEM;
07 驱动卸载不干净,第二次加载直接炸
很多驱动:
原因:
中断没注销
内存没释放
设备号、cdev 没销毁
锁/队列没清空
避坑:
remove 函数与 probe 完全对称
先关中断 → 再停设备 → 再释放资源
用 devm 托管资源,自动清理
08 用户态与内核态数据拷贝错误
绝对不能直接用 memcpy 拷贝用户指针!
坑:
直接访问用户空间指针
没判断地址合法性
中断上下文拷贝用户数据
避坑:
必须用:
copy_from_user
copy_to_user
失败直接返回错误
09 休眠与原子上下文混用,内核直接panic
内核有原子上下文(中断、自旋锁中),
一旦休眠,内核直接崩溃。
这些函数不能在原子上下文用:
msleep
mutex_lock
copy_from_user
分配大量内存
避坑:
10 调试只会 printk,不会看Oops/panic
驱动崩溃时,大多数人只会干瞪眼。
其实内核Oops信息就是答案:
避坑:
写在最后
Linux驱动,坑不在语法,而在内核机制。
时钟、中断、内存、并发、设备树,任何一个细节错,都是崩溃。
真正的驱动工程师:
这10个坑,你中过几个?
欢迎在评论区聊聊你最崩溃的一次驱动BUG。
觉得这篇干货硬核,
点赞 + 在看 + 转发,