linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4] mac80211:  Optimize sta lookup for many VIFs
@ 2013-03-29 16:00 greearb
  2013-04-03 12:58 ` Johannes Berg
  2013-04-09  9:50 ` Johannes Berg
  0 siblings, 2 replies; 8+ messages in thread
From: greearb @ 2013-03-29 16:00 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ben Greear

From: Ben Greear <greearb@candelatech.com>

The sta_info hash is designed to deal with an AP
with lots of stations associated, or a station interface
connected to a single AP.

However, when you have lots of station VIFs connected
to the same AP, the sta_info hash becomes worthless
as there is a single hash bucket that contains all the
entries in a linked list.

So, have the sdata object cache one of its station
interfaces.  If we are a station VIF with a single
sta_info, then this means we can ignore the sta_info
hash entirely.

On a test case with 128 stations and 50 TCP streams,
tx performance went from around 80Mbps to 124Mbps.

Signed-off-by: Ben Greear <greearb@candelatech.com>
---

v4:  Use rcu_dereference_protected as designed, passing a mutex
     as the second argument instead of hard-coding it to 1.

:100644 100644 a618bda... a7e7f5d... M	net/mac80211/cfg.c
:100644 100644 493e2e8... c6386c7... M	net/mac80211/ieee80211_i.h
:100644 100644 415f9c6... d87a76d... M	net/mac80211/sta_info.c
 net/mac80211/cfg.c         |    6 ++++++
 net/mac80211/ieee80211_i.h |    6 ++++++
 net/mac80211/sta_info.c    |   23 ++++++++++++++++++++++-
 3 files changed, 34 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a618bda..a7e7f5d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1287,6 +1287,7 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 	if (params->vlan && params->vlan != sta->sdata->dev) {
 		bool prev_4addr = false;
 		bool new_4addr = false;
+		struct sta_info *some_sta;
 
 		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
@@ -1312,7 +1313,12 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 			prev_4addr = true;
 		}
 
+		some_sta = rcu_dereference_protected(sta->sdata->some_sta,
+					lockdep_is_held(&local->sta_mtx));
+		if (some_sta == sta)
+			rcu_assign_pointer(sta->sdata->some_sta, NULL);
 		sta->sdata = vlansdata;
+		rcu_assign_pointer(sta->sdata->some_sta, sta);
 
 		if (sta->sta_state == IEEE80211_STA_AUTHORIZED &&
 		    prev_4addr != new_4addr) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 493e2e8..c6386c7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -669,6 +669,12 @@ struct ieee80211_sub_if_data {
 	/* count for keys needing tailroom space allocation */
 	int crypto_tx_tailroom_needed_cnt;
 
+	/* A pointer to some station associated with this interface, or
+	 * NULL.  This allows opportunistic lookup for sta_info objects when
+	 * sdata is a station with a single sta_info.
+	 */
+	struct sta_info __rcu *some_sta;
+
 	struct net_device *dev;
 	struct ieee80211_local *local;
 
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 415f9c6..d87a76d 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -67,7 +67,12 @@
 static int sta_info_hash_del(struct ieee80211_local *local,
 			     struct sta_info *sta)
 {
-	struct sta_info *s;
+	struct sta_info *s, *some_sta;
+
+	some_sta = rcu_dereference_protected(sta->sdata->some_sta,
+					     lockdep_is_held(&local->sta_mtx));
+	if (some_sta == sta)
+		rcu_assign_pointer(sta->sdata->some_sta, NULL);
 
 	s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)],
 				      lockdep_is_held(&local->sta_mtx));
@@ -195,6 +200,20 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 
+	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+		struct sta_info *some_sta;
+
+		/* Shortcut for finding station entries for STATION VIFs */
+		some_sta = rcu_dereference(sdata->some_sta);
+		if (some_sta) {
+			if (WARN_ON(some_sta->sdata != sdata))
+				rcu_assign_pointer(sdata->some_sta, NULL);
+			else
+				if (ether_addr_equal(some_sta->sta.addr, addr))
+					return some_sta;
+		}
+	}
+
 	sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
 				    lockdep_is_held(&local->sta_mtx));
 	while (sta) {
@@ -278,6 +297,8 @@ static void sta_info_hash_add(struct ieee80211_local *local,
 	lockdep_assert_held(&local->sta_mtx);
 	sta->hnext = local->sta_hash[STA_HASH(sta->sta.addr)];
 	rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
+
+	rcu_assign_pointer(sta->sdata->some_sta, sta);
 }
 
 static void sta_unblock(struct work_struct *wk)
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-04-11 16:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-29 16:00 [PATCH v4] mac80211: Optimize sta lookup for many VIFs greearb
2013-04-03 12:58 ` Johannes Berg
2013-04-03 13:18   ` Ben Greear
2013-04-03 13:19     ` Johannes Berg
2013-04-09  9:50 ` Johannes Berg
2013-04-09 17:35   ` Ben Greear
2013-04-11  9:15     ` Johannes Berg
2013-04-11 16:17       ` Ben Greear

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).