aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding
diff options
context:
space:
mode:
authorAndy Gospodarek <andy@greyhouse.net>2008-01-29 21:07:46 -0500
committerDavid S. Miller <davem@davemloft.net>2008-02-03 07:28:13 -0500
commit2439f9ebd45349246b0fec7c47e6d0e05b1357c7 (patch)
tree803000e31f25d0647d71bad8a7b9f2b7b3aea9c1 /drivers/net/bonding
parent4fe4763cd8cacd81d892193efb48b99c99c15323 (diff)
bonding: fix race that causes invalid statistics
I've seen reports of invalid stats in /proc/net/dev for bonding interfaces, and found it's a pretty easy problem to reproduce. Since the current code zeros the bonding stats when a read is requested and a pointer to that data is returned to the caller we cannot guarantee that the caller has completely accessed the data before a successive call to request the stats zeroes the stats again. This patch creates a new stack variable to keep track of the updated stats and copies the data from that variable into the bonding stats structure. This ensures that the value for any of the bonding stats should not incorrectly return zero for any of the bonding statistics. This does use more stack space and require an extra memcpy, but it seems like a fair trade-off for consistently correct bonding statistics. Signed-off-by: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: Chris Snook <csnook@redhat.com> Acked-by: Jay Vosburgh <fubar@us.ibm.com> Signed-off-by: Jeff Garzik <jeff@garzik.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_main.c57
1 files changed, 30 insertions, 27 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 81b45740ed77..8a8d5c3de9e3 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3775,41 +3775,44 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
3775{ 3775{
3776 struct bonding *bond = bond_dev->priv; 3776 struct bonding *bond = bond_dev->priv;
3777 struct net_device_stats *stats = &(bond->stats), *sstats; 3777 struct net_device_stats *stats = &(bond->stats), *sstats;
3778 struct net_device_stats local_stats;
3778 struct slave *slave; 3779 struct slave *slave;
3779 int i; 3780 int i;
3780 3781
3781 memset(stats, 0, sizeof(struct net_device_stats)); 3782 memset(&local_stats, 0, sizeof(struct net_device_stats));
3782 3783
3783 read_lock_bh(&bond->lock); 3784 read_lock_bh(&bond->lock);
3784 3785
3785 bond_for_each_slave(bond, slave, i) { 3786 bond_for_each_slave(bond, slave, i) {
3786 sstats = slave->dev->get_stats(slave->dev); 3787 sstats = slave->dev->get_stats(slave->dev);
3787 stats->rx_packets += sstats->rx_packets; 3788 local_stats.rx_packets += sstats->rx_packets;
3788 stats->rx_bytes += sstats->rx_bytes; 3789 local_stats.rx_bytes += sstats->rx_bytes;
3789 stats->rx_errors += sstats->rx_errors; 3790 local_stats.rx_errors += sstats->rx_errors;
3790 stats->rx_dropped += sstats->rx_dropped; 3791 local_stats.rx_dropped += sstats->rx_dropped;
3791 3792
3792 stats->tx_packets += sstats->tx_packets; 3793 local_stats.tx_packets += sstats->tx_packets;
3793 stats->tx_bytes += sstats->tx_bytes; 3794 local_stats.tx_bytes += sstats->tx_bytes;
3794 stats->tx_errors += sstats->tx_errors; 3795 local_stats.tx_errors += sstats->tx_errors;
3795 stats->tx_dropped += sstats->tx_dropped; 3796 local_stats.tx_dropped += sstats->tx_dropped;
3796 3797
3797 stats->multicast += sstats->multicast; 3798 local_stats.multicast += sstats->multicast;
3798 stats->collisions += sstats->collisions; 3799 local_stats.collisions += sstats->collisions;
3799 3800
3800 stats->rx_length_errors += sstats->rx_length_errors; 3801 local_stats.rx_length_errors += sstats->rx_length_errors;
3801 stats->rx_over_errors += sstats->rx_over_errors; 3802 local_stats.rx_over_errors += sstats->rx_over_errors;
3802 stats->rx_crc_errors += sstats->rx_crc_errors; 3803 local_stats.rx_crc_errors += sstats->rx_crc_errors;
3803 stats->rx_frame_errors += sstats->rx_frame_errors; 3804 local_stats.rx_frame_errors += sstats->rx_frame_errors;
3804 stats->rx_fifo_errors += sstats->rx_fifo_errors; 3805 local_stats.rx_fifo_errors += sstats->rx_fifo_errors;
3805 stats->rx_missed_errors += sstats->rx_missed_errors; 3806 local_stats.rx_missed_errors += sstats->rx_missed_errors;
3806 3807
3807 stats->tx_aborted_errors += sstats->tx_aborted_errors; 3808 local_stats.tx_aborted_errors += sstats->tx_aborted_errors;
3808 stats->tx_carrier_errors += sstats->tx_carrier_errors; 3809 local_stats.tx_carrier_errors += sstats->tx_carrier_errors;
3809 stats->tx_fifo_errors += sstats->tx_fifo_errors; 3810 local_stats.tx_fifo_errors += sstats->tx_fifo_errors;
3810 stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; 3811 local_stats.tx_heartbeat_errors += sstats->tx_heartbeat_errors;
3811 stats->tx_window_errors += sstats->tx_window_errors; 3812 local_stats.tx_window_errors += sstats->tx_window_errors;
3812 } 3813 }
3814
3815 memcpy(stats, &local_stats, sizeof(struct net_device_stats));
3813 3816
3814 read_unlock_bh(&bond->lock); 3817 read_unlock_bh(&bond->lock);
3815 3818