diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-07-07 17:58:56 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-07-07 17:58:56 -0400 |
commit | 28172739f0a276eb8d6ca917b3974c2edb036da3 (patch) | |
tree | b1dc00cfa20c209992e247c6f73601f609f9ca3b /net/core | |
parent | 217d32dc5f299c483ca0d3c8cc6811c72c0339c4 (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/core')
-rw-r--r-- | net/core/dev.c | 25 | ||||
-rw-r--r-- | net/core/net-sysfs.c | 4 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 3 |
3 files changed, 21 insertions, 11 deletions
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 | ||
3704 | static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) | 3704 | static 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 | */ |
5290 | const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev) | 5292 | const 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 | } |
5302 | EXPORT_SYMBOL(dev_get_stats); | 5309 | EXPORT_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, |