summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2016-09-19 07:00:10 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-20 04:43:36 -0400
commit83e7e4ce9e93c3b020497144f4354b62aed5d894 (patch)
tree946fbe77a562eb44d6533660d206a6141406d664 /net
parentca26893f05e86497a86732768ec53cd38c0819ca (diff)
mac80211: Use rhltable instead of rhashtable
mac80211 currently uses rhashtable with insecure_elasticity set to true. The latter is because of duplicate objects. What's more, mac80211 walks the rhashtable chains by hand which is broken as rhashtable may contain multiple tables due to resizing or rehashing. This patch fixes it by converting it to the newly added rhltable interface which is designed for use with duplicate objects. With rhltable a lookup returns a list of objects instead of a single one. This is then fed into the existing for_each_sta_info macro. This patch also deletes the sta_addr_hash function since rhashtable defaults to jhash. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/rx.c7
-rw-r--r--net/mac80211/sta_info.c52
-rw-r--r--net/mac80211/sta_info.h19
-rw-r--r--net/mac80211/status.c7
5 files changed, 33 insertions, 54 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c71c73594790..e496dee5af08 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1213,7 +1213,7 @@ struct ieee80211_local {
1213 spinlock_t tim_lock; 1213 spinlock_t tim_lock;
1214 unsigned long num_sta; 1214 unsigned long num_sta;
1215 struct list_head sta_list; 1215 struct list_head sta_list;
1216 struct rhashtable sta_hash; 1216 struct rhltable sta_hash;
1217 struct timer_list sta_cleanup; 1217 struct timer_list sta_cleanup;
1218 int sta_generation; 1218 int sta_generation;
1219 1219
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index e796060b7c5e..f7cf342bab52 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -4003,7 +4003,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
4003 __le16 fc; 4003 __le16 fc;
4004 struct ieee80211_rx_data rx; 4004 struct ieee80211_rx_data rx;
4005 struct ieee80211_sub_if_data *prev; 4005 struct ieee80211_sub_if_data *prev;
4006 struct rhash_head *tmp; 4006 struct rhlist_head *tmp;
4007 int err = 0; 4007 int err = 0;
4008 4008
4009 fc = ((struct ieee80211_hdr *)skb->data)->frame_control; 4009 fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
@@ -4046,13 +4046,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
4046 goto out; 4046 goto out;
4047 } else if (ieee80211_is_data(fc)) { 4047 } else if (ieee80211_is_data(fc)) {
4048 struct sta_info *sta, *prev_sta; 4048 struct sta_info *sta, *prev_sta;
4049 const struct bucket_table *tbl;
4050 4049
4051 prev_sta = NULL; 4050 prev_sta = NULL;
4052 4051
4053 tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); 4052 for_each_sta_info(local, hdr->addr2, sta, tmp) {
4054
4055 for_each_sta_info(local, tbl, hdr->addr2, sta, tmp) {
4056 if (!prev_sta) { 4053 if (!prev_sta) {
4057 prev_sta = sta; 4054 prev_sta = sta;
4058 continue; 4055 continue;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 1b1b28ff4fdb..c803e2cb58bc 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -67,12 +67,10 @@
67 67
68static const struct rhashtable_params sta_rht_params = { 68static const struct rhashtable_params sta_rht_params = {
69 .nelem_hint = 3, /* start small */ 69 .nelem_hint = 3, /* start small */
70 .insecure_elasticity = true, /* Disable chain-length checks. */
71 .automatic_shrinking = true, 70 .automatic_shrinking = true,
72 .head_offset = offsetof(struct sta_info, hash_node), 71 .head_offset = offsetof(struct sta_info, hash_node),
73 .key_offset = offsetof(struct sta_info, addr), 72 .key_offset = offsetof(struct sta_info, addr),
74 .key_len = ETH_ALEN, 73 .key_len = ETH_ALEN,
75 .hashfn = sta_addr_hash,
76 .max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE, 74 .max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE,
77}; 75};
78 76
@@ -80,8 +78,8 @@ static const struct rhashtable_params sta_rht_params = {
80static int sta_info_hash_del(struct ieee80211_local *local, 78static int sta_info_hash_del(struct ieee80211_local *local,
81 struct sta_info *sta) 79 struct sta_info *sta)
82{ 80{
83 return rhashtable_remove_fast(&local->sta_hash, &sta->hash_node, 81 return rhltable_remove(&local->sta_hash, &sta->hash_node,
84 sta_rht_params); 82 sta_rht_params);
85} 83}
86 84
87static void __cleanup_single_sta(struct sta_info *sta) 85static void __cleanup_single_sta(struct sta_info *sta)
@@ -157,19 +155,22 @@ static void cleanup_single_sta(struct sta_info *sta)
157 sta_info_free(local, sta); 155 sta_info_free(local, sta);
158} 156}
159 157
158struct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local,
159 const u8 *addr)
160{
161 return rhltable_lookup(&local->sta_hash, addr, sta_rht_params);
162}
163
160/* protected by RCU */ 164/* protected by RCU */
161struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, 165struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
162 const u8 *addr) 166 const u8 *addr)
163{ 167{
164 struct ieee80211_local *local = sdata->local; 168 struct ieee80211_local *local = sdata->local;
169 struct rhlist_head *tmp;
165 struct sta_info *sta; 170 struct sta_info *sta;
166 struct rhash_head *tmp;
167 const struct bucket_table *tbl;
168 171
169 rcu_read_lock(); 172 rcu_read_lock();
170 tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); 173 for_each_sta_info(local, addr, sta, tmp) {
171
172 for_each_sta_info(local, tbl, addr, sta, tmp) {
173 if (sta->sdata == sdata) { 174 if (sta->sdata == sdata) {
174 rcu_read_unlock(); 175 rcu_read_unlock();
175 /* this is safe as the caller must already hold 176 /* this is safe as the caller must already hold
@@ -190,14 +191,11 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
190 const u8 *addr) 191 const u8 *addr)
191{ 192{
192 struct ieee80211_local *local = sdata->local; 193 struct ieee80211_local *local = sdata->local;
194 struct rhlist_head *tmp;
193 struct sta_info *sta; 195 struct sta_info *sta;
194 struct rhash_head *tmp;
195 const struct bucket_table *tbl;
196 196
197 rcu_read_lock(); 197 rcu_read_lock();
198 tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); 198 for_each_sta_info(local, addr, sta, tmp) {
199
200 for_each_sta_info(local, tbl, addr, sta, tmp) {
201 if (sta->sdata == sdata || 199 if (sta->sdata == sdata ||
202 (sta->sdata->bss && sta->sdata->bss == sdata->bss)) { 200 (sta->sdata->bss && sta->sdata->bss == sdata->bss)) {
203 rcu_read_unlock(); 201 rcu_read_unlock();
@@ -263,8 +261,8 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
263static int sta_info_hash_add(struct ieee80211_local *local, 261static int sta_info_hash_add(struct ieee80211_local *local,
264 struct sta_info *sta) 262 struct sta_info *sta)
265{ 263{
266 return rhashtable_insert_fast(&local->sta_hash, &sta->hash_node, 264 return rhltable_insert(&local->sta_hash, &sta->hash_node,
267 sta_rht_params); 265 sta_rht_params);
268} 266}
269 267
270static void sta_deliver_ps_frames(struct work_struct *wk) 268static void sta_deliver_ps_frames(struct work_struct *wk)
@@ -453,9 +451,9 @@ static int sta_info_insert_check(struct sta_info *sta)
453 is_multicast_ether_addr(sta->sta.addr))) 451 is_multicast_ether_addr(sta->sta.addr)))
454 return -EINVAL; 452 return -EINVAL;
455 453
456 /* Strictly speaking this isn't necessary as we hold the mutex, but 454 /* The RCU read lock is required by rhashtable due to
457 * the rhashtable code can't really deal with that distinction. We 455 * asynchronous resize/rehash. We also require the mutex
458 * do require the mutex for correctness though. 456 * for correctness.
459 */ 457 */
460 rcu_read_lock(); 458 rcu_read_lock();
461 lockdep_assert_held(&sdata->local->sta_mtx); 459 lockdep_assert_held(&sdata->local->sta_mtx);
@@ -1043,16 +1041,11 @@ static void sta_info_cleanup(unsigned long data)
1043 round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL)); 1041 round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL));
1044} 1042}
1045 1043
1046u32 sta_addr_hash(const void *key, u32 length, u32 seed)
1047{
1048 return jhash(key, ETH_ALEN, seed);
1049}
1050
1051int sta_info_init(struct ieee80211_local *local) 1044int sta_info_init(struct ieee80211_local *local)
1052{ 1045{
1053 int err; 1046 int err;
1054 1047
1055 err = rhashtable_init(&local->sta_hash, &sta_rht_params); 1048 err = rhltable_init(&local->sta_hash, &sta_rht_params);
1056 if (err) 1049 if (err)
1057 return err; 1050 return err;
1058 1051
@@ -1068,7 +1061,7 @@ int sta_info_init(struct ieee80211_local *local)
1068void sta_info_stop(struct ieee80211_local *local) 1061void sta_info_stop(struct ieee80211_local *local)
1069{ 1062{
1070 del_timer_sync(&local->sta_cleanup); 1063 del_timer_sync(&local->sta_cleanup);
1071 rhashtable_destroy(&local->sta_hash); 1064 rhltable_destroy(&local->sta_hash);
1072} 1065}
1073 1066
1074 1067
@@ -1138,17 +1131,14 @@ struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
1138 const u8 *localaddr) 1131 const u8 *localaddr)
1139{ 1132{
1140 struct ieee80211_local *local = hw_to_local(hw); 1133 struct ieee80211_local *local = hw_to_local(hw);
1134 struct rhlist_head *tmp;
1141 struct sta_info *sta; 1135 struct sta_info *sta;
1142 struct rhash_head *tmp;
1143 const struct bucket_table *tbl;
1144
1145 tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
1146 1136
1147 /* 1137 /*
1148 * Just return a random station if localaddr is NULL 1138 * Just return a random station if localaddr is NULL
1149 * ... first in list. 1139 * ... first in list.
1150 */ 1140 */
1151 for_each_sta_info(local, tbl, addr, sta, tmp) { 1141 for_each_sta_info(local, addr, sta, tmp) {
1152 if (localaddr && 1142 if (localaddr &&
1153 !ether_addr_equal(sta->sdata->vif.addr, localaddr)) 1143 !ether_addr_equal(sta->sdata->vif.addr, localaddr))
1154 continue; 1144 continue;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 530231b73278..ed5fcb984a01 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -455,7 +455,7 @@ struct sta_info {
455 /* General information, mostly static */ 455 /* General information, mostly static */
456 struct list_head list, free_list; 456 struct list_head list, free_list;
457 struct rcu_head rcu_head; 457 struct rcu_head rcu_head;
458 struct rhash_head hash_node; 458 struct rhlist_head hash_node;
459 u8 addr[ETH_ALEN]; 459 u8 addr[ETH_ALEN];
460 struct ieee80211_local *local; 460 struct ieee80211_local *local;
461 struct ieee80211_sub_if_data *sdata; 461 struct ieee80211_sub_if_data *sdata;
@@ -638,6 +638,9 @@ rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
638 */ 638 */
639#define STA_INFO_CLEANUP_INTERVAL (10 * HZ) 639#define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
640 640
641struct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local,
642 const u8 *addr);
643
641/* 644/*
642 * Get a STA info, must be under RCU read lock. 645 * Get a STA info, must be under RCU read lock.
643 */ 646 */
@@ -647,17 +650,9 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
647struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, 650struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
648 const u8 *addr); 651 const u8 *addr);
649 652
650u32 sta_addr_hash(const void *key, u32 length, u32 seed); 653#define for_each_sta_info(local, _addr, _sta, _tmp) \
651 654 rhl_for_each_entry_rcu(_sta, _tmp, \
652#define _sta_bucket_idx(_tbl, _a) \ 655 sta_info_hash_lookup(local, _addr), hash_node)
653 rht_bucket_index(_tbl, sta_addr_hash(_a, ETH_ALEN, (_tbl)->hash_rnd))
654
655#define for_each_sta_info(local, tbl, _addr, _sta, _tmp) \
656 rht_for_each_entry_rcu(_sta, _tmp, tbl, \
657 _sta_bucket_idx(tbl, _addr), \
658 hash_node) \
659 /* compare address and run code only if it matches */ \
660 if (ether_addr_equal(_sta->addr, (_addr)))
661 656
662/* 657/*
663 * Get STA info by index, BROKEN! 658 * Get STA info by index, BROKEN!
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index ea39f8a7baf3..ddf71c648cab 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -746,8 +746,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
746 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 746 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
747 __le16 fc; 747 __le16 fc;
748 struct ieee80211_supported_band *sband; 748 struct ieee80211_supported_band *sband;
749 struct rhlist_head *tmp;
749 struct sta_info *sta; 750 struct sta_info *sta;
750 struct rhash_head *tmp;
751 int retry_count; 751 int retry_count;
752 int rates_idx; 752 int rates_idx;
753 bool send_to_cooked; 753 bool send_to_cooked;
@@ -755,7 +755,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
755 struct ieee80211_bar *bar; 755 struct ieee80211_bar *bar;
756 int shift = 0; 756 int shift = 0;
757 int tid = IEEE80211_NUM_TIDS; 757 int tid = IEEE80211_NUM_TIDS;
758 const struct bucket_table *tbl;
759 758
760 rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); 759 rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
761 760
@@ -764,9 +763,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
764 sband = local->hw.wiphy->bands[info->band]; 763 sband = local->hw.wiphy->bands[info->band];
765 fc = hdr->frame_control; 764 fc = hdr->frame_control;
766 765
767 tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash); 766 for_each_sta_info(local, hdr->addr1, sta, tmp) {
768
769 for_each_sta_info(local, tbl, hdr->addr1, sta, tmp) {
770 /* skip wrong virtual interface */ 767 /* skip wrong virtual interface */
771 if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr)) 768 if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
772 continue; 769 continue;