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);