From cbfe89c67b58e2bd1b47f6986b3b793f06f3d9b0 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Wed, 24 Jun 2009 18:58:47 +0530 Subject: [PATCH] ath9k: Fix leak in tx descriptor When we reclaim the tx desc, we always assume that the last desc is a holding desc, which is not true, and skip it. If the tx queue is drained during channel change, internal reset and etc, the last descriptor may not be the holding descriptor and we fail to reclaim them. This results in the following two issues. 1. Tx stuck - We drop all the frames coming from upper layer due to shortage in tx desc. 2. Crash - If we fail to reclaim a tx descriptor, we miss to update the tx BA window with the seq number of the frame associated to that desc, which, at some point, result in the following crash due to an assert failure in ath_tx_addto_baw(). This patch fixes these two issues. kernel BUG at ../drivers/net/wireless/ath/ath9k/xmit.c:180! [155064.304164] invalid opcode: 0000 [#1] SMP Call Trace: [] ? ath9k_tx+0xeb/0x160 [ath9k] [] ipv6? __ieee80211_tx+0x41/0x120 [mac80211] [] ? aes_i586ieee80211_master_start_xmit+0x28e/0x560 [mac80211] [] aes_generic? _spin_lock_irqsave+0x31/0x40 [] ? dev_hard_start_xmit+0x16b/0x1c0 [] ? __qdisc_run+0x1b5/0x200 [] ? af_packetieee80211_select_queue+0xa/0x100 [mac80211] [] ? i915dev_queue_xmit+0x2e7/0x3f0 [] ? ieee80211_subif_start_xmit+0x369/0x7a0 [mac80211] [] ? ip_output+0x55/0xb0 [] ? show_memcpy_count+0x18/0x60 [] ? __kfree_skb+0x36/0x90 [] ? binfmt_miscdev_queue_xmit_nit+0xd2/0x110 [] ? dev_hard_start_xmit+0x16b/0x1c0 [] ? __qdisc_run+0x1b5/0x200 [] ? scoarp_create+0x57/0x2a0 [] ? bridgedev_queue_xmit+0x2e7/0x3f0 [] ? eth_header+0x0/0xc0 [] stp? arp_xmit+0x5f/0x70 [] ? arp_send+0x5f/0x70 [] bnep? arp_solicit+0x105/0x210 [] ? neigh_timer_handler+0x19a/0x390 [] ? run_timer_softirq+0x138/0x210 [] ? ppdevneigh_timer_handler+0x0/0x390 [] ? neigh_timer_handler+0x0/0x390 Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: John W. Linville --- drivers/net/wireless/ath/ath9k/xmit.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b61a071788a5..4ccf48e396df 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -355,7 +355,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } if (bf_next == NULL) { - INIT_LIST_HEAD(&bf_head); + /* + * Make sure the last desc is reclaimed if it + * not a holding desc. + */ + if (!bf_last->bf_stale) + list_move_tail(&bf->list, &bf_head); + else + INIT_LIST_HEAD(&bf_head); } else { ASSERT(!list_empty(bf_q)); list_move_tail(&bf->list, &bf_head); -- 2.20.1