diff options
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.patch | 275 |
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 0000000..4c5fff1 --- /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; |