123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- 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;
|