Skip to content

Commit 2817273

Browse files
Eric Dumazetdavem330
authored andcommitted
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: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 217d32d commit 2817273

File tree

18 files changed

+89
-71
lines changed

18 files changed

+89
-71
lines changed

arch/s390/appldata/appldata_net_sum.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ static void appldata_get_net_sum_data(void *data)
8585

8686
rcu_read_lock();
8787
for_each_netdev_rcu(&init_net, dev) {
88-
const struct net_device_stats *stats = dev_get_stats(dev);
88+
struct rtnl_link_stats64 temp;
89+
const struct net_device_stats *stats = dev_get_stats(dev, &temp);
8990

9091
rx_packets += stats->rx_packets;
9192
tx_packets += stats->tx_packets;

drivers/net/bonding/bond_main.c

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3804,51 +3804,49 @@ static int bond_close(struct net_device *bond_dev)
38043804
return 0;
38053805
}
38063806

3807-
static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev)
3807+
static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
3808+
struct rtnl_link_stats64 *stats)
38083809
{
38093810
struct bonding *bond = netdev_priv(bond_dev);
3810-
struct rtnl_link_stats64 *stats = &bond_dev->stats64;
3811-
struct rtnl_link_stats64 local_stats;
3811+
struct rtnl_link_stats64 temp;
38123812
struct slave *slave;
38133813
int i;
38143814

3815-
memset(&local_stats, 0, sizeof(local_stats));
3815+
memset(stats, 0, sizeof(*stats));
38163816

38173817
read_lock_bh(&bond->lock);
38183818

38193819
bond_for_each_slave(bond, slave, i) {
38203820
const struct rtnl_link_stats64 *sstats =
3821-
dev_get_stats(slave->dev);
3822-
3823-
local_stats.rx_packets += sstats->rx_packets;
3824-
local_stats.rx_bytes += sstats->rx_bytes;
3825-
local_stats.rx_errors += sstats->rx_errors;
3826-
local_stats.rx_dropped += sstats->rx_dropped;
3827-
3828-
local_stats.tx_packets += sstats->tx_packets;
3829-
local_stats.tx_bytes += sstats->tx_bytes;
3830-
local_stats.tx_errors += sstats->tx_errors;
3831-
local_stats.tx_dropped += sstats->tx_dropped;
3832-
3833-
local_stats.multicast += sstats->multicast;
3834-
local_stats.collisions += sstats->collisions;
3835-
3836-
local_stats.rx_length_errors += sstats->rx_length_errors;
3837-
local_stats.rx_over_errors += sstats->rx_over_errors;
3838-
local_stats.rx_crc_errors += sstats->rx_crc_errors;
3839-
local_stats.rx_frame_errors += sstats->rx_frame_errors;
3840-
local_stats.rx_fifo_errors += sstats->rx_fifo_errors;
3841-
local_stats.rx_missed_errors += sstats->rx_missed_errors;
3842-
3843-
local_stats.tx_aborted_errors += sstats->tx_aborted_errors;
3844-
local_stats.tx_carrier_errors += sstats->tx_carrier_errors;
3845-
local_stats.tx_fifo_errors += sstats->tx_fifo_errors;
3846-
local_stats.tx_heartbeat_errors += sstats->tx_heartbeat_errors;
3847-
local_stats.tx_window_errors += sstats->tx_window_errors;
3821+
dev_get_stats(slave->dev, &temp);
3822+
3823+
stats->rx_packets += sstats->rx_packets;
3824+
stats->rx_bytes += sstats->rx_bytes;
3825+
stats->rx_errors += sstats->rx_errors;
3826+
stats->rx_dropped += sstats->rx_dropped;
3827+
3828+
stats->tx_packets += sstats->tx_packets;
3829+
stats->tx_bytes += sstats->tx_bytes;
3830+
stats->tx_errors += sstats->tx_errors;
3831+
stats->tx_dropped += sstats->tx_dropped;
3832+
3833+
stats->multicast += sstats->multicast;
3834+
stats->collisions += sstats->collisions;
3835+
3836+
stats->rx_length_errors += sstats->rx_length_errors;
3837+
stats->rx_over_errors += sstats->rx_over_errors;
3838+
stats->rx_crc_errors += sstats->rx_crc_errors;
3839+
stats->rx_frame_errors += sstats->rx_frame_errors;
3840+
stats->rx_fifo_errors += sstats->rx_fifo_errors;
3841+
stats->rx_missed_errors += sstats->rx_missed_errors;
3842+
3843+
stats->tx_aborted_errors += sstats->tx_aborted_errors;
3844+
stats->tx_carrier_errors += sstats->tx_carrier_errors;
3845+
stats->tx_fifo_errors += sstats->tx_fifo_errors;
3846+
stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
3847+
stats->tx_window_errors += sstats->tx_window_errors;
38483848
}
38493849

3850-
memcpy(stats, &local_stats, sizeof(struct net_device_stats));
3851-
38523850
read_unlock_bh(&bond->lock);
38533851

38543852
return stats;

drivers/net/ixgbe/ixgbe_ethtool.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ struct ixgbe_stats {
5555
offsetof(struct ixgbe_adapter, m)
5656
#define IXGBE_NETDEV_STAT(m) NETDEV_STATS, \
5757
sizeof(((struct net_device *)0)->m), \
58-
offsetof(struct net_device, m)
58+
offsetof(struct net_device, m) - offsetof(struct net_device, stats)
5959

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

10051007
ixgbe_update_stats(adapter);
1006-
dev_get_stats(netdev);
1008+
net_stats = dev_get_stats(netdev, &temp);
10071009
for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
10081010
switch (ixgbe_gstrings_stats[i].type) {
10091011
case NETDEV_STATS:
1010-
p = (char *) netdev +
1012+
p = (char *) net_stats +
10111013
ixgbe_gstrings_stats[i].stat_offset;
10121014
break;
10131015
case IXGBE_STATS:

drivers/net/loopback.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,10 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
9898
return NETDEV_TX_OK;
9999
}
100100

101-
static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev)
101+
static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
102+
struct rtnl_link_stats64 *stats)
102103
{
103104
const struct pcpu_lstats __percpu *pcpu_lstats;
104-
struct rtnl_link_stats64 *stats = &dev->stats64;
105105
u64 bytes = 0;
106106
u64 packets = 0;
107107
u64 drops = 0;

drivers/net/macvlan.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,12 +431,12 @@ static void macvlan_uninit(struct net_device *dev)
431431
free_percpu(vlan->rx_stats);
432432
}
433433

434-
static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev)
434+
static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
435+
struct rtnl_link_stats64 *stats)
435436
{
436-
struct rtnl_link_stats64 *stats = &dev->stats64;
437437
struct macvlan_dev *vlan = netdev_priv(dev);
438438

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

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

drivers/net/sfc/efx.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,11 +1533,10 @@ static int efx_net_stop(struct net_device *net_dev)
15331533
}
15341534

15351535
/* Context: process, dev_base_lock or RTNL held, non-blocking. */
1536-
static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev)
1536+
static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats)
15371537
{
15381538
struct efx_nic *efx = netdev_priv(net_dev);
15391539
struct efx_mac_stats *mac_stats = &efx->mac_stats;
1540-
struct rtnl_link_stats64 *stats = &net_dev->stats64;
15411540

15421541
spin_lock_bh(&efx->stats_lock);
15431542
efx->type->update_stats(efx);

drivers/net/sfc/ethtool.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,12 +469,13 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
469469
struct efx_mac_stats *mac_stats = &efx->mac_stats;
470470
struct efx_ethtool_stat *stat;
471471
struct efx_channel *channel;
472+
struct rtnl_link_stats64 temp;
472473
int i;
473474

474475
EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
475476

476477
/* Update MAC and NIC statistics */
477-
dev_get_stats(net_dev);
478+
dev_get_stats(net_dev, &temp);
478479

479480
/* Fill detailed statistics buffer */
480481
for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {

drivers/parisc/led.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,13 @@ static __inline__ int led_get_net_activity(void)
355355
rcu_read_lock();
356356
for_each_netdev_rcu(&init_net, dev) {
357357
const struct net_device_stats *stats;
358+
struct rtnl_link_stats64 temp;
358359
struct in_device *in_dev = __in_dev_get_rcu(dev);
359360
if (!in_dev || !in_dev->ifa_list)
360361
continue;
361362
if (ipv4_is_loopback(in_dev->ifa_list->ifa_local))
362363
continue;
363-
stats = dev_get_stats(dev);
364+
stats = dev_get_stats(dev, &temp);
364365
rx_total += stats->rx_packets;
365366
tx_total += stats->tx_packets;
366367
}

drivers/scsi/fcoe/fcoe.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2653,6 +2653,7 @@ static void fcoe_get_lesb(struct fc_lport *lport,
26532653
u32 lfc, vlfc, mdac;
26542654
struct fcoe_dev_stats *devst;
26552655
struct fcoe_fc_els_lesb *lesb;
2656+
struct rtnl_link_stats64 temp;
26562657
struct net_device *netdev = fcoe_netdev(lport);
26572658

26582659
lfc = 0;
@@ -2669,7 +2670,7 @@ static void fcoe_get_lesb(struct fc_lport *lport,
26692670
lesb->lesb_link_fail = htonl(lfc);
26702671
lesb->lesb_vlink_fail = htonl(vlfc);
26712672
lesb->lesb_miss_fka = htonl(mdac);
2672-
lesb->lesb_fcs_error = htonl(dev_get_stats(netdev)->rx_crc_errors);
2673+
lesb->lesb_fcs_error = htonl(dev_get_stats(netdev, &temp)->rx_crc_errors);
26732674
}
26742675

26752676
/**

drivers/staging/batman-adv/hard-interface.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
440440
struct batman_packet *batman_packet;
441441
struct batman_if *batman_if;
442442
struct net_device_stats *stats;
443+
struct rtnl_link_stats64 temp;
443444
int ret;
444445

445446
skb = skb_share_check(skb, GFP_ATOMIC);
@@ -468,7 +469,7 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
468469
if (batman_if->if_status != IF_ACTIVE)
469470
goto err_free;
470471

471-
stats = (struct net_device_stats *)dev_get_stats(skb->dev);
472+
stats = (struct net_device_stats *)dev_get_stats(skb->dev, &temp);
472473
if (stats) {
473474
stats->rx_packets++;
474475
stats->rx_bytes += skb->len;

0 commit comments

Comments
 (0)