Commit 2b1c8b0f authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

veth: Fix veth_get_stats()

veth_get_stats() can be called in parallel on several cpus.

It's better to not reset dev->stats as it could give wrong result on
one cpu. Use temporary variables, then store the final results.

Also, we should loop on every possible cpus, not only online cpus,
or cpu hotplug can suddenly give wrong veth stats.
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 56cf5483
...@@ -210,32 +210,29 @@ rx_drop: ...@@ -210,32 +210,29 @@ rx_drop:
static struct net_device_stats *veth_get_stats(struct net_device *dev) static struct net_device_stats *veth_get_stats(struct net_device *dev)
{ {
struct veth_priv *priv; struct veth_priv *priv;
struct net_device_stats *dev_stats;
int cpu; int cpu;
struct veth_net_stats *stats; struct veth_net_stats *stats, total = {0};
priv = netdev_priv(dev); priv = netdev_priv(dev);
dev_stats = &dev->stats;
dev_stats->rx_packets = 0;
dev_stats->tx_packets = 0;
dev_stats->rx_bytes = 0;
dev_stats->tx_bytes = 0;
dev_stats->tx_dropped = 0;
dev_stats->rx_dropped = 0;
for_each_online_cpu(cpu) { for_each_possible_cpu(cpu) {
stats = per_cpu_ptr(priv->stats, cpu); stats = per_cpu_ptr(priv->stats, cpu);
dev_stats->rx_packets += stats->rx_packets; total.rx_packets += stats->rx_packets;
dev_stats->tx_packets += stats->tx_packets; total.tx_packets += stats->tx_packets;
dev_stats->rx_bytes += stats->rx_bytes; total.rx_bytes += stats->rx_bytes;
dev_stats->tx_bytes += stats->tx_bytes; total.tx_bytes += stats->tx_bytes;
dev_stats->tx_dropped += stats->tx_dropped; total.tx_dropped += stats->tx_dropped;
dev_stats->rx_dropped += stats->rx_dropped; total.rx_dropped += stats->rx_dropped;
} }
dev->stats.rx_packets = total.rx_packets;
return dev_stats; dev->stats.tx_packets = total.tx_packets;
dev->stats.rx_bytes = total.rx_bytes;
dev->stats.tx_bytes = total.tx_bytes;
dev->stats.tx_dropped = total.tx_dropped;
dev->stats.rx_dropped = total.rx_dropped;
return &dev->stats;
} }
static int veth_open(struct net_device *dev) static int veth_open(struct net_device *dev)
......
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