aboutsummaryrefslogtreecommitdiffstats
path: root/net
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 /net
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>
Diffstat (limited to 'net')
-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
6 files changed, 27 insertions, 18 deletions
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,