DF-5464 / icu_msiabi_livelock.c
/* * DF-5464 crasher #2 (livelock): msi_alloc(count = 0). * * With count == 0 the loop at icu_abi.c:473 * for (i = msi_start; i < IDT_HWI_VECTORS; i += count) * never advances (i += 0) and the body 'continue's forever * (icu_irqmaps[0][0].im_type is ICU_IMT_LEGACY != UNUSED on the first * iteration and i never changes) -- while lwkt_gettoken(&icu_irqmap_tok) * (icu_abi.c:463) is held. The loading thread spins forever; every * later ICU MSI path (msi_alloc/msi_release/msi_map) blocks on the token. * * Expected: kldload never returns; 'timeout' on the caller side expires * (exit status 124) while the guest stays alive (other CPUs unaffected). * * On an INVARIANTS kernel this panics at KASSERT(count > 0) * (icu_abi.c:460) instead. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/machintr.h> extern struct machintr_abi MachIntrABI_ICU; static int zone[8]; static int icu_live_modevent(module_t mod __unused, int type, void *data __unused) { int rc; switch (type) { case MOD_LOAD: kprintf("icu_msiabi_livelock: calling ICU msi_alloc(count=0, " "cpu0): expect infinite loop at icu_abi.c:473 holding " "icu_irqmap_tok -- kldload will not return\n"); rc = MachIntrABI_ICU.msi_alloc(zone, 0, 0); kprintf("icu_msiabi_livelock: returned rc=%d (unexpected on " "a production kernel)\n", rc); return 0; case MOD_UNLOAD: return 0; default: return EOPNOTSUPP; } } static moduledata_t icu_msiabi_livelock_mod = { "icu_msiabi_livelock", icu_live_modevent, NULL }; DECLARE_MODULE(icu_msiabi_livelock, icu_msiabi_livelock_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); MODULE_VERSION(icu_msiabi_livelock, 1); |