⬢ DragonFlyBSD Kernel Audit
DF-5074 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/acpica/acpi_acad.c
+++ b/sys/dev/acpica/acpi_acad.c
@@ -62,10 +62,11 @@
 
 struct	acpi_acad_softc {
     int status;
+    struct sysctl_oid *acline_oid;
 };
 
 static void	acpi_acad_get_status(void *);
 static void	acpi_acad_notify_handler(ACPI_HANDLE, UINT32, void *);
+static int	acpi_acad_detach(device_t);
 static int	acpi_acad_probe(device_t);
 static int	acpi_acad_ioctl(u_long, caddr_t, void *);
 static int	acpi_acad_sysctl(SYSCTL_HANDLER_ARGS);
@@ -74,6 +75,7 @@ static device_method_t acpi_acad_methods[] = {
     /* Device interface */
     DEVMETHOD(device_probe,	acpi_acad_probe),
     DEVMETHOD(device_attach,	acpi_acad_attach),
+    DEVMETHOD(device_detach,	acpi_acad_detach),
 
     DEVMETHOD_END
 };
@@ -176,8 +178,10 @@ acpi_acad_attach(device_t dev)
     ACPI_SERIAL_INIT(acad);
 
     if (device_get_unit(dev) == 0) {
 	acpi_sc = acpi_device_get_parent_softc(dev);
-	SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx,
+	sc->acline_oid = SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx,
 			SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
 			OID_AUTO, "acline", CTLTYPE_INT | CTLFLAG_RD,
 			&sc->status, 0, acpi_acad_sysctl, "I", "");
@@ -205,6 +209,28 @@ acpi_acad_attach(device_t dev)
     return (0);
 }
 
+static int
+acpi_acad_detach(device_t dev)
+{
+    struct acpi_acad_softc *sc;
+
+    sc = device_get_softc(dev);
+
+    /* Remove both the system and device notify handlers installed at
+     * attach (context = dev); ACPICA's AcpiRemoveNotifyHandler drains
+     * deferred notify work itself (evxface.c calls AcpiOsWaitEventsComplete
+     * while holding the handler removal lock, so an in-flight
+     * acpi_acad_notify_handler cannot queue new acpi_acad_get_status work
+     * behind our back).
+     */
+    AcpiRemoveNotifyHandler(acpi_get_handle(dev), ACPI_ALL_NOTIFY,
+	acpi_acad_notify_handler);
+
+    acpi_deregister_ioctl(ACPIIO_ACAD_GET_STATUS, acpi_acad_ioctl);
+
+    if (sc->acline_oid != NULL)
+	sysctl_remove_oid(sc->acline_oid, 1, 0);
+
+    return (0);
+}
+
 static int
 acpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg)
 {