Commit 2439f9eb authored by Andy Gospodarek's avatar Andy Gospodarek Committed by David S. Miller

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: default avatarAndy Gospodarek <andy@greyhouse.net>
Signed-off-by: default avatarChris Snook <csnook@redhat.com>
Acked-by: default avatarJay Vosburgh <fubar@us.ibm.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4fe4763c
...@@ -3775,41 +3775,44 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) ...@@ -3775,41 +3775,44 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
{ {
struct bonding *bond = bond_dev->priv; struct bonding *bond = bond_dev->priv;
struct net_device_stats *stats = &(bond->stats), *sstats; struct net_device_stats *stats = &(bond->stats), *sstats;
struct net_device_stats local_stats;
struct slave *slave; struct slave *slave;
int i; int i;
memset(stats, 0, sizeof(struct net_device_stats)); memset(&local_stats, 0, sizeof(struct net_device_stats));
read_lock_bh(&bond->lock); read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) { bond_for_each_slave(bond, slave, i) {
sstats = slave->dev->get_stats(slave->dev); sstats = slave->dev->get_stats(slave->dev);
stats->rx_packets += sstats->rx_packets; local_stats.rx_packets += sstats->rx_packets;
stats->rx_bytes += sstats->rx_bytes; local_stats.rx_bytes += sstats->rx_bytes;
stats->rx_errors += sstats->rx_errors; local_stats.rx_errors += sstats->rx_errors;
stats->rx_dropped += sstats->rx_dropped; local_stats.rx_dropped += sstats->rx_dropped;
stats->tx_packets += sstats->tx_packets; local_stats.tx_packets += sstats->tx_packets;
stats->tx_bytes += sstats->tx_bytes; local_stats.tx_bytes += sstats->tx_bytes;
stats->tx_errors += sstats->tx_errors; local_stats.tx_errors += sstats->tx_errors;
stats->tx_dropped += sstats->tx_dropped; local_stats.tx_dropped += sstats->tx_dropped;
stats->multicast += sstats->multicast; local_stats.multicast += sstats->multicast;
stats->collisions += sstats->collisions; local_stats.collisions += sstats->collisions;
stats->rx_length_errors += sstats->rx_length_errors; local_stats.rx_length_errors += sstats->rx_length_errors;
stats->rx_over_errors += sstats->rx_over_errors; local_stats.rx_over_errors += sstats->rx_over_errors;
stats->rx_crc_errors += sstats->rx_crc_errors; local_stats.rx_crc_errors += sstats->rx_crc_errors;
stats->rx_frame_errors += sstats->rx_frame_errors; local_stats.rx_frame_errors += sstats->rx_frame_errors;
stats->rx_fifo_errors += sstats->rx_fifo_errors; local_stats.rx_fifo_errors += sstats->rx_fifo_errors;
stats->rx_missed_errors += sstats->rx_missed_errors; local_stats.rx_missed_errors += sstats->rx_missed_errors;
stats->tx_aborted_errors += sstats->tx_aborted_errors; local_stats.tx_aborted_errors += sstats->tx_aborted_errors;
stats->tx_carrier_errors += sstats->tx_carrier_errors; local_stats.tx_carrier_errors += sstats->tx_carrier_errors;
stats->tx_fifo_errors += sstats->tx_fifo_errors; local_stats.tx_fifo_errors += sstats->tx_fifo_errors;
stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors; local_stats.tx_heartbeat_errors += sstats->tx_heartbeat_errors;
stats->tx_window_errors += sstats->tx_window_errors; local_stats.tx_window_errors += sstats->tx_window_errors;
} }
memcpy(stats, &local_stats, sizeof(struct net_device_stats));
read_unlock_bh(&bond->lock); read_unlock_bh(&bond->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment