Scull驱动写入字符设备时出现list_add/list_del损坏问题求助
排查scull模块
list_add()/list_del()损坏及信号量相关问题的思路 核心排查方向
虽然你简化了write函数,但错误指向链表操作损坏,结合信号量的使用,重点从以下几点入手:
1. 信号量初始化是否合规
- 检查
struct semaphore变量的初始化:必须用sema_init(&sem, 1)(动态初始化)或static DECLARE_SEMAPHORE_GENERIC(sem, 1)(静态初始化),绝对不能直接赋值0或1。信号量内部包含链表结构,直接赋值会破坏其内部节点的初始化状态,这是触发链表损坏的高频原因。
2. 信号量的down/up是否完全匹配
- 确保每一次
down_interruptible()(或其他down类调用)都对应一次up(),哪怕write函数提前返回(比如错误分支)。只down不up会导致信号量内部链表状态异常,后续操作触发损坏。 - 遍历write函数的所有退出路径:比如
down_interruptible()返回-EINTR时,是否遗漏up()?其他错误分支有没有忘记释放信号量?
3. 全局链表的操作合法性
scull模块中struct scull_dev的链表成员(比如list)可能在其他函数(open、release等)中有非法操作,需检查:
- 调用
list_add()/list_del()时,节点是否已在链表中? - 有没有在未持有信号量的情况下修改全局链表?
- 链表节点是否未初始化就加入链表,或被重复释放?
4. 内存越界排查
检查struct scull_dev的定义是否正确,是否存在数组越界、指针错误赋值等情况,导致信号量内部的wait_list链表内存被覆盖破坏。
5. 内核调试工具辅助定位
- 在关键位置(down/up前后、链表操作前后)添加
dump_stack(),打印栈信息确认错误触发时机。 - 开启内核
CONFIG_DEBUG_LIST和CONFIG_DEBUG_SEMAPHORE配置,重新编译内核。内核会对链表和信号量操作做严格检查,输出更详细的错误信息,直接定位异常节点或信号量。
快速验证步骤
- 替换信号量的初始化代码为标准方式;
- 在write函数所有退出路径补全
up()调用,确保down/up完全匹配; - 检查open函数中是否正确初始化了scull_dev的链表节点(比如
INIT_LIST_HEAD(&dev->list))。
内容的提问来源于stack exchange,提问作者Aman
相关产品推荐
相关产品推荐

