DF-5125 / fix.diff
--- 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: |