Linux内核驱动如何处理设备移除?字符设备USB拔插场景实现方案
问题解答
1. 内核原生引用计数及回调机制
Linux内核原生提供了struct kref结构实现轻量级引用计数,完全可以满足你的需求,无需自行造轮子:
- 在你的字符设备管理结构体中嵌入
struct kref成员,每个设备实例独立持有,无全局依赖,支持任意数量USB设备接入 - 在
file_operations的open回调中调用kref_get()对引用计数加1 - 在
file_operations的release回调中调用kref_put()对引用计数减1,kref_put()的第二个参数就是所有引用全部释放后自动触发的回调函数,你可以在这个回调里完成管理结构体内存释放、mutex销毁等操作
内核不会直接统计单个字符设备的打开句柄数,但kref本身就是为这类单对象引用计数场景设计的,完全匹配你的需求。
2. 方案可行性
这是USB字符驱动热拔插场景的标准实现方案,完全可行,符合内核设计规范:
- 所有IO操作入口(read/write/ioctl)首先检查设备在位标记,标记为已拔出时直接返回
-ENODEV错误即可 - 引用计数保证只要有未完成的IO或者未关闭的句柄,管理结构体的内存就不会被释放,正在持有的mutex可以正常完成解锁操作,不会出现野指针访问问题
3. USB拔出时移除字符设备的标准流程
在USB驱动的disconnect回调中按以下顺序执行:
- 原子设置设备在位标记为「已拔出」,该标记需要在IO操作的公共判断路径里被访问,保证新进入的系统调用直接返回错误
- 调用
cdev_del()接口从内核中注销该字符设备,彻底阻止新的open请求打开该设备 - 调用
kref_put()释放你在创建设备时持有的初始引用计数
注意:此时不要直接释放管理结构体的内存,也不要销毁mutex,所有释放逻辑都放到kref的释放回调里执行,等所有已打开的句柄全部关闭、所有运行中的IO全部完成后,回调会自动触发执行资源清理。
内容的提问来源于stack exchange,提问作者Sven
相关产品推荐
相关产品推荐

