Commit 051007d9 authored by Johannes Berg's avatar Johannes Berg

mac80211: optimise roaming time again

The last fixes re-added the RCU synchronize penalty
on roaming to fix the races. Split up sta_info_flush()
now to get rid of that again, and let managed mode
(and only it) delay the actual destruction.
Tested-by: default avatarBen Greear <greearb@candelatech.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 09f4114e
...@@ -775,8 +775,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -775,8 +775,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
* This is relevant only in WDS mode, in all other modes we've * This is relevant only in WDS mode, in all other modes we've
* already removed all stations when disconnecting or similar, * already removed all stations when disconnecting or similar,
* so warn otherwise. * so warn otherwise.
*
* We call sta_info_flush_cleanup() later, to combine RCU waits.
*/ */
flushed = sta_info_flush(sdata); flushed = sta_info_flush_defer(sdata);
WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) || WARN_ON_ONCE((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
(sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)); (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1));
...@@ -861,11 +863,14 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, ...@@ -861,11 +863,14 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
cancel_work_sync(&sdata->work); cancel_work_sync(&sdata->work);
/* /*
* When we get here, the interface is marked down. * When we get here, the interface is marked down.
* Call synchronize_rcu() to wait for the RX path * sta_info_flush_cleanup() calls rcu_barrier to
* should it be using the interface and enqueuing * wait for the station call_rcu() calls to complete,
* frames at this very time on another CPU. * here we require it to wait for the RX path in case
* it is using the interface and enqueuing frames at
* this very time on another CPU.
*/ */
synchronize_rcu(); sta_info_flush_cleanup(sdata);
skb_queue_purge(&sdata->skb_queue); skb_queue_purge(&sdata->skb_queue);
/* /*
......
...@@ -1521,7 +1521,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ...@@ -1521,7 +1521,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
memset(ifmgd->bssid, 0, ETH_ALEN); memset(ifmgd->bssid, 0, ETH_ALEN);
/* remove AP and TDLS peers */ /* remove AP and TDLS peers */
sta_info_flush(sdata); sta_info_flush_defer(sdata);
/* finally reset all BSS / config parameters */ /* finally reset all BSS / config parameters */
changed |= ieee80211_reset_erp_info(sdata); changed |= ieee80211_reset_erp_info(sdata);
......
...@@ -104,6 +104,16 @@ static void cleanup_single_sta(struct sta_info *sta) ...@@ -104,6 +104,16 @@ static void cleanup_single_sta(struct sta_info *sta)
* neither mac80211 nor the driver can reference this * neither mac80211 nor the driver can reference this
* sta struct any more except by still existing timers * sta struct any more except by still existing timers
* associated with this station that we clean up below. * associated with this station that we clean up below.
*
* Note though that this still uses the sdata and even
* calls the driver in AP and mesh mode, so interfaces
* of those types mush use call sta_info_flush_cleanup()
* (typically via sta_info_flush()) before deconfiguring
* the driver.
*
* In station mode, nothing happens here so it doesn't
* have to (and doesn't) do that, this is intentional to
* speed up roaming.
*/ */
if (test_sta_flag(sta, WLAN_STA_PS_STA)) { if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
...@@ -887,14 +897,8 @@ void sta_info_stop(struct ieee80211_local *local) ...@@ -887,14 +897,8 @@ void sta_info_stop(struct ieee80211_local *local)
del_timer_sync(&local->sta_cleanup); del_timer_sync(&local->sta_cleanup);
} }
/**
* sta_info_flush - flush matching STA entries from the STA table int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata)
*
* Returns the number of removed STA entries.
*
* @sdata: sdata to remove all stations from
*/
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;
...@@ -911,12 +915,15 @@ int sta_info_flush(struct ieee80211_sub_if_data *sdata) ...@@ -911,12 +915,15 @@ int sta_info_flush(struct ieee80211_sub_if_data *sdata)
} }
mutex_unlock(&local->sta_mtx); mutex_unlock(&local->sta_mtx);
return ret;
}
void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata)
{
rcu_barrier(); rcu_barrier();
ieee80211_cleanup_sdata_stas(sdata); ieee80211_cleanup_sdata_stas(sdata);
cancel_work_sync(&sdata->cleanup_stations_wk); cancel_work_sync(&sdata->cleanup_stations_wk);
return ret;
} }
void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
......
...@@ -548,7 +548,25 @@ void sta_info_recalc_tim(struct sta_info *sta); ...@@ -548,7 +548,25 @@ void sta_info_recalc_tim(struct sta_info *sta);
void sta_info_init(struct ieee80211_local *local); void sta_info_init(struct ieee80211_local *local);
void sta_info_stop(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local);
int sta_info_flush(struct ieee80211_sub_if_data *sdata); int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata);
void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata);
/**
* sta_info_flush - flush matching STA entries from the STA table
*
* Returns the number of removed STA entries.
*
* @sdata: sdata to remove all stations from
*/
static inline int sta_info_flush(struct ieee80211_sub_if_data *sdata)
{
int ret = sta_info_flush_defer(sdata);
sta_info_flush_cleanup(sdata);
return ret;
}
void sta_set_rate_info_tx(struct sta_info *sta, void sta_set_rate_info_tx(struct sta_info *sta,
const struct ieee80211_tx_rate *rate, const struct ieee80211_tx_rate *rate,
struct rate_info *rinfo); struct rate_info *rinfo);
......
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