svn commit: r224774 - user/adrian/if_ath_tx/sys/dev/ath
Adrian Chadd
adrian at FreeBSD.org
Thu Aug 11 08:51:53 UTC 2011
Author: adrian
Date: Thu Aug 11 08:51:53 2011
New Revision: 224774
URL: http://svn.freebsd.org/changeset/base/224774
Log:
Fix the TXQ recursive locking bug that sometimes occurs when an interface
is destroyed.
Only lock the TXQ if it isn't locked by us.
Modified:
user/adrian/if_ath_tx/sys/dev/ath/README
user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c
user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h
Modified: user/adrian/if_ath_tx/sys/dev/ath/README
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/README Thu Aug 11 06:45:12 2011 (r224773)
+++ user/adrian/if_ath_tx/sys/dev/ath/README Thu Aug 11 08:51:53 2011 (r224774)
@@ -59,8 +59,15 @@ fork_trampoline+10 (?,?,?,?) ra 0 sp c77
pid 0
+
+
+Fixed issues:
+
* Recursive TXQ lock on interface destruction:
+ - Fixed by only locking the TXQ in ath_tx_node_flush if the TXQ
+ isn't already locked by us.
+
drian-home-mips# ifconfig wlan0 destroy
ath1: ath_tx_node_flush: called
ar5212StopDmaReceive: dma failed to stop in 10ms
Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Thu Aug 11 06:45:12 2011 (r224773)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Thu Aug 11 08:51:53 2011 (r224774)
@@ -1818,41 +1818,34 @@ ath_tx_tid_free_pkts(struct ath_softc *s
/*
* Flush all software queued packets for the given node.
*
- * XXX there's a recursive lock here which currently panics
- * XXX the kernel.
- *
- * bringing the interface down/up causes a flush on interface
- * _up_; the stack looks like this:
- *
- * <panic>
- * ath_tx_node_flush - locks each hardware txq
- * ieee80211_free_node
- * ath_tx_freebuf
- * ath_tx_default_comp
- * ath_tx_processq - locks the hardware txq
- *
- * To fix? Not (yet) sure. Perhaps unsched the TID in freebuf
- * if there's no further buffers for it; then only flush
- * nodes w/ a lock below if the qlen is 0. But can the tid
- * txq length be checked without having the txq locked?
- * It'll be locked by someone, but if this node is being freed,
- * in theory all references to the node should be released
- * and thus there shouldn't be any packets in the TIDs for that
- * node. Hm.
+ * Work around recursive TXQ locking.
+ * This occurs when a completion handler frees the last buffer
+ * for a node, and the node is thus freed. This causes the node
+ * to be cleaned up, which ends up calling ath_tx_node_flush.
*/
void
ath_tx_node_flush(struct ath_softc *sc, struct ath_node *an)
{
int tid;
+ int is_owned;
for (tid = 0; tid < IEEE80211_TID_SIZE; tid++) {
struct ath_tid *atid = &an->an_tid[tid];
struct ath_txq *txq = sc->sc_ac2q[atid->ac];
- ATH_TXQ_LOCK(txq);
+ /*
+ * Only lock if we don't have it locked.
+ * It may be locked already if this is being called
+ * when the last buffer for an ieee80211_node is
+ * being freed.
+ */
+ is_owned = ATH_TXQ_IS_LOCKED(txq);
+ if (! is_owned)
+ ATH_TXQ_LOCK(txq);
/* Remove this tid from the list of active tids */
ath_tx_tid_unsched(sc, an, tid);
- ATH_TXQ_UNLOCK(txq);
+ if (! is_owned)
+ ATH_TXQ_UNLOCK(txq);
/* Free packets */
ath_tx_tid_free_pkts(sc, an, tid);
Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Thu Aug 11 06:45:12 2011 (r224773)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Thu Aug 11 08:51:53 2011 (r224774)
@@ -249,6 +249,7 @@ struct ath_txq {
#define ATH_TXQ_LOCK(_tq) mtx_lock(&(_tq)->axq_lock)
#define ATH_TXQ_UNLOCK(_tq) mtx_unlock(&(_tq)->axq_lock)
#define ATH_TXQ_LOCK_ASSERT(_tq) mtx_assert(&(_tq)->axq_lock, MA_OWNED)
+#define ATH_TXQ_IS_LOCKED(_tq) mtx_owned(&(_tq)->axq_lock)
#define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \
STAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \
More information about the svn-src-user
mailing list