DF-4685 / fix.diff
diff --git a/sys/dev/drm/include/linux/rcutree.h b/sys/dev/drm/include/linux/rcutree.h --- a/sys/dev/drm/include/linux/rcutree.h +++ b/sys/dev/drm/include/linux/rcutree.h @@ -27,7 +27,7 @@ #ifndef _LINUX_RCUTREE_H_ #define _LINUX_RCUTREE_H_ -static inline void rcu_barrier(void) {} +extern void rcu_barrier(void); /* implemented in linux_rcu.c (drain the delay lines) */ static inline void synchronize_rcu_expedited(void) diff --git a/sys/dev/drm/linux_rcu.c b/sys/dev/drm/linux_rcu.c --- a/sys/dev/drm/linux_rcu.c +++ b/sys/dev/drm/linux_rcu.c @@ -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> @@ -209,6 +210,36 @@ call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *)) crit_exit(); } +/* + * rcu_barrier: wait until every per-cpu delay line has fully drained. + * + * This port has no read-side grace tracking (rcu_read_lock() is only + * preempt_disable()), so a "barrier" can only mean "all previously + * queued callbacks have executed". That is exactly what callers such + * as amdgpu_fence_slab_fini() need before module text may be unmapped: + * every pending call_rcu()/__kfree_rcu() callback targeting the module + * must have run. Reading other cpus' e/s indexes unlocked is safe here: + * we only need a conservative drain check and we re-check in a loop. + */ +void +rcu_barrier(void) +{ + int i; + int more; + + if (rcupcpu == NULL) + return; + do { + more = 0; + for (i = 0; i < ncpus; ++i) { + if (rcupcpu[i].e != rcupcpu[i].s) + more = 1; + } + if (more) + tsleep(&rcupcpu, 0, "rcubr", hz / 10); + } while (more); +} + static int init_rcu(void *dummy __unused) { |