提供一个最小的代码示例将很困难,但是我将提供一些sudo代码以期希望您能提出要点/问题。
TL; DR:我的工作队列开始,被中断,然后再也没有完成,导致CPU停顿。
我正在为PCIe设备创建网络驱动程序。对于语言,Tx = host out,Rx = host in。对于Tx方面,我正在使用工作队列(work_struct)。所以。
ndo_start_xmit(){
//Perform some operations and load a DMA.
}
request_irq(irq_handler);
INIT_WORK(work,work_handler);
irq_handler(){
//Check what caused the IRQ
if(ndo_xmit_dma caused irq){
schedule_work(work);
}
}
work_handler(){
if(xmit_called){
spin_lock()
//Do some stuff
spin_unlock()
}
}
然后在Rx方面类似,但是现在使用NAPI代替工作队列,因为我正在学习,老实说可能会将所有工作移至napi(请说明是否可以解决问题)。
irq_handler(){
if(Rx caused the irq){
napi_schedule();
}
}
//Do a bunch of napi releated stuff (never try to grab the spin_lock).
那是什么问题?在我的Tx和Rx IRQ的work_handler中途发生了(到目前为止没什么大不了的)。 IRQ显然使我退出了安排NAPI的工作队列。现在,它不再处理工作队列,而是处理NAPI函数(同样,对于我的程序而言,这并不是什么大问题,我认为这是优先事项)。然后我的内核调用ndo_start_xmit再次进入spin_lock,此时CPU停止运行。程序决不会从work_handler返回计划的但中断的工作。在测试中,它实际上是在2条打印语句之间中断的,所以我知道它甚至从未执行过部分返回。
那么为什么工作队列永远不会返回?有办法解决吗?我最初的猜测是flush_work,但感觉更像是问题的补丁,并未解决问题的根源。将我的Tx schedule_work移到NAPI处理程序中会更好吗?
感谢您的见解。
更新: 这是我接受了一个很好的答案之后。在随后的讨论中,我提出了多个NAPI实例。简而言之,每个netdev 1个NAPI,否则会出现很多问题。我无法仅通过napi结构来区分是什么原因导致了napi(也许有人看到我除了滥用预算数字外没有其他方法)。至于我的问题,我发现这是一个三步问题。工作队列被RX irq / napi中断。然后,通过调用ndo_start_xmit阻止了Rx napi。 ndo_start_xmit尝试获取工作队列正在使用的自旋锁,因此我被卡在无法移动的位置,因此导致CPU停顿。
答案 0 :(得分:2)
如果spin_lock..spin_unlock之间的区域很短,则spin_lock_irqsave可能适用。至少要尝试一下,看看它是否使您的问题消失了。我怀疑NAPI固定了您的work_handler上下文。
虽然_irqsave可能起作用,但您应该进行适当的锁顺序分析。
看看https://www.kernel.org/doc/Documentation/locking/spinlocks.txt;特别是最下面的位:
spin_lock(&lock);
...
<- interrupt comes in:
spin_lock(&lock);