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>
This commit is contained in:
parent
05a9a16170
commit
7236fe29fd
|
@ -1991,6 +1991,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
|
|||
void ieee80211_tx_pending(unsigned long data)
|
||||
{
|
||||
struct ieee80211_local *local = (struct ieee80211_local *)data;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
bool txok;
|
||||
|
@ -2029,6 +2030,11 @@ void ieee80211_tx_pending(unsigned long data)
|
|||
if (!txok)
|
||||
break;
|
||||
}
|
||||
|
||||
if (skb_queue_empty(&local->pending[i]))
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
netif_tx_wake_queue(
|
||||
netdev_get_tx_queue(sdata->dev, i));
|
||||
}
|
||||
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
|
||||
|
|
|
@ -279,13 +279,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
|
|||
/* someone still has this queue stopped */
|
||||
return;
|
||||
|
||||
if (!skb_queue_empty(&local->pending[queue]))
|
||||
if (skb_queue_empty(&local->pending[queue])) {
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
|
||||
rcu_read_unlock();
|
||||
} else
|
||||
tasklet_schedule(&local->tx_pending_tasklet);
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(sdata, &local->interfaces, list)
|
||||
netif_tx_wake_queue(netdev_get_tx_queue(sdata->dev, queue));
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
|
|
Loading…
Reference in a new issue