Dave, Stanislaw has given us two late-breaking fixes intended for 3.3. One avoids a NULL pointer dereference in iwl3945, and the other corrects a locking issue in the rt2x00 driver that can lead to random traffic stalls. Please let me know if there are problems! Thanks, John --- The following changes since commit 1ab5ecb90cb6a3df1476e052f76a6e8f6511cb3d: tun: don't hold network namespace by tun sockets (2012-03-12 17:14:00 -0700) are available in the git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless.git for-davem John W. Linville (1): Merge branch 'master' of git://git.kernel.org/.../linville/wireless into for-davem Stanislaw Gruszka (2): iwl3945: fix possible il->txq NULL pointer dereference in delayed works rt2x00: fix random stalls drivers/net/wireless/iwlegacy/3945-mac.c | 2 +- drivers/net/wireless/iwlegacy/3945.c | 7 ++++--- drivers/net/wireless/rt2x00/rt2x00dev.c | 6 +++++- drivers/net/wireless/rt2x00/rt2x00mac.c | 9 +++++++++ drivers/net/wireless/rt2x00/rt2x00queue.c | 3 +++ 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 54b2d39..a7dfba8 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -2475,7 +2475,7 @@ il3945_bg_alive_start(struct work_struct *data) container_of(data, struct il_priv, alive_start.work); mutex_lock(&il->mutex); - if (test_bit(S_EXIT_PENDING, &il->status)) + if (test_bit(S_EXIT_PENDING, &il->status) || il->txq == NULL) goto out; il3945_alive_start(il); diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c index 1489b15..c80eb9b 100644 --- a/drivers/net/wireless/iwlegacy/3945.c +++ b/drivers/net/wireless/iwlegacy/3945.c @@ -1870,11 +1870,12 @@ il3945_bg_reg_txpower_periodic(struct work_struct *work) struct il_priv *il = container_of(work, struct il_priv, _3945.thermal_periodic.work); - if (test_bit(S_EXIT_PENDING, &il->status)) - return; - mutex_lock(&il->mutex); + if (test_bit(S_EXIT_PENDING, &il->status) || il->txq == NULL) + goto out; + il3945_reg_txpower_periodic(il); +out: mutex_unlock(&il->mutex); } diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index d2a1ea9..fd356b7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -426,10 +426,14 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * If the data queue was below the threshold before the txdone * handler we must make sure the packet queue in the mac80211 stack - * is reenabled when the txdone handler has finished. + * is reenabled when the txdone handler has finished. This has to be + * serialized with rt2x00mac_tx(), otherwise we can wake up queue + * before it was stopped. */ + spin_lock_bh(&entry->queue->tx_lock); if (!rt2x00queue_threshold(entry->queue)) rt2x00queue_unpause_queue(entry->queue); + spin_unlock_bh(&entry->queue->tx_lock); } EXPORT_SYMBOL_GPL(rt2x00lib_txdone); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index ede3c58..2df2eb6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -152,13 +152,22 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (unlikely(rt2x00queue_write_tx_frame(queue, skb, false))) goto exit_fail; + /* + * Pausing queue has to be serialized with rt2x00lib_txdone(). Note + * we should not use spin_lock_bh variant as bottom halve was already + * disabled before ieee80211_xmit() call. + */ + spin_lock(&queue->tx_lock); if (rt2x00queue_threshold(queue)) rt2x00queue_pause_queue(queue); + spin_unlock(&queue->tx_lock); return; exit_fail: + spin_lock(&queue->tx_lock); rt2x00queue_pause_queue(queue); + spin_unlock(&queue->tx_lock); exit_free_skb: ieee80211_free_txskb(hw, skb); } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 5adfb3e..9b1b2b7 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -619,6 +619,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb, else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags)) rt2x00queue_align_frame(skb); + /* + * That function must be called with bh disabled. + */ spin_lock(&queue->tx_lock); if (unlikely(rt2x00queue_full(queue))) { -- John W. Linville Someday the world will need a hero, and you linville@xxxxxxxxxxxxx might be all we have. Be ready.
Attachment:
pgpL7UrRlrnQn.pgp
Description: PGP signature