aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch')
-rw-r--r--package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch275
1 files changed, 275 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch b/package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch
new file mode 100644
index 0000000000..4c5fff1274
--- /dev/null
+++ b/package/kernel/mac80211/patches/312-mac80211-Use-rhltable-instead-of-rhashtable.patch
@@ -0,0 +1,275 @@
+From: Herbert Xu <herbert@gondor.apana.org.au>
+Date: Mon, 19 Sep 2016 19:00:10 +0800
+Subject: [PATCH] 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>
+---
+
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1233,7 +1233,7 @@ struct ieee80211_local {
+ spinlock_t tim_lock;
+ unsigned long num_sta;
+ struct list_head sta_list;
+- struct rhashtable sta_hash;
++ struct rhltable sta_hash;
+ struct timer_list sta_cleanup;
+ int sta_generation;
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -4004,7 +4004,7 @@ static void __ieee80211_rx_handle_packet
+ __le16 fc;
+ struct ieee80211_rx_data rx;
+ struct ieee80211_sub_if_data *prev;
+- struct rhash_head *tmp;
++ struct rhlist_head *tmp;
+ int err = 0;
+
+ fc = ((struct ieee80211_hdr *)skb->data)->frame_control;
+@@ -4047,13 +4047,10 @@ static void __ieee80211_rx_handle_packet
+ goto out;
+ } else if (ieee80211_is_data(fc)) {
+ struct sta_info *sta, *prev_sta;
+- const struct bucket_table *tbl;
+
+ prev_sta = NULL;
+
+- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+-
+- for_each_sta_info(local, tbl, hdr->addr2, sta, tmp) {
++ for_each_sta_info(local, hdr->addr2, sta, tmp) {
+ if (!prev_sta) {
+ prev_sta = sta;
+ continue;
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -67,12 +67,10 @@
+
+ static const struct rhashtable_params sta_rht_params = {
+ .nelem_hint = 3, /* start small */
+- .insecure_elasticity = true, /* Disable chain-length checks. */
+ .automatic_shrinking = true,
+ .head_offset = offsetof(struct sta_info, hash_node),
+ .key_offset = offsetof(struct sta_info, addr),
+ .key_len = ETH_ALEN,
+- .hashfn = sta_addr_hash,
+ .max_size = CPTCFG_MAC80211_STA_HASH_MAX_SIZE,
+ };
+
+@@ -80,8 +78,8 @@ static const struct rhashtable_params st
+ static int sta_info_hash_del(struct ieee80211_local *local,
+ struct sta_info *sta)
+ {
+- return rhashtable_remove_fast(&local->sta_hash, &sta->hash_node,
+- sta_rht_params);
++ return rhltable_remove(&local->sta_hash, &sta->hash_node,
++ sta_rht_params);
+ }
+
+ static void __cleanup_single_sta(struct sta_info *sta)
+@@ -157,19 +155,22 @@ static void cleanup_single_sta(struct st
+ sta_info_free(local, sta);
+ }
+
++struct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local,
++ const u8 *addr)
++{
++ return rhltable_lookup(&local->sta_hash, addr, sta_rht_params);
++}
++
+ /* protected by RCU */
+ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr)
+ {
+ struct ieee80211_local *local = sdata->local;
++ struct rhlist_head *tmp;
+ struct sta_info *sta;
+- struct rhash_head *tmp;
+- const struct bucket_table *tbl;
+
+ rcu_read_lock();
+- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+-
+- for_each_sta_info(local, tbl, addr, sta, tmp) {
++ for_each_sta_info(local, addr, sta, tmp) {
+ if (sta->sdata == sdata) {
+ rcu_read_unlock();
+ /* this is safe as the caller must already hold
+@@ -190,14 +191,11 @@ struct sta_info *sta_info_get_bss(struct
+ const u8 *addr)
+ {
+ struct ieee80211_local *local = sdata->local;
++ struct rhlist_head *tmp;
+ struct sta_info *sta;
+- struct rhash_head *tmp;
+- const struct bucket_table *tbl;
+
+ rcu_read_lock();
+- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+-
+- for_each_sta_info(local, tbl, addr, sta, tmp) {
++ for_each_sta_info(local, addr, sta, tmp) {
+ if (sta->sdata == sdata ||
+ (sta->sdata->bss && sta->sdata->bss == sdata->bss)) {
+ rcu_read_unlock();
+@@ -263,8 +261,8 @@ void sta_info_free(struct ieee80211_loca
+ static int sta_info_hash_add(struct ieee80211_local *local,
+ struct sta_info *sta)
+ {
+- return rhashtable_insert_fast(&local->sta_hash, &sta->hash_node,
+- sta_rht_params);
++ return rhltable_insert(&local->sta_hash, &sta->hash_node,
++ sta_rht_params);
+ }
+
+ static void sta_deliver_ps_frames(struct work_struct *wk)
+@@ -453,9 +451,9 @@ static int sta_info_insert_check(struct
+ is_multicast_ether_addr(sta->sta.addr)))
+ return -EINVAL;
+
+- /* Strictly speaking this isn't necessary as we hold the mutex, but
+- * the rhashtable code can't really deal with that distinction. We
+- * do require the mutex for correctness though.
++ /* The RCU read lock is required by rhashtable due to
++ * asynchronous resize/rehash. We also require the mutex
++ * for correctness.
+ */
+ rcu_read_lock();
+ lockdep_assert_held(&sdata->local->sta_mtx);
+@@ -1043,16 +1041,11 @@ static void sta_info_cleanup(unsigned lo
+ round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL));
+ }
+
+-u32 sta_addr_hash(const void *key, u32 length, u32 seed)
+-{
+- return jhash(key, ETH_ALEN, seed);
+-}
+-
+ int sta_info_init(struct ieee80211_local *local)
+ {
+ int err;
+
+- err = rhashtable_init(&local->sta_hash, &sta_rht_params);
++ err = rhltable_init(&local->sta_hash, &sta_rht_params);
+ if (err)
+ return err;
+
+@@ -1068,7 +1061,7 @@ int sta_info_init(struct ieee80211_local
+ void sta_info_stop(struct ieee80211_local *local)
+ {
+ del_timer_sync(&local->sta_cleanup);
+- rhashtable_destroy(&local->sta_hash);
++ rhltable_destroy(&local->sta_hash);
+ }
+
+
+@@ -1138,17 +1131,14 @@ struct ieee80211_sta *ieee80211_find_sta
+ const u8 *localaddr)
+ {
+ struct ieee80211_local *local = hw_to_local(hw);
++ struct rhlist_head *tmp;
+ struct sta_info *sta;
+- struct rhash_head *tmp;
+- const struct bucket_table *tbl;
+-
+- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+
+ /*
+ * Just return a random station if localaddr is NULL
+ * ... first in list.
+ */
+- for_each_sta_info(local, tbl, addr, sta, tmp) {
++ for_each_sta_info(local, addr, sta, tmp) {
+ if (localaddr &&
+ !ether_addr_equal(sta->sdata->vif.addr, localaddr))
+ continue;
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -455,7 +455,7 @@ struct sta_info {
+ /* General information, mostly static */
+ struct list_head list, free_list;
+ struct rcu_head rcu_head;
+- struct rhash_head hash_node;
++ struct rhlist_head hash_node;
+ u8 addr[ETH_ALEN];
+ struct ieee80211_local *local;
+ struct ieee80211_sub_if_data *sdata;
+@@ -638,6 +638,9 @@ rcu_dereference_protected_tid_tx(struct
+ */
+ #define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
+
++struct rhlist_head *sta_info_hash_lookup(struct ieee80211_local *local,
++ const u8 *addr);
++
+ /*
+ * Get a STA info, must be under RCU read lock.
+ */
+@@ -647,17 +650,9 @@ struct sta_info *sta_info_get(struct iee
+ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr);
+
+-u32 sta_addr_hash(const void *key, u32 length, u32 seed);
+-
+-#define _sta_bucket_idx(_tbl, _a) \
+- rht_bucket_index(_tbl, sta_addr_hash(_a, ETH_ALEN, (_tbl)->hash_rnd))
+-
+-#define for_each_sta_info(local, tbl, _addr, _sta, _tmp) \
+- rht_for_each_entry_rcu(_sta, _tmp, tbl, \
+- _sta_bucket_idx(tbl, _addr), \
+- hash_node) \
+- /* compare address and run code only if it matches */ \
+- if (ether_addr_equal(_sta->addr, (_addr)))
++#define for_each_sta_info(local, _addr, _sta, _tmp) \
++ rhl_for_each_entry_rcu(_sta, _tmp, \
++ sta_info_hash_lookup(local, _addr), hash_node)
+
+ /*
+ * Get STA info by index, BROKEN!
+--- a/net/mac80211/status.c
++++ b/net/mac80211/status.c
+@@ -759,8 +759,8 @@ void ieee80211_tx_status(struct ieee8021
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ __le16 fc;
+ struct ieee80211_supported_band *sband;
++ struct rhlist_head *tmp;
+ struct sta_info *sta;
+- struct rhash_head *tmp;
+ int retry_count;
+ int rates_idx;
+ bool send_to_cooked;
+@@ -768,7 +768,6 @@ void ieee80211_tx_status(struct ieee8021
+ struct ieee80211_bar *bar;
+ int shift = 0;
+ int tid = IEEE80211_NUM_TIDS;
+- const struct bucket_table *tbl;
+
+ rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
+
+@@ -777,9 +776,7 @@ void ieee80211_tx_status(struct ieee8021
+ sband = local->hw.wiphy->bands[info->band];
+ fc = hdr->frame_control;
+
+- tbl = rht_dereference_rcu(local->sta_hash.tbl, &local->sta_hash);
+-
+- for_each_sta_info(local, tbl, hdr->addr1, sta, tmp) {
++ for_each_sta_info(local, hdr->addr1, sta, tmp) {
+ /* skip wrong virtual interface */
+ if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
+ continue;