⬢ DragonFlyBSD Kernel Audit
DF-4685 / fix.diff
← back to finding ↓ download raw
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)
 {