sfc: Hold efx_nic::stats_lock while reading efx_nic::mac_stats
efx_nic::stats_lock is used to serialise stats updates, but each
reader was dropping it before it finished reading efx_nic::mac_stats.
If there were concurrent stats reads using procfs, or one using procfs
and one using ethtool, an update could race with a read. On a 32-bit
system, the reader could see word-tearing of 64-bit stats (32 bits of
the old value and 32 bits of the new).
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index eff5d30..8f4cbb6 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -1743,8 +1743,8 @@
struct efx_mac_stats *mac_stats = &efx->mac_stats;
spin_lock_bh(&efx->stats_lock);
+
efx->type->update_stats(efx);
- spin_unlock_bh(&efx->stats_lock);
stats->rx_packets = mac_stats->rx_packets;
stats->tx_packets = mac_stats->tx_packets;
@@ -1768,6 +1768,8 @@
stats->tx_errors = (stats->tx_window_errors +
mac_stats->tx_bad);
+ spin_unlock_bh(&efx->stats_lock);
+
return stats;
}