]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/bonding/bond_main.c
bonding: fix race that causes invalid statistics
[linux-2.6-omap-h63xx.git] / drivers / net / bonding / bond_main.c
index 81b45740ed77079ea2e6f8671aee9b150105a014..8a8d5c3de9e35b89b0e9433bf1323aba3a6726c1 100644 (file)
@@ -3775,41 +3775,44 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
 {
        struct bonding *bond = bond_dev->priv;
        struct net_device_stats *stats = &(bond->stats), *sstats;
+       struct net_device_stats local_stats;
        struct slave *slave;
        int i;
 
-       memset(stats, 0, sizeof(struct net_device_stats));
+       memset(&local_stats, 0, sizeof(struct net_device_stats));
 
        read_lock_bh(&bond->lock);
 
        bond_for_each_slave(bond, slave, i) {
                sstats = slave->dev->get_stats(slave->dev);
-               stats->rx_packets += sstats->rx_packets;
-               stats->rx_bytes += sstats->rx_bytes;
-               stats->rx_errors += sstats->rx_errors;
-               stats->rx_dropped += sstats->rx_dropped;
-
-               stats->tx_packets += sstats->tx_packets;
-               stats->tx_bytes += sstats->tx_bytes;
-               stats->tx_errors += sstats->tx_errors;
-               stats->tx_dropped += sstats->tx_dropped;
-
-               stats->multicast += sstats->multicast;
-               stats->collisions += sstats->collisions;
-
-               stats->rx_length_errors += sstats->rx_length_errors;
-               stats->rx_over_errors += sstats->rx_over_errors;
-               stats->rx_crc_errors += sstats->rx_crc_errors;
-               stats->rx_frame_errors += sstats->rx_frame_errors;
-               stats->rx_fifo_errors += sstats->rx_fifo_errors;
-               stats->rx_missed_errors += sstats->rx_missed_errors;
-
-               stats->tx_aborted_errors += sstats->tx_aborted_errors;
-               stats->tx_carrier_errors += sstats->tx_carrier_errors;
-               stats->tx_fifo_errors += sstats->tx_fifo_errors;
-               stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
-               stats->tx_window_errors += sstats->tx_window_errors;
-       }
+               local_stats.rx_packets += sstats->rx_packets;
+               local_stats.rx_bytes += sstats->rx_bytes;
+               local_stats.rx_errors += sstats->rx_errors;
+               local_stats.rx_dropped += sstats->rx_dropped;
+
+               local_stats.tx_packets += sstats->tx_packets;
+               local_stats.tx_bytes += sstats->tx_bytes;
+               local_stats.tx_errors += sstats->tx_errors;
+               local_stats.tx_dropped += sstats->tx_dropped;
+
+               local_stats.multicast += sstats->multicast;
+               local_stats.collisions += sstats->collisions;
+
+               local_stats.rx_length_errors += sstats->rx_length_errors;
+               local_stats.rx_over_errors += sstats->rx_over_errors;
+               local_stats.rx_crc_errors += sstats->rx_crc_errors;
+               local_stats.rx_frame_errors += sstats->rx_frame_errors;
+               local_stats.rx_fifo_errors += sstats->rx_fifo_errors;
+               local_stats.rx_missed_errors += sstats->rx_missed_errors;
+
+               local_stats.tx_aborted_errors += sstats->tx_aborted_errors;
+               local_stats.tx_carrier_errors += sstats->tx_carrier_errors;
+               local_stats.tx_fifo_errors += sstats->tx_fifo_errors;
+               local_stats.tx_heartbeat_errors += sstats->tx_heartbeat_errors;
+               local_stats.tx_window_errors += sstats->tx_window_errors;
+       }
+
+       memcpy(stats, &local_stats, sizeof(struct net_device_stats));
 
        read_unlock_bh(&bond->lock);