public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [syzbot] [kernel?] INFO: rcu detected stall in kill
@ 2026-04-03 17:50 syzbot
  2026-04-05  1:21 ` Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue syzbot
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: syzbot @ 2026-04-03 17:50 UTC (permalink / raw)
  To: anna-maria, frederic, linux-kernel, syzkaller-bugs, tglx

Hello,

syzbot found the following issue on:

HEAD commit:    9147566d8016 Merge tag 'sched_ext-for-7.0-rc6-fixes' of gi..
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=151c1516580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=6754c86e8d9e4c91
dashboard link: https://syzkaller.appspot.com/bug?extid=9b95da55ba5146a60734
compiler:       Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=111973d6580000
C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=12070dda580000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/c0b15aadfaef/disk-9147566d.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/9df2af7be859/vmlinux-9147566d.xz
kernel image: https://storage.googleapis.com/syzbot-assets/87eba4cf352e/bzImage-9147566d.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+9b95da55ba5146a60734@syzkaller.appspotmail.com

rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
rcu: 	Tasks blocked on level-0 rcu_node (CPUs 0-1): P5969/1:b..l
rcu: 	(detected by 1, t=10502 jiffies, g=14521, q=2117 ncpus=2)
task:syz-executor    state:R  running task     stack:22432 pid:5969  tgid:5969  ppid:5967   task_flags:0x400140 flags:0x00080000
Call Trace:
 <TASK>
 context_switch kernel/sched/core.c:5298 [inline]
 __schedule+0x15dd/0x52d0 kernel/sched/core.c:6911
 preempt_schedule_irq+0x4d/0xa0 kernel/sched/core.c:7238
 irqentry_exit+0x599/0x620 kernel/entry/common.c:239
 asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:697
RIP: 0010:lock_release+0x2d7/0x3d0 kernel/locking/lockdep.c:5893
Code: 16 7b 11 00 00 00 00 eb b5 e8 45 73 0d 0a f7 c3 00 02 00 00 74 b9 65 48 8b 05 c5 d0 7a 11 48 3b 44 24 28 75 44 fb 48 83 c4 30 <5b> 41 5c 41 5d 41 5e 41 5f 5d e9 95 81 6e ff cc 48 8d 3d 72 64 73
RSP: 0018:ffffc90003aafd78 EFLAGS: 00000286
RAX: d3d4042ff14ac900 RBX: 0000000000000202 RCX: 0000000000000046
RDX: 0000000000000000 RSI: ffffffff8e16b29d RDI: ffffffff8c27d100
RBP: ffff8880290229d8 R08: ffffffff9011ccb7 R09: 1ffffffff2023996
R10: dffffc0000000000 R11: fffffbfff2023997 R12: 0000000000000000
R13: 0000000000000000 R14: ffffffff8e75e5e0 R15: ffff888029021e80
 rcu_lock_release include/linux/rcupdate.h:322 [inline]
 rcu_read_unlock include/linux/rcupdate.h:881 [inline]
 kill_proc_info+0x168/0x180 kernel/signal.c:1481
 kill_something_info kernel/signal.c:1577 [inline]
 __do_sys_kill kernel/signal.c:3953 [inline]
 __se_sys_kill+0xd9/0x460 kernel/signal.c:3947
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x14d/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fb210b3dda7
RSP: 002b:00007ffe1e460eb8 EFLAGS: 00000217 ORIG_RAX: 000000000000003e
RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007fb210b3dda7
RDX: 0000000000000097 RSI: 0000000000000009 RDI: 0000000000000003
RBP: 00007ffe1e460efc R08: 7fffffffffffffff R09: 0000000000000000
R10: 4000000000000000 R11: 0000000000000217 R12: 0000000000000000
R13: 0000000000000064 R14: 000000000003f067 R15: 00007ffe1e460f50
 </TASK>
rcu: rcu_preempt kthread starved for 3053 jiffies! g14521 f0x0 RCU_GP_WAIT_FQS(5) ->state=0x0 ->cpu=0
rcu: 	Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior.
rcu: RCU grace-period kthread stack dump:
task:rcu_preempt     state:R  running task     stack:27744 pid:16    tgid:16    ppid:2      task_flags:0x208040 flags:0x00080000
Call Trace:
 <TASK>
 context_switch kernel/sched/core.c:5298 [inline]
 __schedule+0x15dd/0x52d0 kernel/sched/core.c:6911
 __schedule_loop kernel/sched/core.c:6993 [inline]
 schedule+0x164/0x360 kernel/sched/core.c:7008
 schedule_timeout+0x158/0x2c0 kernel/time/sleep_timeout.c:99
 rcu_gp_fqs_loop+0x312/0x11d0 kernel/rcu/tree.c:2095
 rcu_gp_kthread+0x9e/0x2b0 kernel/rcu/tree.c:2297
 kthread+0x388/0x470 kernel/kthread.c:436
 ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>
rcu: Stack dump where RCU GP kthread last ran:
Sending NMI from CPU 1 to CPUs 0:
NMI backtrace for cpu 0
CPU: 0 UID: 0 PID: 3405 Comm: kworker/R-bat_e Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 03/18/2026
Workqueue: bat_events batadv_tt_purge
RIP: 0010:get_current arch/x86/include/asm/current.h:25 [inline]
RIP: 0010:__sanitizer_cov_trace_pc+0x8/0x70 kernel/kcov.c:216
Code: 8b 3d 04 8b 55 0c 48 89 de 5b e9 e3 99 5e 00 cc cc cc 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 48 8b 04 24 <65> 48 8b 0d 28 db 56 11 65 8b 15 49 db 56 11 81 e2 00 01 ff 00 74
RSP: 0018:ffffc900000078f0 EFLAGS: 00000046
RAX: ffffffff878d4630 RBX: 0000000000000000 RCX: 0000000000000100
RDX: ffff888033120000 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffff888156eed200 R08: 0000000000000003 R09: 0000000000000004
R10: dffffc0000000000 R11: fffff52000000f0c R12: ffff88802b35bc00
R13: dffffc0000000000 R14: ffff888029c47000 R15: ffff888029c47408
FS:  0000000000000000(0000) GS:ffff888125457000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000557a11963a38 CR3: 00000000677c5000 CR4: 0000000000350ef0
Call Trace:
 <IRQ>
 dummy_validate_stream drivers/usb/gadget/udc/dummy_hcd.c:1244 [inline]
 dummy_urb_enqueue+0x270/0x780 drivers/usb/gadget/udc/dummy_hcd.c:1282
 usb_hcd_submit_urb+0x328/0x1b70 drivers/usb/core/hcd.c:1542
 ath9k_hif_usb_reg_in_cb+0x4d5/0x6f0 drivers/net/wireless/ath/ath9k/hif_usb.c:790
 __usb_hcd_giveback_urb+0x376/0x540 drivers/usb/core/hcd.c:1657
 dummy_timer+0xbbd/0x45d0 drivers/usb/gadget/udc/dummy_hcd.c:1995
 __run_hrtimer kernel/time/hrtimer.c:1785 [inline]
 __hrtimer_run_queues+0x53a/0xcc0 kernel/time/hrtimer.c:1849
 hrtimer_run_softirq+0x182/0x5a0 kernel/time/hrtimer.c:1866
 handle_softirqs+0x22a/0x870 kernel/softirq.c:622
 do_softirq+0x76/0xd0 kernel/softirq.c:523
 </IRQ>
 <TASK>
 __local_bh_enable_ip+0xf8/0x130 kernel/softirq.c:450
 spin_unlock_bh include/linux/spinlock.h:395 [inline]
 batadv_tt_local_purge+0x2a7/0x340 net/batman-adv/translation-table.c:1315
 batadv_tt_purge+0x35/0x9e0 net/batman-adv/translation-table.c:3509
 process_one_work kernel/workqueue.c:3276 [inline]
 process_scheduled_works+0xb6e/0x18c0 kernel/workqueue.c:3359
 rescuer_thread+0x827/0x1130 kernel/workqueue.c:3583
 kthread+0x388/0x470 kernel/kthread.c:436
 ret_from_fork+0x51e/0xb90 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
 </TASK>


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue
  2026-04-03 17:50 [syzbot] [kernel?] INFO: rcu detected stall in kill syzbot
@ 2026-04-05  1:21 ` syzbot
  2026-04-05  2:19 ` Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue to fix RCU stall syzbot
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: syzbot @ 2026-04-05  1:21 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ath9k: defer reg_in URB resubmission to workqueue
Author: kartikey406@gmail.com

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master

ath9k_hif_usb_reg_in_cb() is a URB completion callback that
runs in softirq context via dummy_hcd's hrtimer which is
registered with HRTIMER_MODE_REL_SOFT.

Calling usb_submit_urb() directly from this softirq context
triggers a long synchronous chain:

  dummy_urb_enqueue()
    hrtimer_start(HRTIMER_MODE_REL_SOFT)
      dummy_timer()
        __usb_hcd_giveback_urb()
          ath9k_hif_usb_reg_in_cb()
            usb_submit_urb()  <- back to start

This keeps CPU busy in softirq context indefinitely, starving
the rcu_preempt kthread and causing an RCU stall:

  rcu: rcu_preempt kthread starved for 3053 jiffies!
  rcu: Unless rcu_preempt kthread gets sufficient CPU time,
       OOM is now expected behavior.

Fix this by deferring URB resubmission to a workqueue via
schedule_work(), allowing the softirq to exit quickly and
giving rcu_preempt kthread sufficient CPU time to process
the grace period.

Reported-by: syzbot+9b95da55ba5146a60734@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9b95da55ba5146a60734
Link: https://syzkaller.appspot.com/bug?extid=9b95da55ba5146a60734
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 drivers/net/wireless/ath/ath9k/hif_usb.c | 38 +++++++++++++++++++-----
 drivers/net/wireless/ath/ath9k/hif_usb.h |  2 ++
 2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 8533b88974b2..38c0cabe52bf 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -731,12 +731,38 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb)
 	kfree(rx_buf);
 }
 
+static void ath9k_hif_usb_reg_in_resubmit(struct work_struct *work)
+{
+	struct rx_buf *rx_buf = container_of(work,
+					     struct rx_buf,
+					     work);
+	struct hif_device_usb *hif_dev = rx_buf->hif_dev;
+	struct urb *urb = rx_buf->urb;
+	int ret;
+
+	if (!hif_dev || !urb)
+		goto free_rx_buf;
+
+	usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
+	ret = usb_submit_urb(urb, GFP_KERNEL);
+	if (ret) {
+		usb_unanchor_urb(urb);
+		goto free_skb;
+	}
+	return;
+
+free_skb:
+	kfree_skb(rx_buf->skb);
+free_rx_buf:
+	kfree(rx_buf);
+	urb->context = NULL;
+}
+
 static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 {
 	struct rx_buf *rx_buf = urb->context;
 	struct hif_device_usb *hif_dev = rx_buf->hif_dev;
 	struct sk_buff *skb = rx_buf->skb;
-	int ret;
 
 	if (!skb)
 		return;
@@ -786,13 +812,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 	}
 
 resubmit:
-	usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret) {
-		usb_unanchor_urb(urb);
-		goto free_skb;
-	}
-
+	rx_buf->urb = urb;
+	INIT_WORK(&rx_buf->work, ath9k_hif_usb_reg_in_resubmit);
+	schedule_work(&rx_buf->work);
 	return;
 free_skb:
 	kfree_skb(skb);
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index b3e66b0485a5..7c2a8d2c1cca 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -89,6 +89,8 @@ struct tx_buf {
 struct rx_buf {
 	struct sk_buff *skb;
 	struct hif_device_usb *hif_dev;
+	struct urb *urb;
+	struct work_struct work;
 };
 
 #define HIF_USB_TX_STOP  BIT(0)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue to fix RCU stall
  2026-04-03 17:50 [syzbot] [kernel?] INFO: rcu detected stall in kill syzbot
  2026-04-05  1:21 ` Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue syzbot
@ 2026-04-05  2:19 ` syzbot
  2026-04-05  4:41 ` syzbot
  2026-04-05  5:18 ` syzbot
  3 siblings, 0 replies; 5+ messages in thread
From: syzbot @ 2026-04-05  2:19 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ath9k: defer reg_in URB resubmission to workqueue to fix RCU stall
Author: kartikey406@gmail.com

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master


ath9k_hif_usb_reg_in_cb() is a URB completion callback that
runs in softirq context via dummy_hcd's hrtimer which is
registered with HRTIMER_MODE_REL_SOFT.

Calling usb_submit_urb() directly from this softirq context
triggers a long synchronous chain:

  dummy_urb_enqueue()
    hrtimer_start(HRTIMER_MODE_REL_SOFT)
      dummy_timer()
        __usb_hcd_giveback_urb()
          ath9k_hif_usb_reg_in_cb()
            usb_submit_urb()  <- back to start

This keeps the CPU busy in softirq context indefinitely,
starving the rcu_preempt kthread and causing an RCU stall:

  rcu: rcu_preempt kthread starved for 3053 jiffies!
  rcu: Unless rcu_preempt kthread gets sufficient CPU time,
       OOM is now expected behavior.

Fix this by introducing a small per-resubmission wrapper
struct (reg_in_work) that is freshly allocated on each URB
completion and carries its own work_struct. The resubmission
is then deferred to the system workqueue via schedule_work(),
allowing the softirq to exit quickly.

Using a fresh wrapper per completion avoids the races that
would arise from reusing a single embedded work_struct:
  - INIT_WORK() is called on a newly allocated struct so
    there is no risk of reinitialising a work item that is
    still queued or running.
  - schedule_work() always returns true so no resubmission
    is silently dropped.
  - usb_get_urb() is called before schedule_work() and
    usb_put_urb() is called in the worker, ensuring the URB
    remains valid for the lifetime of the work item.

On resubmission failure in the worker the original error
path is preserved: the skb and rx_buf are freed and
urb->context is set to NULL, matching the behaviour of the
original goto free_skb path.

Reported-by: syzbot+9b95da55ba5146a60734@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9b95da55ba5146a60734
Link: https://syzkaller.appspot.com/bug?extid=9b95da55ba5146a60734
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 drivers/net/wireless/ath/ath9k/hif_usb.c | 53 ++++++++++++++++++++----
 1 file changed, 45 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 8533b88974b2..3ce598167731 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -731,12 +731,43 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb)
 	kfree(rx_buf);
 }
 
+struct reg_in_work {
+	struct urb		*urb;
+	struct hif_device_usb	*hif_dev;
+	struct work_struct	work;
+};
+
+static void ath9k_hif_usb_reg_in_resubmit(struct work_struct *work)
+{
+	struct reg_in_work *rw = container_of(work,
+					      struct reg_in_work,
+					      work);
+	struct urb *urb = rw->urb;
+	struct rx_buf *rx_buf = urb->context;
+
+	int ret;
+
+	usb_anchor_urb(rw->urb, &rw->hif_dev->reg_in_submitted);
+	ret = usb_submit_urb(rw->urb, GFP_KERNEL);
+	usb_put_urb(rw->urb);
+
+	if (ret) {
+		usb_unanchor_urb(rw->urb);
+		if (rx_buf) {
+			kfree_skb(rx_buf->skb);
+			kfree(rx_buf);
+			urb->context = NULL;
+		}
+	}
+
+	kfree(rw);
+}
+
 static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 {
 	struct rx_buf *rx_buf = urb->context;
 	struct hif_device_usb *hif_dev = rx_buf->hif_dev;
 	struct sk_buff *skb = rx_buf->skb;
-	int ret;
 
 	if (!skb)
 		return;
@@ -786,14 +817,20 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 	}
 
 resubmit:
-	usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret) {
-		usb_unanchor_urb(urb);
-		goto free_skb;
+	{
+		struct reg_in_work *rw;
+
+		rw = kmalloc_obj(*rw, GFP_ATOMIC);
+		if (!rw)
+			goto free_skb;
+
+		rw->urb = urb;
+		rw->hif_dev = hif_dev;
+		usb_get_urb(urb);
+		INIT_WORK(&rw->work, ath9k_hif_usb_reg_in_resubmit);
+		schedule_work(&rw->work);
+		return;
 	}
-
-	return;
 free_skb:
 	kfree_skb(skb);
 free_rx_buf:
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue to fix RCU stall
  2026-04-03 17:50 [syzbot] [kernel?] INFO: rcu detected stall in kill syzbot
  2026-04-05  1:21 ` Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue syzbot
  2026-04-05  2:19 ` Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue to fix RCU stall syzbot
@ 2026-04-05  4:41 ` syzbot
  2026-04-05  5:18 ` syzbot
  3 siblings, 0 replies; 5+ messages in thread
From: syzbot @ 2026-04-05  4:41 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ath9k: defer reg_in URB resubmission to workqueue to fix RCU stall
Author: kartikey406@gmail.com

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master


ath9k_hif_usb_reg_in_cb() is a URB completion callback that
runs in softirq context via dummy_hcd's hrtimer which is
registered with HRTIMER_MODE_REL_SOFT.

Calling usb_submit_urb() directly from this softirq context
triggers a long synchronous chain:

  dummy_urb_enqueue()
    hrtimer_start(HRTIMER_MODE_REL_SOFT)
      dummy_timer()
        __usb_hcd_giveback_urb()
          ath9k_hif_usb_reg_in_cb()
            usb_submit_urb()  <- back to start

This keeps the CPU busy in softirq context indefinitely,
starving the rcu_preempt kthread and causing an RCU stall:

  rcu: rcu_preempt kthread starved for 3053 jiffies!
  rcu: Unless rcu_preempt kthread gets sufficient CPU time,
       OOM is now expected behavior.

Fix this by introducing a small per-resubmission wrapper
struct (reg_in_work) that is freshly allocated on each URB
completion and carries its own work_struct. The resubmission
is then deferred to the system workqueue via schedule_work(),
allowing the softirq to exit quickly.

Using a fresh wrapper per completion avoids races that would
arise from reusing a single embedded work_struct:
  - INIT_WORK() is called on a newly allocated struct so
    there is no risk of reinitialising a work item that is
    still queued or running.
  - schedule_work() on a fresh work_struct always succeeds
    so no resubmission is ever silently dropped.
  - usb_get_urb() is called before schedule_work() and
    usb_put_urb() is called last in the worker after all
    URB accesses are complete, ensuring the URB remains
    valid for the entire lifetime of the work item.

On resubmission failure in the worker the original error
path is preserved: skb and rx_buf are freed and
urb->context is set to NULL before dropping the URB
reference, matching the behaviour of the original
goto free_skb path.

Reported-by: syzbot+9b95da55ba5146a60734@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9b95da55ba5146a60734
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 drivers/net/wireless/ath/ath9k/hif_usb.c | 53 ++++++++++++++++++++----
 1 file changed, 45 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 8533b88974b2..0f9536b2d0a2 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -731,12 +731,43 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb)
 	kfree(rx_buf);
 }
 
+struct reg_in_work {
+	struct urb		*urb;
+	struct hif_device_usb	*hif_dev;
+	struct work_struct	work;
+};
+
+static void ath9k_hif_usb_reg_in_resubmit(struct work_struct *work)
+{
+	struct reg_in_work *rw = container_of(work,
+					      struct reg_in_work,
+					      work);
+	struct urb *urb = rw->urb;
+	struct rx_buf *rx_buf = urb->context;
+
+	int ret;
+
+	usb_anchor_urb(rw->urb, &rw->hif_dev->reg_in_submitted);
+	ret = usb_submit_urb(rw->urb, GFP_KERNEL);
+
+	if (ret) {
+		usb_unanchor_urb(rw->urb);
+		if (rx_buf) {
+			kfree_skb(rx_buf->skb);
+			kfree(rx_buf);
+			urb->context = NULL;
+		}
+	}
+
+	usb_put_urb(urb);
+	kfree(rw);
+}
+
 static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 {
 	struct rx_buf *rx_buf = urb->context;
 	struct hif_device_usb *hif_dev = rx_buf->hif_dev;
 	struct sk_buff *skb = rx_buf->skb;
-	int ret;
 
 	if (!skb)
 		return;
@@ -786,14 +817,20 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 	}
 
 resubmit:
-	usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret) {
-		usb_unanchor_urb(urb);
-		goto free_skb;
+	{
+		struct reg_in_work *rw;
+
+		rw = kmalloc_obj(*rw, GFP_ATOMIC);
+		if (!rw)
+			goto free_skb;
+
+		rw->urb = urb;
+		rw->hif_dev = hif_dev;
+		usb_get_urb(urb);
+		INIT_WORK(&rw->work, ath9k_hif_usb_reg_in_resubmit);
+		schedule_work(&rw->work);
+		return;
 	}
-
-	return;
 free_skb:
 	kfree_skb(skb);
 free_rx_buf:
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue to fix RCU stall
  2026-04-03 17:50 [syzbot] [kernel?] INFO: rcu detected stall in kill syzbot
                   ` (2 preceding siblings ...)
  2026-04-05  4:41 ` syzbot
@ 2026-04-05  5:18 ` syzbot
  3 siblings, 0 replies; 5+ messages in thread
From: syzbot @ 2026-04-05  5:18 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: [PATCH] ath9k: defer reg_in URB resubmission to workqueue to fix RCU stall
Author: kartikey406@gmail.com

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master


ath9k_hif_usb_reg_in_cb() is a URB completion callback that
runs in softirq context via dummy_hcd's hrtimer which is
registered with HRTIMER_MODE_REL_SOFT.

Calling usb_submit_urb() directly from this softirq context
triggers a long synchronous chain:

  dummy_urb_enqueue()
    hrtimer_start(HRTIMER_MODE_REL_SOFT)
      dummy_timer()
        __usb_hcd_giveback_urb()
          ath9k_hif_usb_reg_in_cb()
            usb_submit_urb()  <- back to start

This keeps the CPU busy in softirq context indefinitely,
starving the rcu_preempt kthread and causing an RCU stall:

  rcu: rcu_preempt kthread starved for 3053 jiffies!
  rcu: Unless rcu_preempt kthread gets sufficient CPU time,
       OOM is now expected behavior.

Fix this by introducing a small per-resubmission wrapper
struct (reg_in_work) that is freshly allocated on each URB
completion and carries its own work_struct. The resubmission
is deferred to a dedicated ordered workqueue (reg_in_wq)
via queue_work(), allowing the softirq to exit quickly.

Using a fresh wrapper per completion avoids races that would
arise from reusing a single embedded work_struct:
  - INIT_WORK() is called on a newly allocated struct so
    there is no risk of reinitialising a work item that is
    still queued or running.
  - queue_work() on a fresh work_struct always succeeds so
    no resubmission is ever silently dropped.
  - usb_get_urb() is called before queue_work() and
    usb_put_urb() is called last in the worker after all
    URB accesses are complete, ensuring the URB remains
    valid for the entire lifetime of the work item.

A dedicated ordered workqueue is used instead of the system
workqueue to allow proper synchronization on disconnect.
destroy_workqueue() in ath9k_hif_usb_dealloc_reg_in_urbs()
drains all pending resubmissions before hif_dev is freed,
preventing use-after-free when the device is disconnected
while work items are still pending.

On resubmission failure in the worker the original error
path is preserved: skb and rx_buf are freed and
urb->context is set to NULL before dropping the URB
reference, matching the behaviour of the original
goto free_skb path.

Reported-by: syzbot+9b95da55ba5146a60734@syzkaller.appspotmail.com
Link: https://syzkaller.appspot.com/bug?extid=9b95da55ba5146a60734
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
 drivers/net/wireless/ath/ath9k/hif_usb.c | 58 ++++++++++++++++++++----
 drivers/net/wireless/ath/ath9k/hif_usb.h |  1 +
 2 files changed, 51 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 8533b88974b2..370764681749 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -731,12 +731,43 @@ static void ath9k_hif_usb_rx_cb(struct urb *urb)
 	kfree(rx_buf);
 }
 
+struct reg_in_work {
+	struct urb		*urb;
+	struct hif_device_usb	*hif_dev;
+	struct work_struct	work;
+};
+
+static void ath9k_hif_usb_reg_in_resubmit(struct work_struct *work)
+{
+	struct reg_in_work *rw = container_of(work,
+					      struct reg_in_work,
+					      work);
+	struct urb *urb = rw->urb;
+	struct rx_buf *rx_buf = urb->context;
+
+	int ret;
+
+	usb_anchor_urb(rw->urb, &rw->hif_dev->reg_in_submitted);
+	ret = usb_submit_urb(rw->urb, GFP_KERNEL);
+
+	if (ret) {
+		usb_unanchor_urb(rw->urb);
+		if (rx_buf) {
+			kfree_skb(rx_buf->skb);
+			kfree(rx_buf);
+			urb->context = NULL;
+		}
+	}
+
+	usb_put_urb(urb);
+	kfree(rw);
+}
+
 static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 {
 	struct rx_buf *rx_buf = urb->context;
 	struct hif_device_usb *hif_dev = rx_buf->hif_dev;
 	struct sk_buff *skb = rx_buf->skb;
-	int ret;
 
 	if (!skb)
 		return;
@@ -786,14 +817,20 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 	}
 
 resubmit:
-	usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
-	ret = usb_submit_urb(urb, GFP_ATOMIC);
-	if (ret) {
-		usb_unanchor_urb(urb);
-		goto free_skb;
+	{
+		struct reg_in_work *rw;
+
+		rw = kmalloc_obj(*rw, GFP_ATOMIC);
+		if (!rw)
+			goto free_skb;
+
+		rw->urb = urb;
+		rw->hif_dev = hif_dev;
+		usb_get_urb(urb);
+		INIT_WORK(&rw->work, ath9k_hif_usb_reg_in_resubmit);
+		queue_work(hif_dev->reg_in_wq, &rw->work);
+		return;
 	}
-
-	return;
 free_skb:
 	kfree_skb(skb);
 free_rx_buf:
@@ -959,6 +996,8 @@ static int ath9k_hif_usb_alloc_rx_urbs(struct hif_device_usb *hif_dev)
 static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev)
 {
 	usb_kill_anchored_urbs(&hif_dev->reg_in_submitted);
+	if (hif_dev->reg_in_wq)
+		destroy_workqueue(hif_dev->reg_in_wq);
 }
 
 static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
@@ -969,6 +1008,9 @@ static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
 	int i, ret;
 
 	init_usb_anchor(&hif_dev->reg_in_submitted);
+	hif_dev->reg_in_wq = alloc_ordered_workqueue("ath9k_reg_in", 0);
+	if (!hif_dev->reg_in_wq)
+		return -ENOMEM;
 
 	for (i = 0; i < MAX_REG_IN_URB_NUM; i++) {
 
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index b3e66b0485a5..38f17a12fd5f 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -124,6 +124,7 @@ struct hif_device_usb {
 	struct usb_anchor regout_submitted;
 	struct usb_anchor rx_submitted;
 	struct usb_anchor reg_in_submitted;
+	struct workqueue_struct *reg_in_wq;
 	struct usb_anchor mgmt_submitted;
 	struct sk_buff *remain_skb;
 	char fw_name[64];
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-04-05  5:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-03 17:50 [syzbot] [kernel?] INFO: rcu detected stall in kill syzbot
2026-04-05  1:21 ` Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue syzbot
2026-04-05  2:19 ` Forwarded: [PATCH] ath9k: defer reg_in URB resubmission to workqueue to fix RCU stall syzbot
2026-04-05  4:41 ` syzbot
2026-04-05  5:18 ` syzbot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox