Commit d778207b authored by Johannes Berg's avatar Johannes Berg

mac80211: optimise synchronize_net() for sta_info_flush

There's no reason to have one synchronize_net() for each
removed station, refactor the code slightly to have just
a single synchronize_net() for all stations.

Note that this is currently useless as hostapd removes
stations one by one and this coalescing never happens.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent c8782078
...@@ -794,7 +794,7 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local, ...@@ -794,7 +794,7 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
return have_buffered; return have_buffered;
} }
int __must_check __sta_info_destroy(struct sta_info *sta) static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
{ {
struct ieee80211_local *local; struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
...@@ -831,7 +831,23 @@ int __must_check __sta_info_destroy(struct sta_info *sta) ...@@ -831,7 +831,23 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
rcu_access_pointer(sdata->u.vlan.sta) == sta) rcu_access_pointer(sdata->u.vlan.sta) == sta)
RCU_INIT_POINTER(sdata->u.vlan.sta, NULL); RCU_INIT_POINTER(sdata->u.vlan.sta, NULL);
synchronize_net(); return 0;
}
static void __sta_info_destroy_part2(struct sta_info *sta)
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
int ret;
/*
* NOTE: This assumes at least synchronize_net() was done
* after _part1 and before _part2!
*/
might_sleep();
lockdep_assert_held(&local->sta_mtx);
/* now keys can no longer be reached */ /* now keys can no longer be reached */
ieee80211_free_sta_keys(local, sta); ieee80211_free_sta_keys(local, sta);
...@@ -863,6 +879,18 @@ int __must_check __sta_info_destroy(struct sta_info *sta) ...@@ -863,6 +879,18 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
ieee80211_recalc_min_chandef(sdata); ieee80211_recalc_min_chandef(sdata);
cleanup_single_sta(sta); cleanup_single_sta(sta);
}
int __must_check __sta_info_destroy(struct sta_info *sta)
{
int err = __sta_info_destroy_part1(sta);
if (err)
return err;
synchronize_net();
__sta_info_destroy_part2(sta);
return 0; return 0;
} }
...@@ -936,6 +964,7 @@ int sta_info_flush(struct ieee80211_sub_if_data *sdata) ...@@ -936,6 +964,7 @@ int sta_info_flush(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sta_info *sta, *tmp; struct sta_info *sta, *tmp;
LIST_HEAD(free_list);
int ret = 0; int ret = 0;
might_sleep(); might_sleep();
...@@ -943,10 +972,17 @@ int sta_info_flush(struct ieee80211_sub_if_data *sdata) ...@@ -943,10 +972,17 @@ int sta_info_flush(struct ieee80211_sub_if_data *sdata)
mutex_lock(&local->sta_mtx); mutex_lock(&local->sta_mtx);
list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
if (sdata == sta->sdata) { if (sdata == sta->sdata) {
WARN_ON(__sta_info_destroy(sta)); if (!WARN_ON(__sta_info_destroy_part1(sta)))
list_add(&sta->free_list, &free_list);
ret++; ret++;
} }
} }
if (!list_empty(&free_list)) {
synchronize_net();
list_for_each_entry_safe(sta, tmp, &free_list, free_list)
__sta_info_destroy_part2(sta);
}
mutex_unlock(&local->sta_mtx); mutex_unlock(&local->sta_mtx);
return ret; return ret;
......
...@@ -247,6 +247,7 @@ struct ieee80211_tx_latency_stat { ...@@ -247,6 +247,7 @@ struct ieee80211_tx_latency_stat {
* mac80211 is communicating with. * mac80211 is communicating with.
* *
* @list: global linked list entry * @list: global linked list entry
* @free_list: list entry for keeping track of stations to free
* @hnext: hash table linked list pointer * @hnext: hash table linked list pointer
* @local: pointer to the global information * @local: pointer to the global information
* @sdata: virtual interface this station belongs to * @sdata: virtual interface this station belongs to
...@@ -329,7 +330,7 @@ struct ieee80211_tx_latency_stat { ...@@ -329,7 +330,7 @@ struct ieee80211_tx_latency_stat {
*/ */
struct sta_info { struct sta_info {
/* General information, mostly static */ /* General information, mostly static */
struct list_head list; struct list_head list, free_list;
struct rcu_head rcu_head; struct rcu_head rcu_head;
struct sta_info __rcu *hnext; struct sta_info __rcu *hnext;
struct ieee80211_local *local; struct ieee80211_local *local;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment