⬢ DragonFlyBSD Kernel Audit
DF-5125 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/include/linux/rcupdate.h	2026-09-30 03:22:04.690366500 +0000
+++ b/sys/dev/drm/include/linux/rcupdate.h	2026-09-30 03:22:24.678109972 +0000
@@ -43,15 +43,20 @@
 
 #include <linux/rcutree.h>
 
+extern void rcu_read_acquire(void);
+extern void rcu_read_release(void);
+
 static inline void
 rcu_read_lock(void)
 {
 	preempt_disable();
+	rcu_read_acquire();
 }
 
 static inline void
 rcu_read_unlock(void)
 {
+	rcu_read_release();
 	preempt_enable();
 }
 
@@ -91,7 +96,7 @@
 
 #define rcu_pointer_handoff(p)	(p)
 
-#define synchronize_rcu()
+extern void synchronize_rcu(void);
 #define cond_synchronize_rcu(x)  cpu_mfence()
 #define get_state_synchronize_rcu()	0
 
--- a/sys/dev/drm/linux_rcu.c	2026-09-30 03:22:04.690366500 +0000
+++ b/sys/dev/drm/linux_rcu.c	2026-09-30 03:29:07.768934319 +0000
@@ -38,6 +38,7 @@
 #include <sys/types.h>
 #include <sys/errno.h>
 #include <sys/kernel.h>
+#include <sys/systm.h>
 #include <sys/spinlock.h>
 #include <sys/spinlock2.h>
 #include <linux/gfp.h>
@@ -66,6 +67,50 @@
 static rcu_pcpu_t *rcupcpu;
 
 /*
+ * FIX (DF-5125/DF-5126): the shim previously had NO grace-period
+ * protocol at all -- rcu_read_lock() was a pure compiler fence and
+ * synchronize_rcu() compiled to nothing, so reclamation raced live
+ * readers.  Account read-side critical sections with a global nesting
+ * counter and (a) defer delay-line reclamation while any reader is
+ * inside a critical section, (b) give synchronize_rcu() a real body
+ * that waits out both the delay line and in-flight readers.
+ *
+ * This is deliberately conservative: a reader that begins after the
+ * callback was queued also delays it.  It is, however, sound, which
+ * the previous implementation was not.
+ */
+static volatile u_int rcu_readers;
+
+void
+rcu_read_acquire(void)
+{
+	atomic_add_int(&rcu_readers, 1);
+}
+
+void
+rcu_read_release(void)
+{
+	atomic_add_int(&rcu_readers, -1);
+}
+
+void
+synchronize_rcu(void)
+{
+	int dummy = 0;
+	int elapsed = 0;
+
+	/*
+	 * Wait at least one full delay period (the ring reclaims at
+	 * >= 1s after queueing, checked every hz/10), and until no
+	 * read-side critical section is in flight.
+	 */
+	while (elapsed < 2 * hz || rcu_readers != 0) {
+		tsleep(&dummy, 0, "lrcus", hz / 10);
+		elapsed += hz / 10;
+	}
+}
+
+/*
  * Timer callout (pcpu)
  */
 static void
@@ -81,6 +126,8 @@
 		delta = ticks - elm->ticks;	/* 2s compl underflow */
 		if (delta < hz)
 			break;
+		if (rcu_readers != 0)		/* FIX: defer while readers */
+			break;
 
 		switch(elm->type) {
 		case RCU_NULL: