[PATCH net 2/2] netpoll: avoid blocking on the transmit lock in queue_process

From: Karl Mehltretter

Date: Mon Sep 28 2026 - 02:43:34 EST


queue_process() disables interrupts before taking the device transmit
lock with HARD_TX_LOCK(). The lock may sleep on PREEMPT_RT:

BUG: sleeping function called from invalid context
in_atomic(): 0, irqs_disabled(): 1, non_block: 0
Workqueue: events queue_process
rt_spin_lock
queue_process
process_one_work

Use HARD_TX_TRYLOCK() instead. If another CPU owns the lock, put the skb
back at the head of the deferred queue, restore interrupts and retry
after the existing HZ / 10 delay.

Fixes: 3640543df26f ("[PATCH] netpoll: fix netpoll lockup")
Cc: stable@xxxxxxxxxxxxxxx # 6.12+
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@xxxxxxxxx>
---
net/core/netpoll.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index e0cfcb05468e2..a3c94f0b3f764 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -166,7 +166,13 @@ static void queue_process(struct work_struct *work)
skb_set_queue_mapping(skb, q_index);
}
txq = netdev_get_tx_queue(dev, q_index);
- HARD_TX_LOCK(dev, txq, smp_processor_id());
+ if (!HARD_TX_TRYLOCK(dev, txq)) {
+ netpoll_txq_queue_head(npinfo, skb);
+ local_irq_restore(flags);
+
+ schedule_delayed_work(&npinfo->tx_work, HZ / 10);
+ return;
+ }
if (netif_xmit_frozen_or_stopped(txq) ||
!dev_xmit_complete(netpoll_start_xmit(skb, dev, txq))) {
netpoll_txq_queue_head(npinfo, skb);
--
2.53.0