Windows 10 NDIS过滤驱动触发DPC_WATCHDOG_VIOLATION蓝屏问题求助
问题根因
你遇到的是自旋锁调用IRQL不匹配导致的死锁,直接触发了DPC看门狗超时,具体逻辑如下:
- NDIS自旋锁的两个API有明确的使用限制:
NdisAcquireSpinLock:会自动将当前IRQL提升到DISPATCH_LEVEL,再获取锁,可在<= DISPATCH_LEVEL的任意IRQL调用NdisDprAcquireSpinLock:仅可在已经处于DISPATCH_LEVEL的上下文调用,不会修改当前IRQL,直接尝试获取锁
- 你的
StartReqCancel取消例程执行流程存在错误:- 进入取消例程时,系统持有Cancel自旋锁,IRQL为DISPATCH_LEVEL
- 调用
IoReleaseCancelSpinLock(pIrp->CancelIrql)后,IRQL会回退到触发取消逻辑前的原始IRQL,从你的调用栈看,原始IRQL是PASSIVE_LEVEL(取消逻辑由线程退出时的IRP清理流程触发,运行在PASSIVE_LEVEL) - 此时你调用
NdisDprAcquireSpinLock获取startIrpLock,因为当前IRQL是PASSIVE_LEVEL,调用NdisDprAcquireSpinLock属于未定义行为,你成功拿到了锁,但IRQL仍然停留在PASSIVE_LEVEL
- 死锁触发流程:
- 你在PASSIVE_LEVEL持有
startIrpLock,执行ExFreePool释放内存 - 同一个CPU触发网卡接收DPC中断,IRQL提升到DISPATCH_LEVEL,抢占当前低IRQL的代码执行
- DPC上下文调用
FilterReceiveNetBufferLists,尝试调用NdisDprAcquireSpinLock获取startIrpLock,但锁已经被低IRQL的代码持有 - 高IRQL的DPC上下文会一直自旋等待锁,低IRQL的取消例程永远得不到CPU调度执行,无法释放锁,形成死锁
- DPC上下文长时间执行超过系统DPC看门狗的阈值(默认100ms),触发
DPC_WATCHDOG_VIOLATION类型的BSOD
- 你在PASSIVE_LEVEL持有
修复方案
- 把
StartReqCancel里的NdisDprAcquireSpinLock替换为NdisAcquireSpinLock,对应的释放自旋锁的API替换为NdisReleaseSpinLock:这个API会自动处理IRQL提升,保证持有自旋锁期间IRQL一直是DISPATCH_LEVEL,避免低IRQL持有锁被高IRQL抢占的问题 - 可选优化:你当前持有自旋锁期间执行了多次
ExFreePool操作,虽然逻辑没问题,但自旋锁持有时间越长,出现性能问题的概率越高,如果后续还出现类似超时,可以把要释放的内存指针先暂存到局部数组,释放自旋锁后再执行ExFreePool,减少锁持有时间
验证点
你可以用WinDbg在复现场景下验证问题:
- 触发BSOD后,用
!irql查看触发BSOD的CPU的当前IRQL,死锁时该值为DISPATCH_LEVEL - 用
!spinlock <startIrpLock地址>查看持有锁的CPU,再切换到对应CPU的上下文,用!irql查看该CPU持有锁时的IRQL,会发现值为PASSIVE_LEVEL,和自旋锁持有要求不符
内容的提问来源于stack exchange,提问作者Kola73
相关产品推荐
相关产品推荐

