⬢ DragonFlyBSD Kernel Audit
DF-4888 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/iir/iir_pci.c
+++ b/sys/dev/raid/iir/iir_pci.c
@@ -178,7 +178,7 @@ iir_pci_attach(device_t dev)
 {
     struct gdt_softc    *gdt;
     struct resource     *io = NULL, *irq = NULL;
-    int                 retries, rid, error = 0;
+    int                 retries, io_rid, rid, error = 0;
     void                *ih;
     u_int8_t            protocol;
 
@@ -190,6 +190,7 @@ iir_pci_attach(device_t dev)
         error = ENOMEM;
         goto err;
     }
+    io_rid = rid;
 
     /* get IRQ */
     rid = 0;
@@ -336,6 +337,27 @@ iir_pci_attach(device_t dev)
     error = bus_setup_intr(dev, irq, 0, iir_intr, gdt, &ih, NULL);
     if (error) {
         device_printf(dev, "Unable to register interrupt handler\n");
+        /*
+         * Undo everything iir_init()/iir_attach() set up: XPT SIMs,
+         * the shutdown handler, the control device and all DMA state.
+         * Buses whose xpt_create_path() failed were already torn down
+         * inside iir_attach() itself, so only buses with a live path
+         * are deregistered here.
+         */
+        if (gdt->sc_shutdown_eh != NULL) {
+            EVENTHANDLER_DEREGISTER(shutdown_post_sync, gdt->sc_shutdown_eh);
+            gdt->sc_shutdown_eh = NULL;
+        }
+        for (rid = 0; rid < GDT_MAXBUS; rid++) {
+            if (gdt->paths[rid] != NULL) {
+                xpt_free_path(gdt->paths[rid]);
+                gdt->paths[rid] = NULL;
+                xpt_bus_deregister(cam_sim_path(gdt->sims[rid]));
+                cam_sim_free(gdt->sims[rid]);
+                gdt->sims[rid] = NULL;
+            }
+        }
+        iir_free(gdt);
         error = ENXIO;
         goto err;
     }
@@ -346,10 +368,8 @@ iir_pci_attach(device_t dev)
 err:
     if (irq)
         bus_release_resource( dev, SYS_RES_IRQ, 0, irq );
-/*
     if (io)
-        bus_release_resource( dev, SYS_RES_MEMORY, rid, io );
-*/
+        bus_release_resource( dev, SYS_RES_MEMORY, io_rid, io );
     return (error);
 }
 
--- a/sys/dev/raid/iir/iir.h
+++ b/sys/dev/raid/iir/iir.h
@@ -659,6 +659,7 @@ struct gdt_softc {
 
     struct cam_sim *sims[GDT_MAXBUS];
     struct cam_path *paths[GDT_MAXBUS];
+    eventhandler_tag     sc_shutdown_eh;
 
     void (*sc_copy_cmd)(struct gdt_softc *, struct gdt_ccb *);
     u_int8_t (*sc_get_status)(struct gdt_softc *);
--- a/sys/dev/raid/iir/iir.c
+++ b/sys/dev/raid/iir/iir.c
@@ -511,8 +511,9 @@ iir_attach(struct gdt_softc *gdt)
     }
     cam_simq_release(devq);
     if (i > 0)
-        EVENTHANDLER_REGISTER(shutdown_post_sync, iir_shutdown,
-                              gdt, SHUTDOWN_PRI_DRIVER);
+        gdt->sc_shutdown_eh = EVENTHANDLER_REGISTER(shutdown_post_sync,
+                                                    iir_shutdown,
+                                                    gdt, SHUTDOWN_PRI_DRIVER);
     gdt->sc_state = GDT_NORMAL;
 }