Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -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
	 * already removed all stations when disconnecting or similar,
	 * 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) ||
		     (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1));

@@ -861,11 +863,14 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
		cancel_work_sync(&sdata->work);
		/*
		 * When we get here, the interface is marked down.
		 * Call synchronize_rcu() to wait for the RX path
		 * should it be using the interface and enqueuing
		 * frames at this very time on another CPU.
		 * sta_info_flush_cleanup() calls rcu_barrier to
		 * wait for the station call_rcu() calls to complete,
		 * 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);

		/*
+1 −1
Original line number Diff line number Diff line
@@ -1521,7 +1521,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
	memset(ifmgd->bssid, 0, ETH_ALEN);

	/* remove AP and TDLS peers */
	sta_info_flush(sdata);
	sta_info_flush_defer(sdata);

	/* finally reset all BSS / config parameters */
	changed |= ieee80211_reset_erp_info(sdata);
+17 −10
Original line number Diff line number Diff line
@@ -104,6 +104,16 @@ static void cleanup_single_sta(struct sta_info *sta)
	 * neither mac80211 nor the driver can reference this
	 * sta struct any more except by still existing timers
	 * 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)) {
@@ -887,14 +897,8 @@ void sta_info_stop(struct ieee80211_local *local)
	del_timer_sync(&local->sta_cleanup);
}

/**
 * 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
 */
int sta_info_flush(struct ieee80211_sub_if_data *sdata)

int sta_info_flush_defer(struct ieee80211_sub_if_data *sdata)
{
	struct ieee80211_local *local = sdata->local;
	struct sta_info *sta, *tmp;
@@ -911,12 +915,15 @@ int sta_info_flush(struct ieee80211_sub_if_data *sdata)
	}
	mutex_unlock(&local->sta_mtx);

	return ret;
}

void sta_info_flush_cleanup(struct ieee80211_sub_if_data *sdata)
{
	rcu_barrier();

	ieee80211_cleanup_sdata_stas(sdata);
	cancel_work_sync(&sdata->cleanup_stations_wk);

	return ret;
}

void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
+19 −1
Original line number Diff line number Diff line
@@ -548,7 +548,25 @@ void sta_info_recalc_tim(struct sta_info *sta);

void sta_info_init(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,
			  const struct ieee80211_tx_rate *rate,
			  struct rate_info *rinfo);