From 1cb345220f135dcca24f01cc04cbb97a8242d419 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 2 Sep 2011 23:23:00 +0100 Subject: 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 --- drivers/net/ethernet/sfc/ethtool.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/net/ethernet/sfc/ethtool.c') diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 52c9ee4c8aa3..55a25b14d304 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -489,13 +489,14 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, const struct efx_ethtool_stat *stat; struct efx_channel *channel; struct efx_tx_queue *tx_queue; - struct rtnl_link_stats64 temp; int i; EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS); + spin_lock_bh(&efx->stats_lock); + /* Update MAC and NIC statistics */ - dev_get_stats(net_dev, &temp); + efx->type->update_stats(efx); /* Fill detailed statistics buffer */ for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) { @@ -525,6 +526,8 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, break; } } + + spin_unlock_bh(&efx->stats_lock); } static void efx_ethtool_self_test(struct net_device *net_dev, -- cgit v1.2.3-59-g8ed1b