Workqueue запускается, прерывается и никогда не заканчивается, вызывая зависание процессора - PullRequest
0 голосов
/ 08 мая 2019

Предоставить пример минимального кода будет сложно, но я предоставлю некоторый sudo-код, который, надеюсь, поможет понять точку / вопрос.

TL; DR: Моя рабочая очередь запускается, прерывается, а затем никогда не заканчивается, вызываязависание процессора.

Я создаю сетевой драйвер для устройства 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 вместо workqueue, потому что я учусь и, честно говоря, могу перевести всю работу в 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 (пока ничего страшного).IRQ, очевидно, выводит меня из рабочей очереди, на которой запланирован NAPI.Теперь вместо того, чтобы возвращаться к рабочей очереди, она обрабатывает функцию NAPI (опять же, это не так уж сложно для моей программы, я уверен, что это приоритетная вещь).Затем вызовы моего ядра ndo_start_xmit снова попадают в spin_lock, после чего процессор останавливается.Ни при каких условиях программа никогда не возвращается к запланированной, но прерванной работе из work_handler.При тестировании это фактически было прервано между двумя операторами печати, так что я знаю, что он никогда даже не делал частичного возврата.

Так почему workqueue никогда не возвращается?Есть ли способ решить это?Мое первоначальное предположение - flush_work, но это больше похоже на исправление проблемы, а не на ее устранение.Было бы лучше переместить мою Tx schedule_work, чтобы быть частью обработчика NAPI вместо этого?

Спасибо за понимание.

ОБНОВЛЕНИЕ: Это после того, как я принял совершенно хороший ответ.В последующем обсуждении я предложил несколько экземпляров NAPI.Проще говоря, 1 NAPI на нетдев, в противном случае появляется много проблем.Я не мог отличить причину напи с помощью только структуры напи (возможно, кто-то видит способ, которым я не делаю, кроме злоупотребления бюджетным числом).Что касается моей проблемы, я обнаружил, что это была проблема с 3 шагами.Рабочая очередь была прервана RX irq / napi.Затем Rx napi был заблокирован вызовом ndo_start_xmit.ndo_start_xmit пытается захватить тот же спин-блокировку, который использовал рабочая очередь, поэтому я застрял в положении, в котором ничто не может двигаться, следовательно, происходит останов процессора.

1 Ответ

2 голосов
/ 08 мая 2019

Если область между 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);
...