I managed to trigger the following uvm fault by continously switching an iwm(4) client between two APs on different channels, i.e. a loop that runs: ifconfig iwm0 chan X; sleep 10; ifconfig iwm chan Y; sleep 10;
uvm_fault(0xffffffff819614a0, 0x7, 0, 2) -> e kernel: page fault trap, code=0 Stopped at softclock+0x32: movq %rdx,0x8(%rax) This diff seems to fix the problem. It cancels mira timeouts from interrupt context where a state change is scheduled, instead of cancelling mira timeouts from the process context which performs the actual state change. Also, cancel mira timeouts when the interface is brought down in iwm_stop() because this code path does not go through iwm_newstate(). ok? Note that unless we are in RUN state the timeouts have not been initialized so timeout_del() inside mira_cancel_timeouts() would panic if we called it. This can't be done in a different way since mira state can only be initialized once the node for our AP (ic->ic_bss) is available. Index: if_iwm.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v retrieving revision 1.156 diff -u -p -r1.156 if_iwm.c --- if_iwm.c 12 Jan 2017 18:06:57 -0000 1.156 +++ if_iwm.c 17 Jan 2017 18:59:20 -0000 @@ -5496,10 +5496,8 @@ iwm_newstate_task(void *psc) if (ostate == IEEE80211_S_SCAN && nstate != ostate) iwm_led_blink_stop(sc); - if (ostate == IEEE80211_S_RUN && nstate != ostate) { + if (ostate == IEEE80211_S_RUN && nstate != ostate) iwm_disable_beacon_filter(sc); - ieee80211_mira_cancel_timeouts(&in->in_mn); - } /* Reset the device if moving out of AUTH, ASSOC, or RUN. */ /* XXX Is there a way to switch states without a full reset? */ @@ -5632,8 +5630,11 @@ iwm_newstate(struct ieee80211com *ic, en { struct ifnet *ifp = IC2IFP(ic); struct iwm_softc *sc = ifp->if_softc; + struct iwm_node *in = (void *)ic->ic_bss; timeout_del(&sc->sc_calib_to); + if (ic->ic_state == IEEE80211_S_RUN) + ieee80211_mira_cancel_timeouts(&in->in_mn); sc->ns_nstate = nstate; sc->ns_arg = arg; @@ -6116,6 +6117,8 @@ iwm_stop(struct ifnet *ifp, int disable) ifq_clr_oactive(&ifp->if_snd); in->in_phyctxt = NULL; + if (ic->ic_state == IEEE80211_S_RUN) + ieee80211_mira_cancel_timeouts(&in->in_mn); task_del(systq, &sc->init_task); task_del(sc->sc_nswq, &sc->newstate_task);