mac80211: provide race-free 64-bit traffic counters

Make the TX bytes/packets counters race-free by keeping
them per AC so concurrent TX on queues can't cause lost
or wrong updates. This works since each station belongs
to a single interface. While at it also make the bytes
counters 64-bit.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2013-02-05 10:55:21 +01:00
parent 87f59c70ce
commit 560d268220
3 changed files with 25 additions and 14 deletions

View file

@ -445,12 +445,14 @@ static 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;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct timespec uptime; struct timespec uptime;
u64 packets = 0;
int ac;
sinfo->generation = sdata->local->sta_generation; sinfo->generation = sdata->local->sta_generation;
sinfo->filled = STATION_INFO_INACTIVE_TIME | sinfo->filled = STATION_INFO_INACTIVE_TIME |
STATION_INFO_RX_BYTES | STATION_INFO_RX_BYTES64 |
STATION_INFO_TX_BYTES | STATION_INFO_TX_BYTES64 |
STATION_INFO_RX_PACKETS | STATION_INFO_RX_PACKETS |
STATION_INFO_TX_PACKETS | STATION_INFO_TX_PACKETS |
STATION_INFO_TX_RETRIES | STATION_INFO_TX_RETRIES |
@ -467,10 +469,14 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
sinfo->connected_time = uptime.tv_sec - sta->last_connected; sinfo->connected_time = uptime.tv_sec - sta->last_connected;
sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
sinfo->tx_bytes = 0;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
sinfo->tx_bytes += sta->tx_bytes[ac];
packets += sta->tx_packets[ac];
}
sinfo->tx_packets = packets;
sinfo->rx_bytes = sta->rx_bytes; sinfo->rx_bytes = sta->rx_bytes;
sinfo->tx_bytes = sta->tx_bytes;
sinfo->rx_packets = sta->rx_packets; sinfo->rx_packets = sta->rx_packets;
sinfo->tx_packets = sta->tx_packets;
sinfo->tx_retries = sta->tx_retry_count; sinfo->tx_retries = sta->tx_retry_count;
sinfo->tx_failed = sta->tx_retry_failed; sinfo->tx_failed = sta->tx_retry_failed;
sinfo->rx_dropped_misc = sta->rx_dropped; sinfo->rx_dropped_misc = sta->rx_dropped;
@ -598,8 +604,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
data[i++] += sta->rx_fragments; \ data[i++] += sta->rx_fragments; \
data[i++] += sta->rx_dropped; \ data[i++] += sta->rx_dropped; \
\ \
data[i++] += sta->tx_packets; \ data[i++] += sinfo.tx_packets; \
data[i++] += sta->tx_bytes; \ data[i++] += sinfo.tx_bytes; \
data[i++] += sta->tx_fragments; \ data[i++] += sta->tx_fragments; \
data[i++] += sta->tx_filtered_count; \ data[i++] += sta->tx_filtered_count; \
data[i++] += sta->tx_retry_failed; \ data[i++] += sta->tx_retry_failed; \
@ -621,13 +627,14 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
if (!(sta && !WARN_ON(sta->sdata->dev != dev))) if (!(sta && !WARN_ON(sta->sdata->dev != dev)))
goto do_survey; goto do_survey;
sinfo.filled = 0;
sta_set_sinfo(sta, &sinfo);
i = 0; i = 0;
ADD_STA_STATS(sta); ADD_STA_STATS(sta);
data[i++] = sta->sta_state; data[i++] = sta->sta_state;
sinfo.filled = 0;
sta_set_sinfo(sta, &sinfo);
if (sinfo.filled & STATION_INFO_TX_BITRATE) if (sinfo.filled & STATION_INFO_TX_BITRATE)
data[i] = 100000 * data[i] = 100000 *

View file

@ -333,7 +333,8 @@ struct sta_info {
unsigned long driver_buffered_tids; unsigned long driver_buffered_tids;
/* Updated from RX path only, no locking requirements */ /* Updated from RX path only, no locking requirements */
unsigned long rx_packets, rx_bytes; unsigned long rx_packets;
u64 rx_bytes;
unsigned long wep_weak_iv_count; unsigned long wep_weak_iv_count;
unsigned long last_rx; unsigned long last_rx;
long last_connected; long last_connected;
@ -353,9 +354,9 @@ struct sta_info {
unsigned int fail_avg; unsigned int fail_avg;
/* Updated from TX path only, no locking requirements */ /* Updated from TX path only, no locking requirements */
unsigned long tx_packets; u32 tx_fragments;
unsigned long tx_bytes; u64 tx_packets[IEEE80211_NUM_ACS];
unsigned long tx_fragments; u64 tx_bytes[IEEE80211_NUM_ACS];
struct ieee80211_tx_rate last_tx_rate; struct ieee80211_tx_rate last_tx_rate;
int last_rx_rate_idx; int last_rx_rate_idx;
u32 last_rx_rate_flag; u32 last_rx_rate_flag;

View file

@ -991,15 +991,18 @@ static ieee80211_tx_result debug_noinline
ieee80211_tx_h_stats(struct ieee80211_tx_data *tx) ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
{ {
struct sk_buff *skb; struct sk_buff *skb;
int ac = -1;
if (!tx->sta) if (!tx->sta)
return TX_CONTINUE; return TX_CONTINUE;
tx->sta->tx_packets++;
skb_queue_walk(&tx->skbs, skb) { skb_queue_walk(&tx->skbs, skb) {
ac = skb_get_queue_mapping(skb);
tx->sta->tx_fragments++; tx->sta->tx_fragments++;
tx->sta->tx_bytes += skb->len; tx->sta->tx_bytes[ac] += skb->len;
} }
if (ac >= 0)
tx->sta->tx_packets[ac]++;
return TX_CONTINUE; return TX_CONTINUE;
} }