aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2010-03-22 16:42:43 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-04-26 10:47:48 -0400
commit358f3455718bf3db530eddf4c85ba5465e5f3e2d (patch)
treedbbe263b6f92db230c6caf7641e2827a224f0fad /net
parent19247cfcced8bd22953a04e7cedef591c0ea1ec4 (diff)
mac80211: move netdev queue enabling to correct spot
commit 7236fe29fd72d17074574ba312e7f1bb9d10abaa upstream. "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> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
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 70c79c3013fa..1fdc0a562b47 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1945,6 +1945,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
1945void ieee80211_tx_pending(unsigned long data) 1945void ieee80211_tx_pending(unsigned long data)
1946{ 1946{
1947 struct ieee80211_local *local = (struct ieee80211_local *)data; 1947 struct ieee80211_local *local = (struct ieee80211_local *)data;
1948 struct ieee80211_sub_if_data *sdata;
1948 unsigned long flags; 1949 unsigned long flags;
1949 int i; 1950 int i;
1950 bool txok; 1951 bool txok;
@@ -1983,6 +1984,11 @@ void ieee80211_tx_pending(unsigned long data)
1983 if (!txok) 1984 if (!txok)
1984 break; 1985 break;
1985 } 1986 }
1987
1988 if (skb_queue_empty(&local->pending[i]))
1989 list_for_each_entry_rcu(sdata, &local->interfaces, list)
1990 netif_tx_wake_queue(
1991 netdev_get_tx_queue(sdata->dev, i));
1986 } 1992 }
1987 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); 1993 spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
1988 1994
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 3848140313f5..c7179cbb0d8e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -280,13 +280,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
280 /* someone still has this queue stopped */ 280 /* someone still has this queue stopped */
281 return; 281 return;
282 282
283 if (!skb_queue_empty(&local->pending[queue])) 283 if (skb_queue_empty(&local->pending[queue])) {
284 rcu_read_lock();
285 list_for_each_entry_rcu(sdata, &local->interfaces, list)
286 netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
287 rcu_read_unlock();
288 } else
284 tasklet_schedule(&local->tx_pending_tasklet); 289 tasklet_schedule(&local->tx_pending_tasklet);
285
286 rcu_read_lock();
287 list_for_each_entry_rcu(sdata, &local->interfaces, list)
288 netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
289 rcu_read_unlock();
290} 290}
291 291
292void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, 292void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,