From patchwork Tue Jan 5 08:38:03 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lennert Buytenhek X-Patchwork-Id: 70948 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.2) with ESMTP id o058cAgn016674 for ; Tue, 5 Jan 2010 08:38:10 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750967Ab0AEIiJ (ORCPT ); Tue, 5 Jan 2010 03:38:09 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751179Ab0AEIiJ (ORCPT ); Tue, 5 Jan 2010 03:38:09 -0500 Received: from fw.wantstofly.org ([80.101.37.227]:34073 "EHLO mail.wantstofly.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750868Ab0AEIiI (ORCPT ); Tue, 5 Jan 2010 03:38:08 -0500 Received: by mail.wantstofly.org (Postfix, from userid 500) id EF4AC18E202; Tue, 5 Jan 2010 09:38:03 +0100 (CET) Date: Tue, 5 Jan 2010 09:38:03 +0100 From: Lennert Buytenhek To: linux-wireless@vger.kernel.org Subject: infinite transmit buffering issue in 2.6.32 mac80211 Message-ID: <20100105083803.GP1735@mail.wantstofly.org> Mime-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.4.2.2i Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index eaa4118..f7d9033 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1294,6 +1298,8 @@ static void ieee80211_tx(struct ieee80211_sub_if_data *sda goto drop; /* fall through */ case IEEE80211_TX_PENDING: + goto drop; + skb = tx.skb; spin_lock_irqsave(&local->queue_stop_reason_lock, flags); However, TX queue status feedback is still broken with this, which is problematic as per: http://marc.info/?l=linux-netdev&m=121994203129939&w=2 http://marc.info/?l=linux-netdev&m=122004613003333&w=2 Propagating the queue stop to the higher-level interface (as per the somewhat broken patch below) is closer into the right direction, but Johannes voiced concerns that this is inefficient (which is demonstrated e.g. by the first email referenced above), but also, it creates a new problem, which is that of head-of-line blocking -- a low-priority flow can now cause the wlanX interface's main queue to be stopped, leading to queueing of high-priority traffic in the stack while the hardware's high-priority traffic queue sits empty. The only way I see to solve all of these issues cleanly is to convert the AP/STA/etc subinterfaces to be multiqueue interfaces, with the same number of transmit queues as the hardware has, so that there are independently stoppable/resumable virtual output queues all the way from userland to the actual hardware, and then to stop/resume those queues in response to the hardware DMA queues filling up and draining. Before I go ahead and do this -- thoughts? thanks, Lennert (broken -- doesn't deal properly with stops/wakes on multiple queues) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index dc76267..5ac558f 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -296,8 +296,33 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; + ieee80211_wake_queue_by_reason(hw, queue, IEEE80211_QUEUE_STOP_REASON_DRIVER); + + rcu_read_lock(); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + switch (sdata->vif.type) { + case __NL80211_IFTYPE_AFTER_LAST: + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP_VLAN: + continue; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + if (netif_running(sdata->dev)) + netif_wake_queue(sdata->dev); + break; + } + } + + rcu_read_unlock(); } EXPORT_SYMBOL(ieee80211_wake_queue); @@ -325,8 +350,33 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) { + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; + ieee80211_stop_queue_by_reason(hw, queue, IEEE80211_QUEUE_STOP_REASON_DRIVER); + + rcu_read_lock(); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + switch (sdata->vif.type) { + case __NL80211_IFTYPE_AFTER_LAST: + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP_VLAN: + continue; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_WDS: + case NL80211_IFTYPE_MESH_POINT: + if (netif_running(sdata->dev)) + netif_stop_queue(sdata->dev); + break; + } + } + + rcu_read_unlock(); } EXPORT_SYMBOL(ieee80211_stop_queue);