mac80211: provide race-free 64-bit traffic counters
authorJohannes Berg <johannes.berg@intel.com>
Tue, 5 Feb 2013 09:55:21 +0000 (10:55 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 7 Mar 2013 13:32:18 +0000 (14:32 +0100)
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>
net/mac80211/cfg.c
net/mac80211/sta_info.h
net/mac80211/tx.c

index 1d1ddabd89caf34167fd092baf63262c9a850aef..61fc9116380daa3f101cf82d8fd6d156d34f1044 100644 (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_local *local = sdata->local;
        struct timespec uptime;
+       u64 packets = 0;
+       int ac;
 
        sinfo->generation = sdata->local->sta_generation;
 
        sinfo->filled = STATION_INFO_INACTIVE_TIME |
-                       STATION_INFO_RX_BYTES |
-                       STATION_INFO_TX_BYTES |
+                       STATION_INFO_RX_BYTES64 |
+                       STATION_INFO_TX_BYTES64 |
                        STATION_INFO_RX_PACKETS |
                        STATION_INFO_TX_PACKETS |
                        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->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->tx_bytes = sta->tx_bytes;
        sinfo->rx_packets = sta->rx_packets;
-       sinfo->tx_packets = sta->tx_packets;
        sinfo->tx_retries = sta->tx_retry_count;
        sinfo->tx_failed = sta->tx_retry_failed;
        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_dropped;           \
                                                        \
-               data[i++] += sta->tx_packets;           \
-               data[i++] += sta->tx_bytes;             \
+               data[i++] += sinfo.tx_packets;          \
+               data[i++] += sinfo.tx_bytes;            \
                data[i++] += sta->tx_fragments;         \
                data[i++] += sta->tx_filtered_count;    \
                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)))
                        goto do_survey;
 
+               sinfo.filled = 0;
+               sta_set_sinfo(sta, &sinfo);
+
                i = 0;
                ADD_STA_STATS(sta);
 
                data[i++] = sta->sta_state;
 
-               sinfo.filled = 0;
-               sta_set_sinfo(sta, &sinfo);
 
                if (sinfo.filled & STATION_INFO_TX_BITRATE)
                        data[i] = 100000 *
index e5868c32d1a3f5aab24a6ca001405eb2d3e43aa5..adc30045f99ec9f029c0bd8cfc0a4d7c75b10403 100644 (file)
@@ -333,7 +333,8 @@ struct sta_info {
        unsigned long driver_buffered_tids;
 
        /* 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 last_rx;
        long last_connected;
@@ -353,9 +354,9 @@ struct sta_info {
        unsigned int fail_avg;
 
        /* Updated from TX path only, no locking requirements */
-       unsigned long tx_packets;
-       unsigned long tx_bytes;
-       unsigned long tx_fragments;
+       u32 tx_fragments;
+       u64 tx_packets[IEEE80211_NUM_ACS];
+       u64 tx_bytes[IEEE80211_NUM_ACS];
        struct ieee80211_tx_rate last_tx_rate;
        int last_rx_rate_idx;
        u32 last_rx_rate_flag;
index 8914d2d2881aab77c5741479d6dbf516db59e3b3..3fcdf211810154aa99ae423ad4bc7c3841cabe3d 100644 (file)
@@ -991,15 +991,18 @@ static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
 {
        struct sk_buff *skb;
+       int ac = -1;
 
        if (!tx->sta)
                return TX_CONTINUE;
 
-       tx->sta->tx_packets++;
        skb_queue_walk(&tx->skbs, skb) {
+               ac = skb_get_queue_mapping(skb);
                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;
 }