git: 0d022baa047a - main - LinuxKPI: Run irq_work callbacks under RCU protection

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Fri, 11 Sep 2026 15:50:55 UTC
The branch main has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=0d022baa047aea6499e394d2cd8d097820ecf486

commit 0d022baa047aea6499e394d2cd8d097820ecf486
Author:     JustAnotherHumanBeing <oleglelchuk@gmail.com>
AuthorDate: 2026-09-11 15:49:23 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2026-09-11 15:49:23 +0000

    LinuxKPI: Run irq_work callbacks under RCU protection
    
    Linux executes irq_work callbacks from an interrupt context that
    provides implicit RCU read-side protection. LinuxKPI dispatches these
    callbacks through a taskqueue, so provide equivalent protection
    explicitly.
    
    This prevents an RCU grace period from completing while an irq_work
    callback is still using an RCU-protected object.
    
    Suggested by:   wulf
    Tested by:      JustAnotherHumanBeing
    Signed-off-by:  JustAnotherHumanBeing <oleglelchuk@gmail.com>
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2385
---
 sys/compat/linuxkpi/common/include/linux/irq_work.h | 2 ++
 sys/compat/linuxkpi/common/src/linux_work.c         | 3 +++
 2 files changed, 5 insertions(+)

diff --git a/sys/compat/linuxkpi/common/include/linux/irq_work.h b/sys/compat/linuxkpi/common/include/linux/irq_work.h
index 7c4019bc0242..120df40d0c0f 100644
--- a/sys/compat/linuxkpi/common/include/linux/irq_work.h
+++ b/sys/compat/linuxkpi/common/include/linux/irq_work.h
@@ -33,6 +33,7 @@
 #include <sys/taskqueue.h>
 
 #include <linux/llist.h>
+#include <linux/rcupdate.h>
 #include <linux/workqueue.h>
 
 #define	LKPI_IRQ_WORK_STD_TQ	system_wq->taskqueue
@@ -85,6 +86,7 @@ static inline void
 irq_work_sync(struct irq_work *irqw)
 {
 	taskqueue_drain(LKPI_IRQ_WORK_TQ, &irqw->irq_task);
+	synchronize_rcu();
 }
 
 #endif /* _LINUXKPI_LINUX_IRQ_WORK_H_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_work.c b/sys/compat/linuxkpi/common/src/linux_work.c
index bb25893d9c71..02dfb35d9fd0 100644
--- a/sys/compat/linuxkpi/common/src/linux_work.c
+++ b/sys/compat/linuxkpi/common/src/linux_work.c
@@ -757,7 +757,9 @@ linux_irq_work_fn(void *context, int pending)
 {
 	struct irq_work *irqw = context;
 
+	rcu_read_lock();
 	irqw->func(irqw);
+	rcu_read_unlock();
 }
 
 static void
@@ -791,6 +793,7 @@ SYSINIT(linux_irq_work_init, SI_SUB_TASKQ, SI_ORDER_SECOND,
 static void
 linux_irq_work_uninit(void *arg)
 {
+	/* taskqueue_drain_all() executes synchronize_rcu() implicitly */
 	taskqueue_drain_all(linux_irq_work_tq);
 	taskqueue_free(linux_irq_work_tq);
 }