From owner-svn-src-head@freebsd.org Mon Sep 21 02:12:02 2015 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 92715A06CC9; Mon, 21 Sep 2015 02:12:02 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 7C34611CF; Mon, 21 Sep 2015 02:12:02 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t8L2C206033044; Mon, 21 Sep 2015 02:12:02 GMT (envelope-from adrian@FreeBSD.org) Received: (from adrian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t8L2C2IF033043; Mon, 21 Sep 2015 02:12:02 GMT (envelope-from adrian@FreeBSD.org) Message-Id: <201509210212.t8L2C2IF033043@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: adrian set sender to adrian@FreeBSD.org using -f From: Adrian Chadd Date: Mon, 21 Sep 2015 02:12:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r288051 - head/sys/dev/usb/wlan X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 21 Sep 2015 02:12:02 -0000 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); } /*