On Thu, Jul 12, 2012 at 05:51:32PM +0200, Stefan Sperling wrote: > Running "ifconfig ral0 debug down up" can leave slow systems, such > as edd@'s soekris, with an unusable wireless interface until reboot. > > The net80211 layer will run a scan when the interface comes up. > The scan hops from channel to channel every 200msec. This hopping is > controlled via a timeout that runs at IPL_SOFTCLOCK. When the scan > reaches the last channel it terminates. > > The problem with soekris is that, in noisy environments, they take so > much time printing debug messsages about received frames from > ieee80211_input() to the serial console that another RX interrupt > will run next at IPL_NET. This prevents the scan from running its 200msc > timeout handler at IPL_SOFTCLOCK, and the scan never finishes. > > With the diff below, we print the message from a work queue at IPL_TTY > instead (idea from guenther@). This allows the soekris to finish the scan. > The box is still hardly responsive during the scan but at least concurrent > SSH sessions remain somewhat responsive and eventually the soekris recovers > completely. >
Improved diff after clue-stick from blambert about how work queues and IPLs really interact. Index: ieee80211_input.c =================================================================== RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v retrieving revision 1.119 diff -u -p -r1.119 ieee80211_input.c --- ieee80211_input.c 5 Apr 2011 11:48:28 -0000 1.119 +++ ieee80211_input.c 13 Jul 2012 08:37:13 -0000 @@ -42,6 +42,7 @@ #include <sys/errno.h> #include <sys/proc.h> #include <sys/sysctl.h> +#include <sys/workq.h> #include <net/if.h> #include <net/if_dl.h> @@ -131,6 +132,9 @@ void ieee80211_recv_bar(struct ieee80211 void ieee80211_bar_tid(struct ieee80211com *, struct ieee80211_node *, u_int8_t, u_int16_t); #endif +void ieee80211_input_print(struct ieee80211com *, struct ifnet *, + struct ieee80211_frame *, struct ieee80211_rxinfo *); +void ieee80211_input_print_task(void *, void *); /* * Retrieve the length in bytes of an 802.11 header. @@ -152,6 +156,69 @@ ieee80211_get_hdrlen(const struct ieee80 return size; } +/* Work queue task that prints a received frame. Avoids printf() from + * interrupt context at IPL_NET making slow machines unusable when many + * frames are received and the interface is put in debug mode. */ +void +ieee80211_input_print_task(void *arg1, void *arg2) +{ + char *msg = arg1; + int s; + + s = spltty(); + printf(msg); + splx(s); + free(msg, M_DEVBUF); + +} + +void +ieee80211_input_print(struct ieee80211com *ic, struct ifnet *ifp, + struct ieee80211_frame *wh, struct ieee80211_rxinfo *rxi) +{ + int doprint, error; + char *msg; + u_int8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + /* avoid to print too many frames */ + doprint = 0; + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BEACON: + if (ic->ic_state == IEEE80211_S_SCAN) + doprint = 1; + break; +#ifndef IEEE80211_STA_ONLY + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + if (ic->ic_opmode == IEEE80211_M_IBSS) + doprint = 1; + break; +#endif + default: + doprint = 1; + break; + } +#ifdef IEEE80211_DEBUG + doprint += ieee80211_debug; +#endif + if (!doprint) + return; + + msg = malloc(1024, M_DEVBUF, M_NOWAIT); + if (msg == NULL) + return; + + snprintf(msg, 1024, "%s: received %s from %s rssi %d mode %s\n", + ifp->if_xname, + ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT], + ether_sprintf(wh->i_addr2), rxi->rxi_rssi, + ieee80211_phymode_name[ieee80211_chan2mode( + ic, ic->ic_bss->ni_chan)]); + + error = workq_add_task(NULL, 0, ieee80211_input_print_task, msg, NULL); + if (error) + free(msg, M_DEVBUF); +} + /* * Process a received frame. The node associated with the sender * should be supplied. If nothing was found in the node table then @@ -467,37 +534,8 @@ ieee80211_input(struct ifnet *ifp, struc goto out; } - if (ifp->if_flags & IFF_DEBUG) { - /* avoid to print too many frames */ - int doprint = 0; - - switch (subtype) { - case IEEE80211_FC0_SUBTYPE_BEACON: - if (ic->ic_state == IEEE80211_S_SCAN) - doprint = 1; - break; -#ifndef IEEE80211_STA_ONLY - case IEEE80211_FC0_SUBTYPE_PROBE_REQ: - if (ic->ic_opmode == IEEE80211_M_IBSS) - doprint = 1; - break; -#endif - default: - doprint = 1; - break; - } -#ifdef IEEE80211_DEBUG - doprint += ieee80211_debug; -#endif - if (doprint) - printf("%s: received %s from %s rssi %d mode %s\n", - ifp->if_xname, - ieee80211_mgt_subtype_name[subtype - >> IEEE80211_FC0_SUBTYPE_SHIFT], - ether_sprintf(wh->i_addr2), rxi->rxi_rssi, - ieee80211_phymode_name[ieee80211_chan2mode(ic, - ic->ic_bss->ni_chan)]); - } + if (ifp->if_flags & IFF_DEBUG) + ieee80211_input_print(ic, ifp, wh, rxi); #if NBPFILTER > 0 if (ic->ic_rawbpf) bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_IN);