Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28172739 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

net: fix 64 bit counters on 32 bit arches



There is a small possibility that a reader gets incorrect values on 32
bit arches. SNMP applications could catch incorrect counters when a
32bit high part is changed by another stats consumer/provider.

One way to solve this is to add a rtnl_link_stats64 param to all
ndo_get_stats64() methods, and also add such a parameter to
dev_get_stats().

Rule is that we are not allowed to use dev->stats64 as a temporary
storage for 64bit stats, but a caller provided area (usually on stack)

Old drivers (only providing get_stats() method) need no changes.

Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 217d32dc
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -85,7 +85,8 @@ static void appldata_get_net_sum_data(void *data)

	rcu_read_lock();
	for_each_netdev_rcu(&init_net, dev) {
		const struct net_device_stats *stats = dev_get_stats(dev);
		struct rtnl_link_stats64 temp;
		const struct net_device_stats *stats = dev_get_stats(dev, &temp);

		rx_packets += stats->rx_packets;
		tx_packets += stats->tx_packets;
+31 −33
Original line number Diff line number Diff line
@@ -3804,51 +3804,49 @@ static int bond_close(struct net_device *bond_dev)
	return 0;
}

static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev)
static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
						struct rtnl_link_stats64 *stats)
{
	struct bonding *bond = netdev_priv(bond_dev);
	struct rtnl_link_stats64 *stats = &bond_dev->stats64;
	struct rtnl_link_stats64 local_stats;
	struct rtnl_link_stats64 temp;
	struct slave *slave;
	int i;

	memset(&local_stats, 0, sizeof(local_stats));
	memset(stats, 0, sizeof(*stats));

	read_lock_bh(&bond->lock);

	bond_for_each_slave(bond, slave, i) {
		const struct rtnl_link_stats64 *sstats =
			dev_get_stats(slave->dev);

		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;
			dev_get_stats(slave->dev, &temp);

		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;
	}

	memcpy(stats, &local_stats, sizeof(struct net_device_stats));

	read_unlock_bh(&bond->lock);

	return stats;
+5 −3
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@ struct ixgbe_stats {
				offsetof(struct ixgbe_adapter, m)
#define IXGBE_NETDEV_STAT(m)	NETDEV_STATS, \
				sizeof(((struct net_device *)0)->m), \
				offsetof(struct net_device, m)
				offsetof(struct net_device, m) - offsetof(struct net_device, stats)

static struct ixgbe_stats ixgbe_gstrings_stats[] = {
	{"rx_packets", IXGBE_NETDEV_STAT(stats.rx_packets)},
@@ -998,16 +998,18 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
	struct ixgbe_adapter *adapter = netdev_priv(netdev);
	u64 *queue_stat;
	int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
	struct rtnl_link_stats64 temp;
	const struct rtnl_link_stats64 *net_stats;
	int j, k;
	int i;
	char *p = NULL;

	ixgbe_update_stats(adapter);
	dev_get_stats(netdev);
	net_stats = dev_get_stats(netdev, &temp);
	for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
		switch (ixgbe_gstrings_stats[i].type) {
		case NETDEV_STATS:
			p = (char *) netdev +
			p = (char *) net_stats +
					ixgbe_gstrings_stats[i].stat_offset;
			break;
		case IXGBE_STATS:
+2 −2
Original line number Diff line number Diff line
@@ -98,10 +98,10 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
	return NETDEV_TX_OK;
}

static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev)
static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
						      struct rtnl_link_stats64 *stats)
{
	const struct pcpu_lstats __percpu *pcpu_lstats;
	struct rtnl_link_stats64 *stats = &dev->stats64;
	u64 bytes = 0;
	u64 packets = 0;
	u64 drops = 0;
+3 −3
Original line number Diff line number Diff line
@@ -431,12 +431,12 @@ static void macvlan_uninit(struct net_device *dev)
	free_percpu(vlan->rx_stats);
}

static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev)
static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
							 struct rtnl_link_stats64 *stats)
{
	struct rtnl_link_stats64 *stats = &dev->stats64;
	struct macvlan_dev *vlan = netdev_priv(dev);

	dev_txq_stats_fold(dev, &dev->stats);
	dev_txq_stats_fold(dev, (struct net_device_stats *)stats);

	if (vlan->rx_stats) {
		struct macvlan_rx_stats *p, accum = {0};
Loading