aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-07-07 17:58:56 -0400
committerDavid S. Miller <davem@davemloft.net>2010-07-07 17:58:56 -0400
commit28172739f0a276eb8d6ca917b3974c2edb036da3 (patch)
treeb1dc00cfa20c209992e247c6f73601f609f9ca3b
parent217d32dc5f299c483ca0d3c8cc6811c72c0339c4 (diff)
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 <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/s390/appldata/appldata_net_sum.c3
-rw-r--r--drivers/net/bonding/bond_main.c64
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c8
-rw-r--r--drivers/net/loopback.c4
-rw-r--r--drivers/net/macvlan.c6
-rw-r--r--drivers/net/sfc/efx.c3
-rw-r--r--drivers/net/sfc/ethtool.c3
-rw-r--r--drivers/parisc/led.c3
-rw-r--r--drivers/scsi/fcoe/fcoe.c3
-rw-r--r--drivers/staging/batman-adv/hard-interface.c3
-rw-r--r--drivers/usb/gadget/rndis.c3
-rw-r--r--include/linux/netdevice.h12
-rw-r--r--net/8021q/vlan_dev.c6
-rw-r--r--net/8021q/vlanproc.c3
-rw-r--r--net/bridge/br_device.c4
-rw-r--r--net/core/dev.c25
-rw-r--r--net/core/net-sysfs.c4
-rw-r--r--net/core/rtnetlink.c3
18 files changed, 89 insertions, 71 deletions
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index 9a9586f4103f..f02e89ce4df1 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -85,7 +85,8 @@ static void appldata_get_net_sum_data(void *data)
85 85
86 rcu_read_lock(); 86 rcu_read_lock();
87 for_each_netdev_rcu(&init_net, dev) { 87 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);
89 90
90 rx_packets += stats->rx_packets; 91 rx_packets += stats->rx_packets;
91 tx_packets += stats->tx_packets; 92 tx_packets += stats->tx_packets;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a95a41b74b4e..9bb9bfa225b6 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3804,51 +3804,49 @@ static int bond_close(struct net_device *bond_dev)
3804 return 0; 3804 return 0;
3805} 3805}
3806 3806
3807static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev) 3807static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
3808 struct rtnl_link_stats64 *stats)
3808{ 3809{
3809 struct bonding *bond = netdev_priv(bond_dev); 3810 struct bonding *bond = netdev_priv(bond_dev);
3810 struct rtnl_link_stats64 *stats = &bond_dev->stats64; 3811 struct rtnl_link_stats64 temp;
3811 struct rtnl_link_stats64 local_stats;
3812 struct slave *slave; 3812 struct slave *slave;
3813 int i; 3813 int i;
3814 3814
3815 memset(&local_stats, 0, sizeof(local_stats)); 3815 memset(stats, 0, sizeof(*stats));
3816 3816
3817 read_lock_bh(&bond->lock); 3817 read_lock_bh(&bond->lock);
3818 3818
3819 bond_for_each_slave(bond, slave, i) { 3819 bond_for_each_slave(bond, slave, i) {
3820 const struct rtnl_link_stats64 *sstats = 3820 const struct rtnl_link_stats64 *sstats =
3821 dev_get_stats(slave->dev); 3821 dev_get_stats(slave->dev, &temp);
3822 3822
3823 local_stats.rx_packets += sstats->rx_packets; 3823 stats->rx_packets += sstats->rx_packets;
3824 local_stats.rx_bytes += sstats->rx_bytes; 3824 stats->rx_bytes += sstats->rx_bytes;
3825 local_stats.rx_errors += sstats->rx_errors; 3825 stats->rx_errors += sstats->rx_errors;
3826 local_stats.rx_dropped += sstats->rx_dropped; 3826 stats->rx_dropped += sstats->rx_dropped;
3827 3827
3828 local_stats.tx_packets += sstats->tx_packets; 3828 stats->tx_packets += sstats->tx_packets;
3829 local_stats.tx_bytes += sstats->tx_bytes; 3829 stats->tx_bytes += sstats->tx_bytes;
3830 local_stats.tx_errors += sstats->tx_errors; 3830 stats->tx_errors += sstats->tx_errors;
3831 local_stats.tx_dropped += sstats->tx_dropped; 3831 stats->tx_dropped += sstats->tx_dropped;
3832 3832
3833 local_stats.multicast += sstats->multicast; 3833 stats->multicast += sstats->multicast;
3834 local_stats.collisions += sstats->collisions; 3834 stats->collisions += sstats->collisions;
3835 3835
3836 local_stats.rx_length_errors += sstats->rx_length_errors; 3836 stats->rx_length_errors += sstats->rx_length_errors;
3837 local_stats.rx_over_errors += sstats->rx_over_errors; 3837 stats->rx_over_errors += sstats->rx_over_errors;
3838 local_stats.rx_crc_errors += sstats->rx_crc_errors; 3838 stats->rx_crc_errors += sstats->rx_crc_errors;
3839 local_stats.rx_frame_errors += sstats->rx_frame_errors; 3839 stats->rx_frame_errors += sstats->rx_frame_errors;
3840 local_stats.rx_fifo_errors += sstats->rx_fifo_errors; 3840 stats->rx_fifo_errors += sstats->rx_fifo_errors;
3841 local_stats.rx_missed_errors += sstats->rx_missed_errors; 3841 stats->rx_missed_errors += sstats->rx_missed_errors;
3842 3842
3843 local_stats.tx_aborted_errors += sstats->tx_aborted_errors; 3843 stats->tx_aborted_errors += sstats->tx_aborted_errors;
3844 local_stats.tx_carrier_errors += sstats->tx_carrier_errors; 3844 stats->tx_carrier_errors += sstats->tx_carrier_errors;
3845 local_stats.tx_fifo_errors += sstats->tx_fifo_errors; 3845 stats->tx_fifo_errors += sstats->tx_fifo_errors;
3846 local_stats.tx_heartbeat_errors += sstats->tx_heartbeat_errors; 3846 stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
3847 local_stats.tx_window_errors += sstats->tx_window_errors; 3847 stats->tx_window_errors += sstats->tx_window_errors;
3848 } 3848 }
3849 3849
3850 memcpy(stats, &local_stats, sizeof(struct net_device_stats));
3851
3852 read_unlock_bh(&bond->lock); 3850 read_unlock_bh(&bond->lock);
3853 3851
3854 return stats; 3852 return stats;
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index b35ef36741ef..da54b38bb480 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -55,7 +55,7 @@ struct ixgbe_stats {
55 offsetof(struct ixgbe_adapter, m) 55 offsetof(struct ixgbe_adapter, m)
56#define IXGBE_NETDEV_STAT(m) NETDEV_STATS, \ 56#define IXGBE_NETDEV_STAT(m) NETDEV_STATS, \
57 sizeof(((struct net_device *)0)->m), \ 57 sizeof(((struct net_device *)0)->m), \
58 offsetof(struct net_device, m) 58 offsetof(struct net_device, m) - offsetof(struct net_device, stats)
59 59
60static struct ixgbe_stats ixgbe_gstrings_stats[] = { 60static struct ixgbe_stats ixgbe_gstrings_stats[] = {
61 {"rx_packets", IXGBE_NETDEV_STAT(stats.rx_packets)}, 61 {"rx_packets", IXGBE_NETDEV_STAT(stats.rx_packets)},
@@ -998,16 +998,18 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
998 struct ixgbe_adapter *adapter = netdev_priv(netdev); 998 struct ixgbe_adapter *adapter = netdev_priv(netdev);
999 u64 *queue_stat; 999 u64 *queue_stat;
1000 int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64); 1000 int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
1001 struct rtnl_link_stats64 temp;
1002 const struct rtnl_link_stats64 *net_stats;
1001 int j, k; 1003 int j, k;
1002 int i; 1004 int i;
1003 char *p = NULL; 1005 char *p = NULL;
1004 1006
1005 ixgbe_update_stats(adapter); 1007 ixgbe_update_stats(adapter);
1006 dev_get_stats(netdev); 1008 net_stats = dev_get_stats(netdev, &temp);
1007 for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { 1009 for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
1008 switch (ixgbe_gstrings_stats[i].type) { 1010 switch (ixgbe_gstrings_stats[i].type) {
1009 case NETDEV_STATS: 1011 case NETDEV_STATS:
1010 p = (char *) netdev + 1012 p = (char *) net_stats +
1011 ixgbe_gstrings_stats[i].stat_offset; 1013 ixgbe_gstrings_stats[i].stat_offset;
1012 break; 1014 break;
1013 case IXGBE_STATS: 1015 case IXGBE_STATS:
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 4dd0510d7a99..9a0996795321 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -98,10 +98,10 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
98 return NETDEV_TX_OK; 98 return NETDEV_TX_OK;
99} 99}
100 100
101static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev) 101static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev,
102 struct rtnl_link_stats64 *stats)
102{ 103{
103 const struct pcpu_lstats __percpu *pcpu_lstats; 104 const struct pcpu_lstats __percpu *pcpu_lstats;
104 struct rtnl_link_stats64 *stats = &dev->stats64;
105 u64 bytes = 0; 105 u64 bytes = 0;
106 u64 packets = 0; 106 u64 packets = 0;
107 u64 drops = 0; 107 u64 drops = 0;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index e6d626e78515..6112f1498940 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -431,12 +431,12 @@ static void macvlan_uninit(struct net_device *dev)
431 free_percpu(vlan->rx_stats); 431 free_percpu(vlan->rx_stats);
432} 432}
433 433
434static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev) 434static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
435 struct rtnl_link_stats64 *stats)
435{ 436{
436 struct rtnl_link_stats64 *stats = &dev->stats64;
437 struct macvlan_dev *vlan = netdev_priv(dev); 437 struct macvlan_dev *vlan = netdev_priv(dev);
438 438
439 dev_txq_stats_fold(dev, &dev->stats); 439 dev_txq_stats_fold(dev, (struct net_device_stats *)stats);
440 440
441 if (vlan->rx_stats) { 441 if (vlan->rx_stats) {
442 struct macvlan_rx_stats *p, accum = {0}; 442 struct macvlan_rx_stats *p, accum = {0};
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 35b3f2922e5c..ba674c5ca29e 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1533,11 +1533,10 @@ static int efx_net_stop(struct net_device *net_dev)
1533} 1533}
1534 1534
1535/* Context: process, dev_base_lock or RTNL held, non-blocking. */ 1535/* Context: process, dev_base_lock or RTNL held, non-blocking. */
1536static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev) 1536static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats)
1537{ 1537{
1538 struct efx_nic *efx = netdev_priv(net_dev); 1538 struct efx_nic *efx = netdev_priv(net_dev);
1539 struct efx_mac_stats *mac_stats = &efx->mac_stats; 1539 struct efx_mac_stats *mac_stats = &efx->mac_stats;
1540 struct rtnl_link_stats64 *stats = &net_dev->stats64;
1541 1540
1542 spin_lock_bh(&efx->stats_lock); 1541 spin_lock_bh(&efx->stats_lock);
1543 efx->type->update_stats(efx); 1542 efx->type->update_stats(efx);
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 3b8b0a062749..fd19d6ab97a2 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -469,12 +469,13 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
469 struct efx_mac_stats *mac_stats = &efx->mac_stats; 469 struct efx_mac_stats *mac_stats = &efx->mac_stats;
470 struct efx_ethtool_stat *stat; 470 struct efx_ethtool_stat *stat;
471 struct efx_channel *channel; 471 struct efx_channel *channel;
472 struct rtnl_link_stats64 temp;
472 int i; 473 int i;
473 474
474 EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS); 475 EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
475 476
476 /* Update MAC and NIC statistics */ 477 /* Update MAC and NIC statistics */
477 dev_get_stats(net_dev); 478 dev_get_stats(net_dev, &temp);
478 479
479 /* Fill detailed statistics buffer */ 480 /* Fill detailed statistics buffer */
480 for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) { 481 for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index 188bc8496a26..18dff43b8bd2 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -355,12 +355,13 @@ static __inline__ int led_get_net_activity(void)
355 rcu_read_lock(); 355 rcu_read_lock();
356 for_each_netdev_rcu(&init_net, dev) { 356 for_each_netdev_rcu(&init_net, dev) {
357 const struct net_device_stats *stats; 357 const struct net_device_stats *stats;
358 struct rtnl_link_stats64 temp;
358 struct in_device *in_dev = __in_dev_get_rcu(dev); 359 struct in_device *in_dev = __in_dev_get_rcu(dev);
359 if (!in_dev || !in_dev->ifa_list) 360 if (!in_dev || !in_dev->ifa_list)
360 continue; 361 continue;
361 if (ipv4_is_loopback(in_dev->ifa_list->ifa_local)) 362 if (ipv4_is_loopback(in_dev->ifa_list->ifa_local))
362 continue; 363 continue;
363 stats = dev_get_stats(dev); 364 stats = dev_get_stats(dev, &temp);
364 rx_total += stats->rx_packets; 365 rx_total += stats->rx_packets;
365 tx_total += stats->tx_packets; 366 tx_total += stats->tx_packets;
366 } 367 }
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 44a07593de56..1a429ed6da9d 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -2653,6 +2653,7 @@ static void fcoe_get_lesb(struct fc_lport *lport,
2653 u32 lfc, vlfc, mdac; 2653 u32 lfc, vlfc, mdac;
2654 struct fcoe_dev_stats *devst; 2654 struct fcoe_dev_stats *devst;
2655 struct fcoe_fc_els_lesb *lesb; 2655 struct fcoe_fc_els_lesb *lesb;
2656 struct rtnl_link_stats64 temp;
2656 struct net_device *netdev = fcoe_netdev(lport); 2657 struct net_device *netdev = fcoe_netdev(lport);
2657 2658
2658 lfc = 0; 2659 lfc = 0;
@@ -2669,7 +2670,7 @@ static void fcoe_get_lesb(struct fc_lport *lport,
2669 lesb->lesb_link_fail = htonl(lfc); 2670 lesb->lesb_link_fail = htonl(lfc);
2670 lesb->lesb_vlink_fail = htonl(vlfc); 2671 lesb->lesb_vlink_fail = htonl(vlfc);
2671 lesb->lesb_miss_fka = htonl(mdac); 2672 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);
2673} 2674}
2674 2675
2675/** 2676/**
diff --git a/drivers/staging/batman-adv/hard-interface.c b/drivers/staging/batman-adv/hard-interface.c
index 5ede9c255094..96c86c873011 100644
--- a/drivers/staging/batman-adv/hard-interface.c
+++ b/drivers/staging/batman-adv/hard-interface.c
@@ -440,6 +440,7 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
440 struct batman_packet *batman_packet; 440 struct batman_packet *batman_packet;
441 struct batman_if *batman_if; 441 struct batman_if *batman_if;
442 struct net_device_stats *stats; 442 struct net_device_stats *stats;
443 struct rtnl_link_stats64 temp;
443 int ret; 444 int ret;
444 445
445 skb = skb_share_check(skb, GFP_ATOMIC); 446 skb = skb_share_check(skb, GFP_ATOMIC);
@@ -468,7 +469,7 @@ int batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
468 if (batman_if->if_status != IF_ACTIVE) 469 if (batman_if->if_status != IF_ACTIVE)
469 goto err_free; 470 goto err_free;
470 471
471 stats = (struct net_device_stats *)dev_get_stats(skb->dev); 472 stats = (struct net_device_stats *)dev_get_stats(skb->dev, &temp);
472 if (stats) { 473 if (stats) {
473 stats->rx_packets++; 474 stats->rx_packets++;
474 stats->rx_bytes += skb->len; 475 stats->rx_bytes += skb->len;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index fb69b01c8f3a..020fa5a25fda 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -171,6 +171,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
171 int i, count; 171 int i, count;
172 rndis_query_cmplt_type *resp; 172 rndis_query_cmplt_type *resp;
173 struct net_device *net; 173 struct net_device *net;
174 struct rtnl_link_stats64 temp;
174 const struct rtnl_link_stats64 *stats; 175 const struct rtnl_link_stats64 *stats;
175 176
176 if (!r) return -ENOMEM; 177 if (!r) return -ENOMEM;
@@ -194,7 +195,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
194 resp->InformationBufferOffset = cpu_to_le32 (16); 195 resp->InformationBufferOffset = cpu_to_le32 (16);
195 196
196 net = rndis_per_dev_params[configNr].dev; 197 net = rndis_per_dev_params[configNr].dev;
197 stats = dev_get_stats(net); 198 stats = dev_get_stats(net, &temp);
198 199
199 switch (OID) { 200 switch (OID) {
200 201
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4d27368674db..60de65316fdb 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -666,7 +666,8 @@ struct netdev_rx_queue {
666 * Callback uses when the transmitter has not made any progress 666 * Callback uses when the transmitter has not made any progress
667 * for dev->watchdog ticks. 667 * for dev->watchdog ticks.
668 * 668 *
669 * struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev); 669 * struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev
670 * struct rtnl_link_stats64 *storage);
670 * struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); 671 * struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
671 * Called when a user wants to get the network device usage 672 * Called when a user wants to get the network device usage
672 * statistics. Drivers must do one of the following: 673 * statistics. Drivers must do one of the following:
@@ -733,7 +734,8 @@ struct net_device_ops {
733 struct neigh_parms *); 734 struct neigh_parms *);
734 void (*ndo_tx_timeout) (struct net_device *dev); 735 void (*ndo_tx_timeout) (struct net_device *dev);
735 736
736 struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev); 737 struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
738 struct rtnl_link_stats64 *storage);
737 struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); 739 struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
738 740
739 void (*ndo_vlan_rx_register)(struct net_device *dev, 741 void (*ndo_vlan_rx_register)(struct net_device *dev,
@@ -2139,8 +2141,10 @@ extern void netdev_features_change(struct net_device *dev);
2139/* Load a device via the kmod */ 2141/* Load a device via the kmod */
2140extern void dev_load(struct net *net, const char *name); 2142extern void dev_load(struct net *net, const char *name);
2141extern void dev_mcast_init(void); 2143extern void dev_mcast_init(void);
2142extern const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev); 2144extern const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
2143extern void dev_txq_stats_fold(const struct net_device *dev, struct net_device_stats *stats); 2145 struct rtnl_link_stats64 *storage);
2146extern void dev_txq_stats_fold(const struct net_device *dev,
2147 struct net_device_stats *stats);
2144 2148
2145extern int netdev_max_backlog; 2149extern int netdev_max_backlog;
2146extern int netdev_tstamp_prequeue; 2150extern int netdev_tstamp_prequeue;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index c6456cb842fa..7865a4ce5250 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -803,11 +803,9 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev)
803 return dev_ethtool_get_flags(vlan->real_dev); 803 return dev_ethtool_get_flags(vlan->real_dev);
804} 804}
805 805
806static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev) 806static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
807{ 807{
808 struct rtnl_link_stats64 *stats = &dev->stats64; 808 dev_txq_stats_fold(dev, (struct net_device_stats *)stats);
809
810 dev_txq_stats_fold(dev, &dev->stats);
811 809
812 if (vlan_dev_info(dev)->vlan_rx_stats) { 810 if (vlan_dev_info(dev)->vlan_rx_stats) {
813 struct vlan_rx_stats *p, accum = {0}; 811 struct vlan_rx_stats *p, accum = {0};
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index df56f5ce887c..80e280f56686 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -278,6 +278,7 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
278{ 278{
279 struct net_device *vlandev = (struct net_device *) seq->private; 279 struct net_device *vlandev = (struct net_device *) seq->private;
280 const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev); 280 const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev);
281 struct rtnl_link_stats64 temp;
281 const struct rtnl_link_stats64 *stats; 282 const struct rtnl_link_stats64 *stats;
282 static const char fmt[] = "%30s %12lu\n"; 283 static const char fmt[] = "%30s %12lu\n";
283 static const char fmt64[] = "%30s %12llu\n"; 284 static const char fmt64[] = "%30s %12llu\n";
@@ -286,7 +287,7 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
286 if (!is_vlan_dev(vlandev)) 287 if (!is_vlan_dev(vlandev))
287 return 0; 288 return 0;
288 289
289 stats = dev_get_stats(vlandev); 290 stats = dev_get_stats(vlandev, &temp);
290 seq_printf(seq, 291 seq_printf(seq,
291 "%s VID: %d REORDER_HDR: %i dev->priv_flags: %hx\n", 292 "%s VID: %d REORDER_HDR: %i dev->priv_flags: %hx\n",
292 vlandev->name, dev_info->vlan_id, 293 vlandev->name, dev_info->vlan_id,
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index edf639e96281..075c435ad22d 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -98,10 +98,10 @@ static int br_dev_stop(struct net_device *dev)
98 return 0; 98 return 0;
99} 99}
100 100
101static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev) 101static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev,
102 struct rtnl_link_stats64 *stats)
102{ 103{
103 struct net_bridge *br = netdev_priv(dev); 104 struct net_bridge *br = netdev_priv(dev);
104 struct rtnl_link_stats64 *stats = &dev->stats64;
105 struct br_cpu_netstats tmp, sum = { 0 }; 105 struct br_cpu_netstats tmp, sum = { 0 };
106 unsigned int cpu; 106 unsigned int cpu;
107 107
diff --git a/net/core/dev.c b/net/core/dev.c
index 93b8929fa21d..92482d7a87a9 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3703,7 +3703,8 @@ void dev_seq_stop(struct seq_file *seq, void *v)
3703 3703
3704static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) 3704static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
3705{ 3705{
3706 const struct rtnl_link_stats64 *stats = dev_get_stats(dev); 3706 struct rtnl_link_stats64 temp;
3707 const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
3707 3708
3708 seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu " 3709 seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
3709 "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n", 3710 "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
@@ -5281,23 +5282,29 @@ EXPORT_SYMBOL(dev_txq_stats_fold);
5281/** 5282/**
5282 * dev_get_stats - get network device statistics 5283 * dev_get_stats - get network device statistics
5283 * @dev: device to get statistics from 5284 * @dev: device to get statistics from
5285 * @storage: place to store stats
5284 * 5286 *
5285 * Get network statistics from device. The device driver may provide 5287 * Get network statistics from device. The device driver may provide
5286 * its own method by setting dev->netdev_ops->get_stats64 or 5288 * its own method by setting dev->netdev_ops->get_stats64 or
5287 * dev->netdev_ops->get_stats; otherwise the internal statistics 5289 * dev->netdev_ops->get_stats; otherwise the internal statistics
5288 * structure is used. 5290 * structure is used.
5289 */ 5291 */
5290const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev) 5292const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
5293 struct rtnl_link_stats64 *storage)
5291{ 5294{
5292 const struct net_device_ops *ops = dev->netdev_ops; 5295 const struct net_device_ops *ops = dev->netdev_ops;
5293 5296
5294 if (ops->ndo_get_stats64) 5297 if (ops->ndo_get_stats64) {
5295 return ops->ndo_get_stats64(dev); 5298 memset(storage, 0, sizeof(*storage));
5296 if (ops->ndo_get_stats) 5299 return ops->ndo_get_stats64(dev, storage);
5297 return (struct rtnl_link_stats64 *)ops->ndo_get_stats(dev); 5300 }
5298 5301 if (ops->ndo_get_stats) {
5299 dev_txq_stats_fold(dev, &dev->stats); 5302 memcpy(storage, ops->ndo_get_stats(dev), sizeof(*storage));
5300 return &dev->stats64; 5303 return storage;
5304 }
5305 memcpy(storage, &dev->stats, sizeof(*storage));
5306 dev_txq_stats_fold(dev, (struct net_device_stats *)storage);
5307 return storage;
5301} 5308}
5302EXPORT_SYMBOL(dev_get_stats); 5309EXPORT_SYMBOL(dev_get_stats);
5303 5310
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index ea3bb4c3b87d..914f42b0f039 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -330,7 +330,9 @@ static ssize_t netstat_show(const struct device *d,
330 330
331 read_lock(&dev_base_lock); 331 read_lock(&dev_base_lock);
332 if (dev_isalive(dev)) { 332 if (dev_isalive(dev)) {
333 const struct rtnl_link_stats64 *stats = dev_get_stats(dev); 333 struct rtnl_link_stats64 temp;
334 const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
335
334 ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset)); 336 ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset));
335 } 337 }
336 read_unlock(&dev_base_lock); 338 read_unlock(&dev_base_lock);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e645778e9b7e..5e773ea2201d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -791,6 +791,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
791{ 791{
792 struct ifinfomsg *ifm; 792 struct ifinfomsg *ifm;
793 struct nlmsghdr *nlh; 793 struct nlmsghdr *nlh;
794 struct rtnl_link_stats64 temp;
794 const struct rtnl_link_stats64 *stats; 795 const struct rtnl_link_stats64 *stats;
795 struct nlattr *attr; 796 struct nlattr *attr;
796 797
@@ -847,7 +848,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
847 if (attr == NULL) 848 if (attr == NULL)
848 goto nla_put_failure; 849 goto nla_put_failure;
849 850
850 stats = dev_get_stats(dev); 851 stats = dev_get_stats(dev, &temp);
851 copy_rtnl_link_stats(nla_data(attr), stats); 852 copy_rtnl_link_stats(nla_data(attr), stats);
852 853
853 attr = nla_reserve(skb, IFLA_STATS64, 854 attr = nla_reserve(skb, IFLA_STATS64,