Commit ef04a297 authored by Johannes Berg's avatar Johannes Berg

mac80211: handle station TX latency allocation errors

When the station's TX latency data structures need to be
allocated, handle failures properly and also free all the
structures if there are any other problems.

Move the allocation code up so that allocation failures
don't trigger rate control algorithm calls.
Reported-by: default avatarZHAO Gang <gamerh2o@gmail.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 4cd3c4ec
...@@ -300,6 +300,35 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, ...@@ -300,6 +300,35 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
if (!sta) if (!sta)
return NULL; return NULL;
rcu_read_lock();
tx_latency = rcu_dereference(local->tx_latency);
/* init stations Tx latency statistics && TID bins */
if (tx_latency) {
sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *
sizeof(struct ieee80211_tx_latency_stat),
GFP_ATOMIC);
if (!sta->tx_lat) {
rcu_read_unlock();
goto free;
}
if (tx_latency->n_ranges) {
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
/* size of bins is size of the ranges +1 */
sta->tx_lat[i].bin_count =
tx_latency->n_ranges + 1;
sta->tx_lat[i].bins =
kcalloc(sta->tx_lat[i].bin_count,
sizeof(u32), GFP_ATOMIC);
if (!sta->tx_lat[i].bins) {
rcu_read_unlock();
goto free;
}
}
}
}
rcu_read_unlock();
spin_lock_init(&sta->lock); spin_lock_init(&sta->lock);
INIT_WORK(&sta->drv_unblock_wk, sta_unblock); INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
...@@ -324,10 +353,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, ...@@ -324,10 +353,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++) for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
ewma_init(&sta->chain_signal_avg[i], 1024, 8); ewma_init(&sta->chain_signal_avg[i], 1024, 8);
if (sta_prepare_rate_control(local, sta, gfp)) { if (sta_prepare_rate_control(local, sta, gfp))
kfree(sta); goto free;
return NULL;
}
for (i = 0; i < IEEE80211_NUM_TIDS; i++) { for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
/* /*
...@@ -371,34 +398,17 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, ...@@ -371,34 +398,17 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
} }
} }
rcu_read_lock();
tx_latency = rcu_dereference(local->tx_latency);
/* init stations Tx latency statistics && TID bins */
if (tx_latency)
sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *
sizeof(struct ieee80211_tx_latency_stat),
GFP_ATOMIC);
/*
* if Tx latency and bins are enabled and the previous allocation
* succeeded
*/
if (tx_latency && tx_latency->n_ranges && sta->tx_lat)
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
/* size of bins is size of the ranges +1 */
sta->tx_lat[i].bin_count =
tx_latency->n_ranges + 1;
sta->tx_lat[i].bins = kcalloc(sta->tx_lat[i].bin_count,
sizeof(u32),
GFP_ATOMIC);
}
rcu_read_unlock();
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
return sta; return sta;
free:
if (sta->tx_lat) {
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
kfree(sta->tx_lat[i].bins);
kfree(sta->tx_lat);
}
kfree(sta);
return NULL;
} }
static int sta_info_insert_check(struct sta_info *sta) static int sta_info_insert_check(struct sta_info *sta)
......
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