⬢ DragonFlyBSD Kernel Audit
DF-5006 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/acpica/acpi_cpu.c b/sys/dev/acpica/acpi_cpu.c
index 1111111..2222222 100644
--- a/sys/dev/acpica/acpi_cpu.c
+++ b/sys/dev/acpica/acpi_cpu.c
@@ -48,6 +48,7 @@ static int	acpi_cpu_probe(device_t dev);
 static int	acpi_cpu_attach(device_t dev);
 static struct resource_list *
 		acpi_cpu_get_rlist(device_t, device_t);
+static int	acpi_cpu_detach(device_t dev);
 static struct resource *
 		acpi_cpu_alloc_resource(device_t, device_t,
 			int, int *, u_long, u_long, u_long, u_int, int);
@@ -64,7 +65,7 @@ static device_method_t acpi_cpu_methods[] = {
     /* Device interface */
     DEVMETHOD(device_probe,		acpi_cpu_probe),
     DEVMETHOD(device_attach,		acpi_cpu_attach),
-    DEVMETHOD(device_detach,		bus_generic_detach),
+    DEVMETHOD(device_detach,		acpi_cpu_detach),
     DEVMETHOD(device_shutdown,		bus_generic_shutdown),
     DEVMETHOD(device_suspend,		bus_generic_suspend),
     DEVMETHOD(device_resume,		bus_generic_resume),
@@ -235,14 +236,19 @@ acpi_cpu_attach(device_t dev)
 
     child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1);
     if (child == NULL)
-	return ENXIO;
+	goto fail;
     acpi_set_handle(child, handle);
     acpi_set_magic(child, cpu_id);
     sc->cpu_cst = child;
 
     child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1);
     if (child == NULL)
-	return ENXIO;
+	goto fail_cst;
     acpi_set_handle(child, handle);
     acpi_set_magic(child, cpu_id);
     sc->cpu_pst = child;
@@ -254,6 +260,33 @@ acpi_cpu_attach(device_t dev)
     AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc);
 
     return 0;
+
+fail_cst:
+    device_delete_child(dev, sc->cpu_cst);
+fail:
+    sysctl_ctx_free(&sc->pcpu_sysctl_ctx);
+    if (sc->glob_sysctl_tree != NULL)		/* only cpu_id == 0 created it */
+	sysctl_ctx_free(&sc->glob_sysctl_ctx);
+    sensordev_deinstall(&sc->cpu_sensdev);
+    return ENXIO;
+}
+
+static int
+acpi_cpu_detach(device_t dev)
+{
+    struct acpi_cpu_softc *sc = device_get_softc(dev);
+    int error;
+
+    /* Stop ACPI notifies first: they call into the children through
+     * sc->cpu_cst_notify / sc->cpu_pst_notify, which the children set at
+     * attach and never clear. */
+    AcpiRemoveNotifyHandler(acpi_get_handle(dev), ACPI_DEVICE_NOTIFY,
+	acpi_cpu_notify);
+
+    /* Detach children (cpu_cst / cpu_pst); they added sysctl handlers to
+     * our contexts, so free the contexts only after they are gone. */
+    error = bus_generic_detach(dev);
+    if (error)
+	return (error);
+
+    sysctl_ctx_free(&sc->pcpu_sysctl_ctx);
+    if (sc->glob_sysctl_tree != NULL)
+	sysctl_ctx_free(&sc->glob_sysctl_ctx);
+    sensordev_deinstall(&sc->cpu_sensdev);
+
+    return (0);
 }
 
 /*