mac80211: fix RX u64 stats consistency on 32-bit platforms

On 32-bit platforms, the 64-bit counters we keep need to be protected
to be consistently read. Use the u64_stats_sync mechanism to do that.

In order to not end up with overly long lines, refactor the tidstats
assignments a bit.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2016-03-31 20:02:09 +03:00
parent 4f6b1b3daa
commit 0f9c5a61d4
3 changed files with 54 additions and 29 deletions

View File

@ -1441,7 +1441,11 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
ieee80211_sta_rx_notify(rx->sdata, hdr);
sta->rx_stats.fragments++;
u64_stats_update_begin(&rx->sta->rx_stats.syncp);
sta->rx_stats.bytes += rx->skb->len;
u64_stats_update_end(&rx->sta->rx_stats.syncp);
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
sta->rx_stats.last_signal = status->signal;
ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal);
@ -2124,7 +2128,9 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
* for non-QoS-data frames. Here we know it's a data
* frame, so count MSDUs.
*/
u64_stats_update_begin(&rx->sta->rx_stats.syncp);
rx->sta->rx_stats.msdu[rx->seqno_idx]++;
u64_stats_update_end(&rx->sta->rx_stats.syncp);
}
if ((sdata->vif.type == NL80211_IFTYPE_AP ||

View File

@ -335,6 +335,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->sdata = sdata;
sta->rx_stats.last_rx = jiffies;
u64_stats_init(&sta->rx_stats.syncp);
sta->sta_state = IEEE80211_STA_NONE;
/* Mark TID as unreserved */
@ -1971,6 +1973,41 @@ static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
sta_stats_decode_rate(sta->local, rate, rinfo);
}
static void sta_set_tidstats(struct sta_info *sta,
struct cfg80211_tid_stats *tidstats,
int tid)
{
struct ieee80211_local *local = sta->local;
if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
unsigned int start;
do {
start = u64_stats_fetch_begin(&sta->rx_stats.syncp);
tidstats->rx_msdu = sta->rx_stats.msdu[tid];
} while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start));
tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
}
if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
tidstats->tx_msdu = sta->tx_stats.msdu[tid];
}
if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) &&
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
tidstats->tx_msdu_retries = sta->status_stats.msdu_retries[tid];
}
if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) &&
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
tidstats->tx_msdu_failed = sta->status_stats.msdu_failed[tid];
}
}
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
@ -2025,7 +2062,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
BIT(NL80211_STA_INFO_RX_BYTES)))) {
sinfo->rx_bytes = sta->rx_stats.bytes;
unsigned int start;
do {
start = u64_stats_fetch_begin(&sta->rx_stats.syncp);
sinfo->rx_bytes = sta->rx_stats.bytes;
} while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start));
sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
}
@ -2097,33 +2139,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i];
if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
tidstats->rx_msdu = sta->rx_stats.msdu[i];
}
if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
tidstats->tx_msdu = sta->tx_stats.msdu[i];
}
if (!(tidstats->filled &
BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) &&
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
tidstats->filled |=
BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
tidstats->tx_msdu_retries =
sta->status_stats.msdu_retries[i];
}
if (!(tidstats->filled &
BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) &&
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
tidstats->filled |=
BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
tidstats->tx_msdu_failed =
sta->status_stats.msdu_failed[i];
}
sta_set_tidstats(sta, tidstats, i);
}
if (ieee80211_vif_is_mesh(&sdata->vif)) {

View File

@ -18,6 +18,7 @@
#include <linux/average.h>
#include <linux/etherdevice.h>
#include <linux/rhashtable.h>
#include <linux/u64_stats_sync.h>
#include "key.h"
/**
@ -444,7 +445,6 @@ struct sta_info {
/* Updated from RX path only, no locking requirements */
struct {
unsigned long packets;
u64 bytes;
unsigned long last_rx;
unsigned long num_duplicates;
unsigned long fragments;
@ -453,6 +453,9 @@ struct sta_info {
u8 chains;
s8 chain_signal_last[IEEE80211_MAX_CHAINS];
u16 last_rate;
struct u64_stats_sync syncp;
u64 bytes;
u64 msdu[IEEE80211_NUM_TIDS + 1];
} rx_stats;
struct {