aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-03-22 16:42:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-03-30 15:37:28 -0400
commit7236fe29fd72d17074574ba312e7f1bb9d10abaa (patch)
tree6afd1fed2871daca52f5a8b3070337ae1b6ada0d /net
parent05a9a1617026977422c7c5ed3aeac6f46fa2132c (diff)
mac80211: move netdev queue enabling to correct spot
"mac80211: fix skb buffering issue" still left a race between enabling the hardware queues and the virtual interface queues. In hindsight it's totally obvious that enabling the netdev queues for a hardware queue when the hardware queue is enabled is wrong, because it could well possible that we can fill the hw queue with packets we already have pending. Thus, we must only enable the netdev queues once all the pending packets have been processed and sent off to the device. In testing, I haven't been able to trigger this race condition, but it's clearly there, possibly only when aggregation is being enabled. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Cc: stable@kernel.org Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/tx.c6
-rw-r--r--net/mac80211/util.c12
2 files changed, 12 insertions, 6 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index cbe53ed4fb0b..cfc473e1b050 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1991,6 +1991,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
1991void ieee80211_tx_pending(unsigned long data) 1991void ieee80211_tx_pending(unsigned long data)
1992{ 1992{
1993 struct ieee80211_local *local = (struct ieee80211_local *)data; 1993 struct ieee80211_local *local = (struct ieee80211_local *)data;
1994 struct ieee80211_sub_if_data *sdata;
1994 unsigned long flags; 1995 unsigned long flags;
1995 int i; 1996 int i;
1996 bool txok; 1997 bool txok;
@@ -2029,6 +2030,11 @@ void ieee80211_tx_pending(unsigned long data)
2029 if (!txok) 2030 if (!txok)
2030 break; 2031 break;
2031 } 2032 }
2033
2034 if (skb_queue_empty(&local->pending[i]))
2035 list_for_each_entry_rcu(sdata, &local->interfaces, list)
2036 netif_tx_wake_queue(
2037 netdev_get_tx_queue(sdata->dev, i));
2032 } 2038 }
2033 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 2039 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
2034 2040
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index e6b1fba980c6..53af57047435 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -279,13 +279,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
279 /* someone still has this queue stopped */ 279 /* someone still has this queue stopped */
280 return; 280 return;
281 281
282 if (!skb_queue_empty(&local->pending[queue])) 282 if (skb_queue_empty(&local->pending[queue])) {
283 rcu_read_lock();
284 list_for_each_entry_rcu(sdata, &local->interfaces, list)
285 netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
286 rcu_read_unlock();
287 } else
283 tasklet_schedule(&local->tx_pending_tasklet); 288 tasklet_schedule(&local->tx_pending_tasklet);
284
285 rcu_read_lock();
286 list_for_each_entry_rcu(sdata, &local->interfaces, list)
287 netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
288 rcu_read_unlock();
289} 289}
290 290
291void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, 291void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,