DF-4276 / fix.diff
--- a/sys/dev/pccard/pccbb/pccbb.c +++ b/sys/dev/pccard/pccbb/pccbb.c @@ -279,12 +279,31 @@ int cbb_detach(device_t brdev) { struct cbb_softc *sc = device_get_softc(brdev); int error; + /* + * Stop the slot event thread BEFORE deleting the children: the + * thread re-evaluates the socket every second and calls + * cbb_insert()/cbb_removal() -> CARD_ATTACH_CARD/CARD_DETACH_CARD/ + * exca_insert/exca_removal on sc->cbdev and sc->exca[0].pccarddev, + * which device_delete_children() frees (DF-4276). + */ + sc->flags |= CBB_KTHREAD_DONE; + if (sc->flags & CBB_KTHREAD_RUNNING) { + crit_enter(); + wakeup(&sc->generic_cv); + tsleep(sc->event_thread, 0, "cbbun", 0); + crit_exit(); + } + error = device_delete_children(brdev); if (error != 0) return (error); + /* Children are gone; make sure the thread can never reach them. */ + sc->cbdev = NULL; + sc->exca[0].pccarddev = NULL; + /* * XXX do we teardown all the ones still registered to guard against * XXX buggy client drivers? */ bus_teardown_intr(brdev, sc->irq_res, sc->intrhand); - sc->flags |= CBB_KTHREAD_DONE; - if (sc->flags & CBB_KTHREAD_RUNNING) { - crit_enter(); - wakeup(&sc->generic_cv); - tsleep(sc->event_thread, 0, "cbbun", 0); - crit_exit(); - } bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res); |