]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: fix backlog_unlock_irq_restore() vs CONFIG_PREEMPT_RT
authorEric Dumazet <edumazet@google.com>
Fri, 13 Feb 2026 12:04:27 +0000 (12:04 +0000)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 17 Feb 2026 12:28:10 +0000 (13:28 +0100)
CONFIG_PREEMPT_RT is special, make this clear in backlog_lock_irq_save()
and backlog_unlock_irq_restore().

The issue shows up with CONFIG_DEBUG_IRQFLAGS=y

raw_local_irq_restore() called with IRQs enabled
 WARNING: kernel/locking/irqflag-debug.c:10 at warn_bogus_irq_restore+0xc/0x20 kernel/locking/irqflag-debug.c:10, CPU#1: aoe_tx0/1321
Modules linked in:
CPU: 1 UID: 0 PID: 1321 Comm: aoe_tx0 Not tainted syzkaller #0 PREEMPT_{RT,(full)}
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/24/2026
 RIP: 0010:warn_bogus_irq_restore+0xc/0x20 kernel/locking/irqflag-debug.c:10
Call Trace:
 <TASK>
  backlog_unlock_irq_restore net/core/dev.c:253 [inline]
  enqueue_to_backlog+0x525/0xcf0 net/core/dev.c:5347
  netif_rx_internal+0x120/0x550 net/core/dev.c:5659
  __netif_rx+0xa9/0x110 net/core/dev.c:5679
  loopback_xmit+0x43a/0x660 drivers/net/loopback.c:90
  __netdev_start_xmit include/linux/netdevice.h:5275 [inline]
  netdev_start_xmit include/linux/netdevice.h:5284 [inline]
  xmit_one net/core/dev.c:3864 [inline]
  dev_hard_start_xmit+0x2df/0x830 net/core/dev.c:3880
  __dev_queue_xmit+0x16f4/0x3990 net/core/dev.c:4829
  dev_queue_xmit include/linux/netdevice.h:3384 [inline]

Fixes: 27a01c1969a5 ("net: fully inline backlog_unlock_irq_restore()")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260213120427.2914544-1-edumazet@google.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/core/dev.c

index ac6bcb2a07840671b0910ab1d2a5b588feaeebf0..96f89eb797e891c75f7e9b467e27db7c1a6f92ae 100644 (file)
@@ -231,10 +231,13 @@ static bool use_backlog_threads(void)
 static inline void backlog_lock_irq_save(struct softnet_data *sd,
                                         unsigned long *flags)
 {
-       if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
+       if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
                spin_lock_irqsave(&sd->input_pkt_queue.lock, *flags);
-       else
+       } else {
                local_irq_save(*flags);
+               if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
+                       spin_lock(&sd->input_pkt_queue.lock);
+       }
 }
 
 static inline void backlog_lock_irq_disable(struct softnet_data *sd)
@@ -248,9 +251,13 @@ static inline void backlog_lock_irq_disable(struct softnet_data *sd)
 static inline void backlog_unlock_irq_restore(struct softnet_data *sd,
                                              unsigned long flags)
 {
-       if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
-               spin_unlock(&sd->input_pkt_queue.lock);
-       local_irq_restore(flags);
+       if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
+               spin_unlock_irqrestore(&sd->input_pkt_queue.lock, flags);
+       } else {
+               if (IS_ENABLED(CONFIG_RPS) || use_backlog_threads())
+                       spin_unlock(&sd->input_pkt_queue.lock);
+               local_irq_restore(flags);
+       }
 }
 
 static inline void backlog_unlock_irq_enable(struct softnet_data *sd)