提供一个最小的代码示例是很困难的,但我将提供一些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而不是工作队列,因为我正在学习,而且老实说,很可能会把所有的工作转移到凝固汽油(请说明,如果这将解决问题)。
irq_handler(){
if(Rx caused the irq){
napi_schedule();
}
}
//Do a bunch of napi releated stuff (never try to grab the spin_lock).那有什么问题吗?在我的work_handler中,Tx和Rx会发生(到目前为止没有什么大不了的)。显然,IRQ将我从排定NAPI的工作队列中弹出。现在,它将处理NAPI函数,而不是返回到工作队列(对于我的程序来说,这也不是什么大事,我认为这是一个优先级问题)。然后,我的内核调用ndo_start_xmit再次到达spin_lock,此时CPU停止。在任何时候,程序都不会从work_handler返回预定但中断的工作。在测试中,它实际上是在两个打印语句之间被中断的,所以我知道它从来没有做过部分返回。
那么,为什么工作队列永远不会返回呢?有办法解决这个问题吗?我最初的猜测是flush_work,但这更像是解决问题的补丁,而不是解决问题的根源。将我的Tx schedule_work移动到NAPI处理程序中会更好吗?
谢谢你的洞察力。
更新:这是在我接受了一个完美的答案之后。在随后的讨论中,我提出了多个NAPI实例。简单地说,每个netdev有一个NAPI,否则就会出现很多问题。我无法分辨是什么导致了凝固汽油的结构(也许有人看到的方式,我除了滥用预算号码)。至于我的问题,我发现这是一个3步的问题。工作队列被RX irq/napi打断。Rx随后被ndo_start_xmit的一个调用所阻塞。ndo_start_xmit尝试抓取工作队列使用的自旋锁,因此我陷入了一个无法移动的位置,从而导致CPU失速。
发布于 2019-05-08 14:33:34
如果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);https://stackoverflow.com/questions/56042961
复制相似问题