--- 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"); }