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:
@@ -1441,7 +1441,11 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
|
|||||||
ieee80211_sta_rx_notify(rx->sdata, hdr);
|
ieee80211_sta_rx_notify(rx->sdata, hdr);
|
||||||
|
|
||||||
sta->rx_stats.fragments++;
|
sta->rx_stats.fragments++;
|
||||||
|
|
||||||
|
u64_stats_update_begin(&rx->sta->rx_stats.syncp);
|
||||||
sta->rx_stats.bytes += rx->skb->len;
|
sta->rx_stats.bytes += rx->skb->len;
|
||||||
|
u64_stats_update_end(&rx->sta->rx_stats.syncp);
|
||||||
|
|
||||||
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
|
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
|
||||||
sta->rx_stats.last_signal = status->signal;
|
sta->rx_stats.last_signal = status->signal;
|
||||||
ewma_signal_add(&sta->rx_stats_avg.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
|
* for non-QoS-data frames. Here we know it's a data
|
||||||
* frame, so count MSDUs.
|
* frame, so count MSDUs.
|
||||||
*/
|
*/
|
||||||
|
u64_stats_update_begin(&rx->sta->rx_stats.syncp);
|
||||||
rx->sta->rx_stats.msdu[rx->seqno_idx]++;
|
rx->sta->rx_stats.msdu[rx->seqno_idx]++;
|
||||||
|
u64_stats_update_end(&rx->sta->rx_stats.syncp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
|
if ((sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||||
|
|||||||
@@ -335,6 +335,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
|
|||||||
sta->sdata = sdata;
|
sta->sdata = sdata;
|
||||||
sta->rx_stats.last_rx = jiffies;
|
sta->rx_stats.last_rx = jiffies;
|
||||||
|
|
||||||
|
u64_stats_init(&sta->rx_stats.syncp);
|
||||||
|
|
||||||
sta->sta_state = IEEE80211_STA_NONE;
|
sta->sta_state = IEEE80211_STA_NONE;
|
||||||
|
|
||||||
/* Mark TID as unreserved */
|
/* 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);
|
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)
|
void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
|
||||||
{
|
{
|
||||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
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) |
|
if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
|
||||||
BIT(NL80211_STA_INFO_RX_BYTES)))) {
|
BIT(NL80211_STA_INFO_RX_BYTES)))) {
|
||||||
|
unsigned int start;
|
||||||
|
|
||||||
|
do {
|
||||||
|
start = u64_stats_fetch_begin(&sta->rx_stats.syncp);
|
||||||
sinfo->rx_bytes = sta->rx_stats.bytes;
|
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);
|
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++) {
|
for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
|
||||||
struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i];
|
struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i];
|
||||||
|
|
||||||
if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
|
sta_set_tidstats(sta, tidstats, i);
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
if (ieee80211_vif_is_mesh(&sdata->vif)) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <linux/average.h>
|
#include <linux/average.h>
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <linux/rhashtable.h>
|
#include <linux/rhashtable.h>
|
||||||
|
#include <linux/u64_stats_sync.h>
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -444,7 +445,6 @@ struct sta_info {
|
|||||||
/* Updated from RX path only, no locking requirements */
|
/* Updated from RX path only, no locking requirements */
|
||||||
struct {
|
struct {
|
||||||
unsigned long packets;
|
unsigned long packets;
|
||||||
u64 bytes;
|
|
||||||
unsigned long last_rx;
|
unsigned long last_rx;
|
||||||
unsigned long num_duplicates;
|
unsigned long num_duplicates;
|
||||||
unsigned long fragments;
|
unsigned long fragments;
|
||||||
@@ -453,6 +453,9 @@ struct sta_info {
|
|||||||
u8 chains;
|
u8 chains;
|
||||||
s8 chain_signal_last[IEEE80211_MAX_CHAINS];
|
s8 chain_signal_last[IEEE80211_MAX_CHAINS];
|
||||||
u16 last_rate;
|
u16 last_rate;
|
||||||
|
|
||||||
|
struct u64_stats_sync syncp;
|
||||||
|
u64 bytes;
|
||||||
u64 msdu[IEEE80211_NUM_TIDS + 1];
|
u64 msdu[IEEE80211_NUM_TIDS + 1];
|
||||||
} rx_stats;
|
} rx_stats;
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user