DF-1043 / fix.diff
diff --git a/sys/bus/u4b/serial/ufoma.c b/sys/bus/u4b/serial/ufoma.c --- a/sys/bus/u4b/serial/ufoma.c +++ b/sys/bus/u4b/serial/ufoma.c @@ -185,6 +185,11 @@ uint8_t sc_modetoactivate; uint8_t sc_currentmode; uint8_t sc_name[16]; + + /* sysctl OIDs — removed in ufoma_detach before sc_modetable is freed */ + struct sysctl_oid *sc_oid_support; + struct sysctl_oid *sc_oid_current; + struct sysctl_oid *sc_oid_open; }; /* prototypes */ @@ -450,15 +455,18 @@ sctx = device_get_sysctl_ctx(dev); soid = device_get_sysctl_tree(dev); - SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "supportmode", + sc->sc_oid_support = SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), + OID_AUTO, "supportmode", CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_support, "A", "Supporting port role"); - SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "currentmode", + sc->sc_oid_current = SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), + OID_AUTO, "currentmode", CTLFLAG_RD|CTLTYPE_STRING, sc, 0, ufoma_sysctl_current, "A", "Current port role"); - SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "openmode", + sc->sc_oid_open = SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), + OID_AUTO, "openmode", CTLFLAG_RW|CTLTYPE_STRING, sc, 0, ufoma_sysctl_open, "A", "Mode to transit when port is opened"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "comunit", @@ -476,6 +484,35 @@ ufoma_detach(device_t dev) { struct ufoma_softc *sc = device_get_softc(dev); + struct sysctl_ctx_list *sctx; + + /* + * Remove the sysctl OIDs whose handlers dereference sc_modetable + * (ufoma_sysctl_support, ufoma_sysctl_current, ufoma_sysctl_open) + * BEFORE freeing sc_modetable below. sysctl_remove_oid(…,1,0) + * blocks on the sysctl rwlock until all in-flight handlers drain, + * so after it returns no handler can touch sc_modetable. + * + * sysctl_ctx_entry_del must be called first to drop the stale + * context entry; otherwise device_sysctl_fini → sysctl_ctx_free + * would later iterate a pointer to the freed OID. + */ + sctx = device_get_sysctl_ctx(dev); + if (sc->sc_oid_support != NULL) { + sysctl_ctx_entry_del(sctx, sc->sc_oid_support); + sysctl_remove_oid(sc->sc_oid_support, 1, 0); + sc->sc_oid_support = NULL; + } + if (sc->sc_oid_current != NULL) { + sysctl_ctx_entry_del(sctx, sc->sc_oid_current); + sysctl_remove_oid(sc->sc_oid_current, 1, 0); + sc->sc_oid_current = NULL; + } + if (sc->sc_oid_open != NULL) { + sysctl_ctx_entry_del(sctx, sc->sc_oid_open); + sysctl_remove_oid(sc->sc_oid_open, 1, 0); + sc->sc_oid_open = NULL; + } ucom_detach(&sc->sc_super_ucom, &sc->sc_ucom); usbd_transfer_unsetup(sc->sc_ctrl_xfer, UFOMA_CTRL_ENDPT_MAX); |