⬢ DragonFlyBSD Kernel Audit
DF-2376 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/acpica/Osd/OsdSchedule.c
+++ b/sys/dev/acpica/Osd/OsdSchedule.c
@@ -71,6 +71,9 @@
 
 static struct thread *acpi_task_td;
 struct lwkt_port acpi_afree_rport;
+static volatile int acpi_task_pending;
+
+void acpi_os_wait_events_complete(void);
 
 /*
  * Initialize the ACPI helper thread.
@@ -106,6 +109,9 @@
 	func = at->at_function;
 	func(at->at_context);
 	lwkt_replymsg(&at->at_msg, 0);
+	atomic_subtract_int(&acpi_task_pending, 1);
+	if (acpi_task_pending == 0)
+	    wakeup(&acpi_task_pending);
     }
     lwkt_reltoken(&acpi_token);
 }
@@ -139,8 +145,27 @@
     at->at_function = Function;
     at->at_context = Context;
     at->at_type = Type;
+    atomic_add_int(&acpi_task_pending, 1);
     lwkt_sendmsg(&acpi_task_td->td_msgport, &at->at_msg);
     return_ACPI_STATUS (AE_OK);
+}
+
+/*
+ * Real AcpiOsWaitEventsComplete (was a no-op "XXX TBI"): wait until
+ * every message already queued for the helper thread has been
+ * dispatched and replied, so a driver detach cannot free state a
+ * still-queued callback references (DF-2376/DF-2381/DF-2393).
+ */
+void
+acpi_os_wait_events_complete(void)
+{
+    int i;
+
+    for (i = 0; i < 120; i++) {
+	if (acpi_task_pending == 0)
+	    break;
+	tsleep(&acpi_task_pending, 0, "acpdrn", hz / 20);
+    }
 }
 
 /*
--- a/sys/contrib/dev/acpica/source/include/platform/acdragonfly.h
+++ b/sys/contrib/dev/acpica/source/include/platform/acdragonfly.h
@@ -217,7 +217,8 @@
 
 /* XXX TBI */
 #define ACPI_USE_ALTERNATE_PROTOTYPE_AcpiOsWaitEventsComplete
-#define AcpiOsWaitEventsComplete()
+void acpi_os_wait_events_complete(void);
+#define AcpiOsWaitEventsComplete() acpi_os_wait_events_complete()
 
 #define USE_NATIVE_ALLOCATE_ZEROED