diff options
author | Johannes Berg <johannes.berg@intel.com> | 2016-03-31 13:02:09 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2016-04-06 07:18:17 -0400 |
commit | 0f9c5a61d4b2330b12c59126aa5a9108dbfce555 (patch) | |
tree | 6d18031607d94831c71dba87fec4abfb990c6465 /net/mac80211 | |
parent | 4f6b1b3daaf167bf927174224e07efd17ed95984 (diff) |
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>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/rx.c | 6 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 72 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 5 |
3 files changed, 54 insertions, 29 deletions
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5a6c36c3aed6..2863832b0db4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1441,7 +1441,11 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1441 | ieee80211_sta_rx_notify(rx->sdata, hdr); | 1441 | ieee80211_sta_rx_notify(rx->sdata, hdr); |
1442 | 1442 | ||
1443 | sta->rx_stats.fragments++; | 1443 | sta->rx_stats.fragments++; |
1444 | |||
1445 | u64_stats_update_begin(&rx->sta->rx_stats.syncp); | ||
1444 | sta->rx_stats.bytes += rx->skb->len; | 1446 | sta->rx_stats.bytes += rx->skb->len; |
1447 | u64_stats_update_end(&rx->sta->rx_stats.syncp); | ||
1448 | |||
1445 | if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { | 1449 | if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { |
1446 | sta->rx_stats.last_signal = status->signal; | 1450 | sta->rx_stats.last_signal = status->signal; |
1447 | ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal); | 1451 | ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal); |
@@ -2124,7 +2128,9 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) | |||
2124 | * for non-QoS-data frames. Here we know it's a data | 2128 | * for non-QoS-data frames. Here we know it's a data |
2125 | * frame, so count MSDUs. | 2129 | * frame, so count MSDUs. |
2126 | */ | 2130 | */ |
2131 | u64_stats_update_begin(&rx->sta->rx_stats.syncp); | ||
2127 | rx->sta->rx_stats.msdu[rx->seqno_idx]++; | 2132 | rx->sta->rx_stats.msdu[rx->seqno_idx]++; |
2133 | u64_stats_update_end(&rx->sta->rx_stats.syncp); | ||
2128 | } | 2134 | } |
2129 | 2135 | ||
2130 | if ((sdata->vif.type == NL80211_IFTYPE_AP || | 2136 | if ((sdata->vif.type == NL80211_IFTYPE_AP || |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 0b50ae3f0b05..bdd303e8b577 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -335,6 +335,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
335 | sta->sdata = sdata; | 335 | sta->sdata = sdata; |
336 | sta->rx_stats.last_rx = jiffies; | 336 | sta->rx_stats.last_rx = jiffies; |
337 | 337 | ||
338 | u64_stats_init(&sta->rx_stats.syncp); | ||
339 | |||
338 | sta->sta_state = IEEE80211_STA_NONE; | 340 | sta->sta_state = IEEE80211_STA_NONE; |
339 | 341 | ||
340 | /* Mark TID as unreserved */ | 342 | /* Mark TID as unreserved */ |
@@ -1971,6 +1973,41 @@ static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo) | |||
1971 | sta_stats_decode_rate(sta->local, rate, rinfo); | 1973 | sta_stats_decode_rate(sta->local, rate, rinfo); |
1972 | } | 1974 | } |
1973 | 1975 | ||
1976 | static void sta_set_tidstats(struct sta_info *sta, | ||
1977 | struct cfg80211_tid_stats *tidstats, | ||
1978 | int tid) | ||
1979 | { | ||
1980 | struct ieee80211_local *local = sta->local; | ||
1981 | |||
1982 | if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) { | ||
1983 | unsigned int start; | ||
1984 | |||
1985 | do { | ||
1986 | start = u64_stats_fetch_begin(&sta->rx_stats.syncp); | ||
1987 | tidstats->rx_msdu = sta->rx_stats.msdu[tid]; | ||
1988 | } while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start)); | ||
1989 | |||
1990 | tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU); | ||
1991 | } | ||
1992 | |||
1993 | if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) { | ||
1994 | tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU); | ||
1995 | tidstats->tx_msdu = sta->tx_stats.msdu[tid]; | ||
1996 | } | ||
1997 | |||
1998 | if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) && | ||
1999 | ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { | ||
2000 | tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_RETRIES); | ||
2001 | tidstats->tx_msdu_retries = sta->status_stats.msdu_retries[tid]; | ||
2002 | } | ||
2003 | |||
2004 | if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) && | ||
2005 | ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { | ||
2006 | tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_FAILED); | ||
2007 | tidstats->tx_msdu_failed = sta->status_stats.msdu_failed[tid]; | ||
2008 | } | ||
2009 | } | ||
2010 | |||
1974 | void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | 2011 | void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) |
1975 | { | 2012 | { |
1976 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 2013 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -2025,7 +2062,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
2025 | 2062 | ||
2026 | if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) | | 2063 | if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) | |
2027 | BIT(NL80211_STA_INFO_RX_BYTES)))) { | 2064 | BIT(NL80211_STA_INFO_RX_BYTES)))) { |
2028 | sinfo->rx_bytes = sta->rx_stats.bytes; | 2065 | unsigned int start; |
2066 | |||
2067 | do { | ||
2068 | start = u64_stats_fetch_begin(&sta->rx_stats.syncp); | ||
2069 | sinfo->rx_bytes = sta->rx_stats.bytes; | ||
2070 | } while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start)); | ||
2029 | sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); | 2071 | sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64); |
2030 | } | 2072 | } |
2031 | 2073 | ||
@@ -2097,33 +2139,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) | |||
2097 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { | 2139 | for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) { |
2098 | struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i]; | 2140 | struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i]; |
2099 | 2141 | ||
2100 | if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) { | 2142 | sta_set_tidstats(sta, tidstats, i); |
2101 | tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU); | ||
2102 | tidstats->rx_msdu = sta->rx_stats.msdu[i]; | ||
2103 | } | ||
2104 | |||
2105 | if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) { | ||
2106 | tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU); | ||
2107 | tidstats->tx_msdu = sta->tx_stats.msdu[i]; | ||
2108 | } | ||
2109 | |||
2110 | if (!(tidstats->filled & | ||
2111 | BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) && | ||
2112 | ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { | ||
2113 | tidstats->filled |= | ||
2114 | BIT(NL80211_TID_STATS_TX_MSDU_RETRIES); | ||
2115 | tidstats->tx_msdu_retries = | ||
2116 | sta->status_stats.msdu_retries[i]; | ||
2117 | } | ||
2118 | |||
2119 | if (!(tidstats->filled & | ||
2120 | BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) && | ||
2121 | ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { | ||
2122 | tidstats->filled |= | ||
2123 | BIT(NL80211_TID_STATS_TX_MSDU_FAILED); | ||
2124 | tidstats->tx_msdu_failed = | ||
2125 | sta->status_stats.msdu_failed[i]; | ||
2126 | } | ||
2127 | } | 2143 | } |
2128 | 2144 | ||
2129 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | 2145 | if (ieee80211_vif_is_mesh(&sdata->vif)) { |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5549ceb9cbb3..7c23b575672e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/average.h> | 18 | #include <linux/average.h> |
19 | #include <linux/etherdevice.h> | 19 | #include <linux/etherdevice.h> |
20 | #include <linux/rhashtable.h> | 20 | #include <linux/rhashtable.h> |
21 | #include <linux/u64_stats_sync.h> | ||
21 | #include "key.h" | 22 | #include "key.h" |
22 | 23 | ||
23 | /** | 24 | /** |
@@ -444,7 +445,6 @@ struct sta_info { | |||
444 | /* Updated from RX path only, no locking requirements */ | 445 | /* Updated from RX path only, no locking requirements */ |
445 | struct { | 446 | struct { |
446 | unsigned long packets; | 447 | unsigned long packets; |
447 | u64 bytes; | ||
448 | unsigned long last_rx; | 448 | unsigned long last_rx; |
449 | unsigned long num_duplicates; | 449 | unsigned long num_duplicates; |
450 | unsigned long fragments; | 450 | unsigned long fragments; |
@@ -453,6 +453,9 @@ struct sta_info { | |||
453 | u8 chains; | 453 | u8 chains; |
454 | s8 chain_signal_last[IEEE80211_MAX_CHAINS]; | 454 | s8 chain_signal_last[IEEE80211_MAX_CHAINS]; |
455 | u16 last_rate; | 455 | u16 last_rate; |
456 | |||
457 | struct u64_stats_sync syncp; | ||
458 | u64 bytes; | ||
456 | u64 msdu[IEEE80211_NUM_TIDS + 1]; | 459 | u64 msdu[IEEE80211_NUM_TIDS + 1]; |
457 | } rx_stats; | 460 | } rx_stats; |
458 | struct { | 461 | struct { |