Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 21 Sep 2015 02:12:02 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r288051 - head/sys/dev/usb/wlan
Message-ID:  <201509210212.t8L2C2IF033043@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Mon Sep 21 02:12:01 2015
New Revision: 288051
URL: https://svnweb.freebsd.org/changeset/base/288051

Log:
  Drain the mbuf queue upon rsu_stop().
  
  Correctly (I hope!) remove net80211 references before doing so.
  Just doing a dumb mbufq drain isn't enough.
  
  If enough traffic occurs and the mbuf queue fills up then transmit
  stalls (which I'm not fixing in this commit!) but then the mbuf queue
  stays full until the driver is removed.  There's also the net80211
  node refcounting leak.
  
  This just ensures that during rsu_stop and detach the mbuf queue
  is purged (and references!) so the queue-full situation can be
  recovered from.

Modified:
  head/sys/dev/usb/wlan/if_rsu.c

Modified: head/sys/dev/usb/wlan/if_rsu.c
==============================================================================
--- head/sys/dev/usb/wlan/if_rsu.c	Mon Sep 21 01:51:37 2015	(r288050)
+++ head/sys/dev/usb/wlan/if_rsu.c	Mon Sep 21 02:12:01 2015	(r288051)
@@ -508,6 +508,8 @@ rsu_detach(device_t self)
 	rsu_stop(sc);
 	RSU_UNLOCK(sc);
 	usbd_transfer_unsetup(sc->sc_xfer, RSU_N_TRANSFER);
+
+	/* Frames are freed; detach from net80211 */
 	ieee80211_ifdetach(ic);
 
 	taskqueue_drain_timeout(taskqueue_thread, &sc->calib_task);
@@ -516,7 +518,6 @@ rsu_detach(device_t self)
 	rsu_free_tx_list(sc);
 	rsu_free_rx_list(sc);
 
-	mbufq_drain(&sc->sc_snd);
 	mtx_destroy(&sc->sc_mtx);
 
 	return (0);
@@ -759,6 +760,9 @@ rsu_getbuf(struct rsu_softc *sc)
 	RSU_ASSERT_LOCKED(sc);
 
 	bf = _rsu_getbuf(sc);
+	if (bf == NULL) {
+		RSU_DPRINTF(sc, RSU_DEBUG_TX, "%s: no buffers\n", __func__);
+	}
 	return (bf);
 }
 
@@ -1997,6 +2001,10 @@ rsu_transmit(struct ieee80211com *ic, st
 	}
 	error = mbufq_enqueue(&sc->sc_snd, m);
 	if (error) {
+		RSU_DPRINTF(sc, RSU_DEBUG_TX,
+		    "%s: mbufq_enable: failed (%d)\n",
+		    __func__,
+		    error);
 		RSU_UNLOCK(sc);
 		return (error);
 	}
@@ -2007,6 +2015,21 @@ rsu_transmit(struct ieee80211com *ic, st
 }
 
 static void
+rsu_drain_mbufq(struct rsu_softc *sc)
+{
+	struct mbuf *m;
+	struct ieee80211_node *ni;
+
+	RSU_ASSERT_LOCKED(sc);
+	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
+		ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+		m->m_pkthdr.rcvif = NULL;
+		ieee80211_free_node(ni);
+		m_freem(m);
+	}
+}
+
+static void
 rsu_start(struct rsu_softc *sc)
 {
 	struct ieee80211_node *ni;
@@ -2018,6 +2041,8 @@ rsu_start(struct rsu_softc *sc)
 	while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) {
 		bf = rsu_getbuf(sc);
 		if (bf == NULL) {
+			RSU_DPRINTF(sc, RSU_DEBUG_TX,
+			    "%s: failed to get buffer\n", __func__);
 			mbufq_prepend(&sc->sc_snd, m);
 			break;
 		}
@@ -2026,6 +2051,8 @@ rsu_start(struct rsu_softc *sc)
 		m->m_pkthdr.rcvif = NULL;
 
 		if (rsu_tx_start(sc, ni, m, bf) != 0) {
+			RSU_DPRINTF(sc, RSU_DEBUG_TX,
+			    "%s: failed to transmit\n", __func__);
 			if_inc_counter(ni->ni_vap->iv_ifp,
 			    IFCOUNTER_OERRORS, 1);
 			rsu_freebuf(sc, bf);
@@ -2551,6 +2578,9 @@ rsu_init(struct rsu_softc *sc)
 
 	RSU_ASSERT_LOCKED(sc);
 
+	/* Ensure the mbuf queue is drained */
+	rsu_drain_mbufq(sc);
+
 	/* Init host async commands ring. */
 	sc->cmdq.cur = sc->cmdq.next = sc->cmdq.queued = 0;
 
@@ -2660,6 +2690,9 @@ rsu_stop(struct rsu_softc *sc)
 
 	for (i = 0; i < RSU_N_TRANSFER; i++)
 		usbd_transfer_stop(sc->sc_xfer[i]);
+
+	/* Ensure the mbuf queue is drained */
+	rsu_drain_mbufq(sc);
 }
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201509210212.t8L2C2IF033043>