⬢ DragonFlyBSD Kernel Audit
DF-4173 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/iir/iir.c
+++ b/sys/dev/raid/iir/iir.c
@@ -1489,9 +1489,6 @@
     kprintf("iir%d: Flushing all Host Drives. Please wait ...  ",
            gdt->sc_hanum);
 
-    /* allocate ucmd buffer */
-    ucmd = kmalloc(sizeof(gdt_ucmd_t), M_GDTBUF, M_INTWAIT | M_ZERO);
-
     /* wait for pending IOs */
     crit_enter();
     gdt->sc_state = GDT_SHUTDOWN;
@@ -1502,6 +1499,9 @@
     /* flush */
     for (i = 0; i < GDT_MAX_HDRIVES; ++i) {
         if (gdt->sc_hdr[i].hd_present) {
+            /* one ucmd per drive: a still-in-flight ucmd must never be
+               requeued or freed while the controller owns it */
+            ucmd = kmalloc(sizeof(gdt_ucmd_t), M_GDTBUF, M_INTWAIT | M_ZERO);
             ucmd->service = GDT_CACHESERVICE;
             ucmd->OpCode = GDT_FLUSH;
             ucmd->u.cache.DeviceNo = i;
@@ -1512,10 +1512,13 @@
             gdt_next(gdt);
             if (!ucmd->complete_flag)
                 (void) tsleep((void *)ucmd, PCATCH, "iirshw", 10*hz);
+            if (ucmd->complete_flag)
+                kfree(ucmd, M_GDTBUF);
+            /* else: still referenced by an in-flight gccb -- leaking at
+               shutdown is safe, freeing is not */
         }
     }
 
-    kfree(ucmd, M_DEVBUF);
     kprintf("Done.\n");
 }