* [PATCHv3 1/2] net: Enable 64-bit net device statistics on 32-bit architectures
@ 2010-06-08 17:19 Ben Hutchings
2010-06-08 17:21 ` [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures Ben Hutchings
2010-06-12 22:54 ` [PATCHv3 1/2] net: Enable 64-bit net device statistics on 32-bit architectures David Miller
0 siblings, 2 replies; 11+ messages in thread
From: Ben Hutchings @ 2010-06-08 17:19 UTC (permalink / raw)
To: David Miller; +Cc: Stephen Hemminger, Arnd Bergmann, netdev, linux-net-drivers
Use struct rtnl_link_stats64 as the statistics structure.
On 32-bit architectures, insert 32 bits of padding after/before each
field of struct net_device_stats to make its layout compatible with
struct rtnl_link_stats64. Add an anonymous union in net_device; move
stats into the union and add struct rtnl_link_stats64 stats64.
Add net_device_ops::ndo_get_stats64, implementations of which will
return a pointer to struct rtnl_link_stats64. Drivers that implement
this operation must not update the structure asynchronously.
Change dev_get_stats() to call ndo_get_stats64 if available, and to
return a pointer to struct rtnl_link_stats64. Change callers of
dev_get_stats() accordingly.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
Changes from v2:
- Keep type of net_device_stats fields as unsigned long rather than
making it explicitly u32 or u64
- Update bonding driver, which calls dev_get_stats() and must now
implement net_device_ops::ndo_get_stats64
Changes from v1:
- Remove accessor macros
Compile-tested allmodconfig on i386; this version should introduce no
new warnings.
Tested that 64-bit statistics work on i386 with bonding and sfc drivers
(using the following patch).
Ben.
drivers/net/bonding/bond_main.c | 13 +++---
include/linux/if_link.h | 3 +-
include/linux/netdevice.h | 91 +++++++++++++++++++++++----------------
net/8021q/vlanproc.c | 13 +++---
net/core/dev.c | 19 +++++---
net/core/net-sysfs.c | 12 +++---
net/core/rtnetlink.c | 6 +-
7 files changed, 90 insertions(+), 67 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 5e12462..275f555 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3774,20 +3774,21 @@ static int bond_close(struct net_device *bond_dev)
return 0;
}
-static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
+static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct net_device_stats *stats = &bond_dev->stats;
- struct net_device_stats local_stats;
+ struct rtnl_link_stats64 *stats = &bond_dev->stats64;
+ struct rtnl_link_stats64 local_stats;
struct slave *slave;
int i;
- memset(&local_stats, 0, sizeof(struct net_device_stats));
+ memset(&local_stats, 0, sizeof(local_stats));
read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
- const struct net_device_stats *sstats = dev_get_stats(slave->dev);
+ 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;
@@ -4488,7 +4489,7 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_open = bond_open,
.ndo_stop = bond_close,
.ndo_start_xmit = bond_start_xmit,
- .ndo_get_stats = bond_get_stats,
+ .ndo_get_stats64 = bond_get_stats,
.ndo_do_ioctl = bond_do_ioctl,
.ndo_set_multicast_list = bond_set_multicast_list,
.ndo_change_mtu = bond_change_mtu,
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 85c812d..7fcad2e 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -4,7 +4,7 @@
#include <linux/types.h>
#include <linux/netlink.h>
-/* The struct should be in sync with struct net_device_stats */
+/* This struct should be in sync with struct rtnl_link_stats64 */
struct rtnl_link_stats {
__u32 rx_packets; /* total packets received */
__u32 tx_packets; /* total packets transmitted */
@@ -37,6 +37,7 @@ struct rtnl_link_stats {
__u32 tx_compressed;
};
+/* The main device statistics structure */
struct rtnl_link_stats64 {
__u64 rx_packets; /* total packets received */
__u64 tx_packets; /* total packets transmitted */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a249161..d85a38e 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -159,45 +159,49 @@ static inline bool dev_xmit_complete(int rc)
#define MAX_HEADER (LL_MAX_HEADER + 48)
#endif
-#endif /* __KERNEL__ */
-
/*
- * Network device statistics. Akin to the 2.0 ether stats but
- * with byte counters.
+ * Old network device statistics. Fields are native words
+ * (unsigned long) so they can be read and written atomically.
+ * Each field is padded to 64 bits for compatibility with
+ * rtnl_link_stats64.
*/
+#if BITS_PER_LONG == 64
+#define NET_DEVICE_STATS_DEFINE(name) unsigned long name
+#elif defined(__LITTLE_ENDIAN)
+#define NET_DEVICE_STATS_DEFINE(name) unsigned long name, pad_ ## name
+#else
+#define NET_DEVICE_STATS_DEFINE(name) unsigned long pad_ ## name, name
+#endif
+
struct net_device_stats {
- unsigned long rx_packets; /* total packets received */
- unsigned long tx_packets; /* total packets transmitted */
- unsigned long rx_bytes; /* total bytes received */
- unsigned long tx_bytes; /* total bytes transmitted */
- unsigned long rx_errors; /* bad packets received */
- unsigned long tx_errors; /* packet transmit problems */
- unsigned long rx_dropped; /* no space in linux buffers */
- unsigned long tx_dropped; /* no space available in linux */
- unsigned long multicast; /* multicast packets received */
- unsigned long collisions;
-
- /* detailed rx_errors: */
- unsigned long rx_length_errors;
- unsigned long rx_over_errors; /* receiver ring buff overflow */
- unsigned long rx_crc_errors; /* recved pkt with crc error */
- unsigned long rx_frame_errors; /* recv'd frame alignment error */
- unsigned long rx_fifo_errors; /* recv'r fifo overrun */
- unsigned long rx_missed_errors; /* receiver missed packet */
-
- /* detailed tx_errors */
- unsigned long tx_aborted_errors;
- unsigned long tx_carrier_errors;
- unsigned long tx_fifo_errors;
- unsigned long tx_heartbeat_errors;
- unsigned long tx_window_errors;
-
- /* for cslip etc */
- unsigned long rx_compressed;
- unsigned long tx_compressed;
+ NET_DEVICE_STATS_DEFINE(rx_packets);
+ NET_DEVICE_STATS_DEFINE(tx_packets);
+ NET_DEVICE_STATS_DEFINE(rx_bytes);
+ NET_DEVICE_STATS_DEFINE(tx_bytes);
+ NET_DEVICE_STATS_DEFINE(rx_errors);
+ NET_DEVICE_STATS_DEFINE(tx_errors);
+ NET_DEVICE_STATS_DEFINE(rx_dropped);
+ NET_DEVICE_STATS_DEFINE(tx_dropped);
+ NET_DEVICE_STATS_DEFINE(multicast);
+ NET_DEVICE_STATS_DEFINE(collisions);
+ NET_DEVICE_STATS_DEFINE(rx_length_errors);
+ NET_DEVICE_STATS_DEFINE(rx_over_errors);
+ NET_DEVICE_STATS_DEFINE(rx_crc_errors);
+ NET_DEVICE_STATS_DEFINE(rx_frame_errors);
+ NET_DEVICE_STATS_DEFINE(rx_fifo_errors);
+ NET_DEVICE_STATS_DEFINE(rx_missed_errors);
+ NET_DEVICE_STATS_DEFINE(tx_aborted_errors);
+ NET_DEVICE_STATS_DEFINE(tx_carrier_errors);
+ NET_DEVICE_STATS_DEFINE(tx_fifo_errors);
+ NET_DEVICE_STATS_DEFINE(tx_heartbeat_errors);
+ NET_DEVICE_STATS_DEFINE(tx_window_errors);
+ NET_DEVICE_STATS_DEFINE(rx_compressed);
+ NET_DEVICE_STATS_DEFINE(tx_compressed);
};
+#endif /* __KERNEL__ */
+
/* Media selection options. */
enum {
@@ -660,10 +664,19 @@ struct netdev_rx_queue {
* Callback uses when the transmitter has not made any progress
* for dev->watchdog ticks.
*
+ * struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev);
* struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
* Called when a user wants to get the network device usage
- * statistics. If not defined, the counters in dev->stats will
- * be used.
+ * statistics. Drivers must do one of the following:
+ * 1. Define @ndo_get_stats64 to update a rtnl_link_stats64 structure
+ * (which should normally be dev->stats64) and return a ponter to
+ * it. The structure must not be changed asynchronously.
+ * 2. Define @ndo_get_stats to update a net_device_stats64 structure
+ * (which should normally be dev->stats) and return a pointer to
+ * it. The structure may be changed asynchronously only if each
+ * field is written atomically.
+ * 3. Update dev->stats asynchronously and atomically, and define
+ * neither operation.
*
* void (*ndo_vlan_rx_register)(struct net_device *dev, struct vlan_group *grp);
* If device support VLAN receive accleration
@@ -718,6 +731,7 @@ struct net_device_ops {
struct neigh_parms *);
void (*ndo_tx_timeout) (struct net_device *dev);
+ struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev);
struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
void (*ndo_vlan_rx_register)(struct net_device *dev,
@@ -867,7 +881,10 @@ struct net_device {
int ifindex;
int iflink;
- struct net_device_stats stats;
+ union {
+ struct rtnl_link_stats64 stats64;
+ struct net_device_stats stats;
+ };
#ifdef CONFIG_WIRELESS_EXT
/* List of functions to handle Wireless Extensions (instead of ioctl).
@@ -2118,7 +2135,7 @@ extern void netdev_features_change(struct net_device *dev);
/* Load a device via the kmod */
extern void dev_load(struct net *net, const char *name);
extern void dev_mcast_init(void);
-extern const struct net_device_stats *dev_get_stats(struct net_device *dev);
+extern const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev);
extern void dev_txq_stats_fold(const struct net_device *dev, struct net_device_stats *stats);
extern int netdev_max_backlog;
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index afead35..df56f5c 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -278,8 +278,9 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
{
struct net_device *vlandev = (struct net_device *) seq->private;
const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev);
- const struct net_device_stats *stats;
+ const struct rtnl_link_stats64 *stats;
static const char fmt[] = "%30s %12lu\n";
+ static const char fmt64[] = "%30s %12llu\n";
int i;
if (!is_vlan_dev(vlandev))
@@ -291,12 +292,12 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
vlandev->name, dev_info->vlan_id,
(int)(dev_info->flags & 1), vlandev->priv_flags);
- seq_printf(seq, fmt, "total frames received", stats->rx_packets);
- seq_printf(seq, fmt, "total bytes received", stats->rx_bytes);
- seq_printf(seq, fmt, "Broadcast/Multicast Rcvd", stats->multicast);
+ seq_printf(seq, fmt64, "total frames received", stats->rx_packets);
+ seq_printf(seq, fmt64, "total bytes received", stats->rx_bytes);
+ seq_printf(seq, fmt64, "Broadcast/Multicast Rcvd", stats->multicast);
seq_puts(seq, "\n");
- seq_printf(seq, fmt, "total frames transmitted", stats->tx_packets);
- seq_printf(seq, fmt, "total bytes transmitted", stats->tx_bytes);
+ seq_printf(seq, fmt64, "total frames transmitted", stats->tx_packets);
+ seq_printf(seq, fmt64, "total bytes transmitted", stats->tx_bytes);
seq_printf(seq, fmt, "total headroom inc",
dev_info->cnt_inc_headroom_on_tx);
seq_printf(seq, fmt, "total encap on xmit",
diff --git a/net/core/dev.c b/net/core/dev.c
index 983a3c1..71a6fd8 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3686,10 +3686,10 @@ void dev_seq_stop(struct seq_file *seq, void *v)
static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{
- const struct net_device_stats *stats = dev_get_stats(dev);
+ const struct rtnl_link_stats64 *stats = dev_get_stats(dev);
- seq_printf(seq, "%6s: %7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
- "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
+ seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
+ "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
dev->name, stats->rx_bytes, stats->rx_packets,
stats->rx_errors,
stats->rx_dropped + stats->rx_missed_errors,
@@ -5266,18 +5266,21 @@ EXPORT_SYMBOL(dev_txq_stats_fold);
* @dev: device to get statistics from
*
* Get network statistics from device. The device driver may provide
- * its own method by setting dev->netdev_ops->get_stats; otherwise
- * the internal statistics structure is used.
+ * its own method by setting dev->netdev_ops->get_stats64 or
+ * dev->netdev_ops->get_stats; otherwise the internal statistics
+ * structure is used.
*/
-const struct net_device_stats *dev_get_stats(struct net_device *dev)
+const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev)
{
const struct net_device_ops *ops = dev->netdev_ops;
+ if (ops->ndo_get_stats64)
+ return ops->ndo_get_stats64(dev);
if (ops->ndo_get_stats)
- return ops->ndo_get_stats(dev);
+ return (struct rtnl_link_stats64 *)ops->ndo_get_stats(dev);
dev_txq_stats_fold(dev, &dev->stats);
- return &dev->stats;
+ return &dev->stats64;
}
EXPORT_SYMBOL(dev_get_stats);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 99e7052..ea3bb4c 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -29,6 +29,7 @@ static const char fmt_hex[] = "%#x\n";
static const char fmt_long_hex[] = "%#lx\n";
static const char fmt_dec[] = "%d\n";
static const char fmt_ulong[] = "%lu\n";
+static const char fmt_u64[] = "%llu\n";
static inline int dev_isalive(const struct net_device *dev)
{
@@ -324,14 +325,13 @@ static ssize_t netstat_show(const struct device *d,
struct net_device *dev = to_net_dev(d);
ssize_t ret = -EINVAL;
- WARN_ON(offset > sizeof(struct net_device_stats) ||
- offset % sizeof(unsigned long) != 0);
+ WARN_ON(offset > sizeof(struct rtnl_link_stats64) ||
+ offset % sizeof(u64) != 0);
read_lock(&dev_base_lock);
if (dev_isalive(dev)) {
- const struct net_device_stats *stats = dev_get_stats(dev);
- ret = sprintf(buf, fmt_ulong,
- *(unsigned long *)(((u8 *) stats) + offset));
+ const struct rtnl_link_stats64 *stats = dev_get_stats(dev);
+ ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset));
}
read_unlock(&dev_base_lock);
return ret;
@@ -343,7 +343,7 @@ static ssize_t show_##name(struct device *d, \
struct device_attribute *attr, char *buf) \
{ \
return netstat_show(d, attr, buf, \
- offsetof(struct net_device_stats, name)); \
+ offsetof(struct rtnl_link_stats64, name)); \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 1a2af24..e645778 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -579,7 +579,7 @@ static unsigned int rtnl_dev_combine_flags(const struct net_device *dev,
}
static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
- const struct net_device_stats *b)
+ const struct rtnl_link_stats64 *b)
{
a->rx_packets = b->rx_packets;
a->tx_packets = b->tx_packets;
@@ -610,7 +610,7 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
a->tx_compressed = b->tx_compressed;
}
-static void copy_rtnl_link_stats64(void *v, const struct net_device_stats *b)
+static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b)
{
struct rtnl_link_stats64 a;
@@ -791,7 +791,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
{
struct ifinfomsg *ifm;
struct nlmsghdr *nlh;
- const struct net_device_stats *stats;
+ const struct rtnl_link_stats64 *stats;
struct nlattr *attr;
nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags);
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures
2010-06-08 17:19 [PATCHv3 1/2] net: Enable 64-bit net device statistics on 32-bit architectures Ben Hutchings
@ 2010-06-08 17:21 ` Ben Hutchings
2010-06-12 22:55 ` David Miller
2010-07-05 18:16 ` Eric Dumazet
2010-06-12 22:54 ` [PATCHv3 1/2] net: Enable 64-bit net device statistics on 32-bit architectures David Miller
1 sibling, 2 replies; 11+ messages in thread
From: Ben Hutchings @ 2010-06-08 17:21 UTC (permalink / raw)
To: David Miller; +Cc: Stephen Hemminger, Arnd Bergmann, netdev, linux-net-drivers
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
This is unchanged from v1.
Ben.
drivers/net/sfc/efx.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 26b0cc2..8ad476a 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1492,11 +1492,11 @@ static int efx_net_stop(struct net_device *net_dev)
}
/* Context: process, dev_base_lock or RTNL held, non-blocking. */
-static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
+static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_mac_stats *mac_stats = &efx->mac_stats;
- struct net_device_stats *stats = &net_dev->stats;
+ struct rtnl_link_stats64 *stats = &net_dev->stats64;
spin_lock_bh(&efx->stats_lock);
efx->type->update_stats(efx);
@@ -1630,7 +1630,7 @@ static void efx_set_multicast_list(struct net_device *net_dev)
static const struct net_device_ops efx_netdev_ops = {
.ndo_open = efx_net_open,
.ndo_stop = efx_net_stop,
- .ndo_get_stats = efx_net_stats,
+ .ndo_get_stats64 = efx_net_stats,
.ndo_tx_timeout = efx_watchdog,
.ndo_start_xmit = efx_hard_start_xmit,
.ndo_validate_addr = eth_validate_addr,
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCHv3 1/2] net: Enable 64-bit net device statistics on 32-bit architectures
2010-06-08 17:19 [PATCHv3 1/2] net: Enable 64-bit net device statistics on 32-bit architectures Ben Hutchings
2010-06-08 17:21 ` [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures Ben Hutchings
@ 2010-06-12 22:54 ` David Miller
1 sibling, 0 replies; 11+ messages in thread
From: David Miller @ 2010-06-12 22:54 UTC (permalink / raw)
To: bhutchings; +Cc: shemminger, arnd, netdev, linux-net-drivers
From: Ben Hutchings <bhutchings@solarflare.com>
Date: Tue, 08 Jun 2010 18:19:54 +0100
> Use struct rtnl_link_stats64 as the statistics structure.
>
> On 32-bit architectures, insert 32 bits of padding after/before each
> field of struct net_device_stats to make its layout compatible with
> struct rtnl_link_stats64. Add an anonymous union in net_device; move
> stats into the union and add struct rtnl_link_stats64 stats64.
>
> Add net_device_ops::ndo_get_stats64, implementations of which will
> return a pointer to struct rtnl_link_stats64. Drivers that implement
> this operation must not update the structure asynchronously.
>
> Change dev_get_stats() to call ndo_get_stats64 if available, and to
> return a pointer to struct rtnl_link_stats64. Change callers of
> dev_get_stats() accordingly.
>
> Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Applied.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures
2010-06-08 17:21 ` [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures Ben Hutchings
@ 2010-06-12 22:55 ` David Miller
2010-07-05 18:16 ` Eric Dumazet
1 sibling, 0 replies; 11+ messages in thread
From: David Miller @ 2010-06-12 22:55 UTC (permalink / raw)
To: bhutchings; +Cc: shemminger, arnd, netdev, linux-net-drivers
From: Ben Hutchings <bhutchings@solarflare.com>
Date: Tue, 08 Jun 2010 18:21:12 +0100
> Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Applied.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures
2010-06-08 17:21 ` [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures Ben Hutchings
2010-06-12 22:55 ` David Miller
@ 2010-07-05 18:16 ` Eric Dumazet
2010-07-05 18:31 ` Eric Dumazet
1 sibling, 1 reply; 11+ messages in thread
From: Eric Dumazet @ 2010-07-05 18:16 UTC (permalink / raw)
To: Ben Hutchings
Cc: David Miller, Stephen Hemminger, Arnd Bergmann, netdev,
linux-net-drivers
Le mardi 08 juin 2010 à 18:21 +0100, Ben Hutchings a écrit :
> Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
> ---
> This is unchanged from v1.
>
> Ben.
>
> drivers/net/sfc/efx.c | 6 +++---
> 1 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
> index 26b0cc2..8ad476a 100644
> --- a/drivers/net/sfc/efx.c
> +++ b/drivers/net/sfc/efx.c
> @@ -1492,11 +1492,11 @@ static int efx_net_stop(struct net_device *net_dev)
> }
>
> /* Context: process, dev_base_lock or RTNL held, non-blocking. */
> -static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
> +static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev)
> {
> struct efx_nic *efx = netdev_priv(net_dev);
> struct efx_mac_stats *mac_stats = &efx->mac_stats;
> - struct net_device_stats *stats = &net_dev->stats;
> + struct rtnl_link_stats64 *stats = &net_dev->stats64;
>
> spin_lock_bh(&efx->stats_lock);
> efx->type->update_stats(efx);
> @@ -1630,7 +1630,7 @@ static void efx_set_multicast_list(struct net_device *net_dev)
> static const struct net_device_ops efx_netdev_ops = {
> .ndo_open = efx_net_open,
> .ndo_stop = efx_net_stop,
> - .ndo_get_stats = efx_net_stats,
> + .ndo_get_stats64 = efx_net_stats,
> .ndo_tx_timeout = efx_watchdog,
> .ndo_start_xmit = efx_hard_start_xmit,
> .ndo_validate_addr = eth_validate_addr,
> --
> 1.6.2.5
>
Ben, David
I believe following patch is needed after our recent commits.
Not sure a seqlock is really needed, maybe a spinlock would be enough.
Thanks
[PATCH net-next-2.6] 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.
I believe we need to add some synchronisation to avoid this.
A driver that provides 64bit stats on a 32bit arches should make sure it
gets the seqlock before updating them. Other drivers can stay unchanged,
since upper 32bits are not updated.
This new seqlock should be acquired in slow path only in process context
(no BH protection for instance).
Drivers should not use it in their rx/tx path. (They better stay with
32bit counters on 32bit arches)
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
drivers/net/loopback.c | 4 ++
drivers/net/macvlan.c | 2 +
drivers/net/sfc/efx.c | 2 +
include/linux/netdevice.h | 43 +++++++++++++++++++++++
net/8021q/vlan_dev.c | 2 +
net/core/dev.c | 38 ++++++++++++--------
net/core/rtnetlink.c | 66 +++++++++++++++++++-----------------
7 files changed, 112 insertions(+), 45 deletions(-)
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 4dd0510..5e82e4a 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -123,12 +123,16 @@ static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev)
bytes += tbytes;
packets += tpackets;
}
+
+ netdev_stats_update_begin(dev);
stats->rx_packets = packets;
stats->tx_packets = packets;
stats->rx_dropped = drops;
stats->rx_errors = drops;
stats->rx_bytes = bytes;
stats->tx_bytes = bytes;
+ netdev_stats_update_end(dev);
+
return stats;
}
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index e6d626e..c39a90a 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -458,11 +458,13 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev)
/* rx_errors is an ulong, updated without syncp protection */
accum.rx_errors += p->rx_errors;
}
+ netdev_stats_update_begin(dev);
stats->rx_packets = accum.rx_packets;
stats->rx_bytes = accum.rx_bytes;
stats->rx_errors = accum.rx_errors;
stats->rx_dropped = accum.rx_errors;
stats->multicast = accum.rx_multicast;
+ netdev_stats_update_end(dev);
}
return stats;
}
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 35b3f29..06afff6 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1543,6 +1543,7 @@ static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev)
efx->type->update_stats(efx);
spin_unlock_bh(&efx->stats_lock);
+ netdev_stats_update_begin(net_dev);
stats->rx_packets = mac_stats->rx_packets;
stats->tx_packets = mac_stats->tx_packets;
stats->rx_bytes = mac_stats->rx_bytes;
@@ -1565,6 +1566,7 @@ static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev)
stats->tx_errors = (stats->tx_window_errors +
mac_stats->tx_bad);
+ netdev_stats_update_end(net_dev);
return stats;
}
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4d27368..d6726cf 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -886,6 +886,9 @@ struct net_device {
int ifindex;
int iflink;
+#if BITS_PER_LONG==32
+ seqlock_t stats_lock;
+#endif
union {
struct rtnl_link_stats64 stats64;
struct net_device_stats stats;
@@ -1080,6 +1083,46 @@ struct net_device {
};
#define to_net_dev(d) container_of(d, struct net_device, dev)
+
+static inline void netdev_stats_initlock(struct net_device *dev)
+{
+#if BITS_PER_LONG==32
+ seqlock_init(&dev->stats_lock);
+#endif
+}
+
+static inline void netdev_stats_update_begin(struct net_device *dev)
+{
+#if BITS_PER_LONG==32
+ write_seqlock(&dev->stats_lock);
+#endif
+}
+
+static inline void netdev_stats_update_end(struct net_device *dev)
+{
+#if BITS_PER_LONG==32
+ write_sequnlock(&dev->stats_lock);
+#endif
+}
+
+static inline unsigned int netdev_stats_fetch_begin(const struct net_device *dev)
+{
+#if BITS_PER_LONG==32
+ return read_seqbegin(&dev->stats_lock);
+#else
+ return 0;
+#endif
+}
+
+static bool inline netdev_stats_fetch_retry(const struct net_device *dev, unsigned int start)
+{
+#if BITS_PER_LONG==32
+ return read_seqretry(&dev->stats_lock, start);
+#else
+ return false;
+#endif
+}
+
#define NETDEV_ALIGN 32
static inline
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index c6456cb..3d4e2f0 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -830,10 +830,12 @@ static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev)
/* rx_errors is an ulong, not protected by syncp */
accum.rx_errors += p->rx_errors;
}
+ netdev_stats_update_begin(dev);
stats->rx_packets = accum.rx_packets;
stats->rx_bytes = accum.rx_bytes;
stats->rx_errors = accum.rx_errors;
stats->multicast = accum.rx_multicast;
+ netdev_stats_update_end(dev);
}
return stats;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index 93b8929..b41c7ac 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3704,24 +3704,31 @@ void dev_seq_stop(struct seq_file *seq, void *v)
static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{
const struct rtnl_link_stats64 *stats = dev_get_stats(dev);
+ struct rtnl_link_stats64 temp;
+ unsigned int start;
+
+ do {
+ start = netdev_stats_fetch_begin(dev);
+ memcpy(&temp, stats, sizeof(temp));
+ } while (netdev_stats_fetch_retry(dev, start));
seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
"%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
- dev->name, stats->rx_bytes, stats->rx_packets,
- stats->rx_errors,
- stats->rx_dropped + stats->rx_missed_errors,
- stats->rx_fifo_errors,
- stats->rx_length_errors + stats->rx_over_errors +
- stats->rx_crc_errors + stats->rx_frame_errors,
- stats->rx_compressed, stats->multicast,
- stats->tx_bytes, stats->tx_packets,
- stats->tx_errors, stats->tx_dropped,
- stats->tx_fifo_errors, stats->collisions,
- stats->tx_carrier_errors +
- stats->tx_aborted_errors +
- stats->tx_window_errors +
- stats->tx_heartbeat_errors,
- stats->tx_compressed);
+ dev->name, temp.rx_bytes, temp.rx_packets,
+ temp.rx_errors,
+ temp.rx_dropped + temp.rx_missed_errors,
+ temp.rx_fifo_errors,
+ temp.rx_length_errors + temp.rx_over_errors +
+ temp.rx_crc_errors + temp.rx_frame_errors,
+ temp.rx_compressed, temp.multicast,
+ temp.tx_bytes, temp.tx_packets,
+ temp.tx_errors, temp.tx_dropped,
+ temp.tx_fifo_errors, temp.collisions,
+ temp.tx_carrier_errors +
+ temp.tx_aborted_errors +
+ temp.tx_window_errors +
+ temp.tx_heartbeat_errors,
+ temp.tx_compressed);
}
/*
@@ -5386,6 +5393,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
if (dev_addr_init(dev))
goto free_rx;
+ netdev_stats_initlock(dev);
dev_mc_init(dev);
dev_uc_init(dev);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e645778..b3a3812 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -610,37 +610,43 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
a->tx_compressed = b->tx_compressed;
}
-static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b)
+static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b,
+ struct net_device *dev)
{
struct rtnl_link_stats64 a;
-
- a.rx_packets = b->rx_packets;
- a.tx_packets = b->tx_packets;
- a.rx_bytes = b->rx_bytes;
- a.tx_bytes = b->tx_bytes;
- a.rx_errors = b->rx_errors;
- a.tx_errors = b->tx_errors;
- a.rx_dropped = b->rx_dropped;
- a.tx_dropped = b->tx_dropped;
-
- a.multicast = b->multicast;
- a.collisions = b->collisions;
-
- a.rx_length_errors = b->rx_length_errors;
- a.rx_over_errors = b->rx_over_errors;
- a.rx_crc_errors = b->rx_crc_errors;
- a.rx_frame_errors = b->rx_frame_errors;
- a.rx_fifo_errors = b->rx_fifo_errors;
- a.rx_missed_errors = b->rx_missed_errors;
-
- a.tx_aborted_errors = b->tx_aborted_errors;
- a.tx_carrier_errors = b->tx_carrier_errors;
- a.tx_fifo_errors = b->tx_fifo_errors;
- a.tx_heartbeat_errors = b->tx_heartbeat_errors;
- a.tx_window_errors = b->tx_window_errors;
-
- a.rx_compressed = b->rx_compressed;
- a.tx_compressed = b->tx_compressed;
+ unsigned int start;
+
+ do {
+ start = netdev_stats_fetch_begin(dev);
+
+ a.rx_packets = b->rx_packets;
+ a.tx_packets = b->tx_packets;
+ a.rx_bytes = b->rx_bytes;
+ a.tx_bytes = b->tx_bytes;
+ a.rx_errors = b->rx_errors;
+ a.tx_errors = b->tx_errors;
+ a.rx_dropped = b->rx_dropped;
+ a.tx_dropped = b->tx_dropped;
+
+ a.multicast = b->multicast;
+ a.collisions = b->collisions;
+
+ a.rx_length_errors = b->rx_length_errors;
+ a.rx_over_errors = b->rx_over_errors;
+ a.rx_crc_errors = b->rx_crc_errors;
+ a.rx_frame_errors = b->rx_frame_errors;
+ a.rx_fifo_errors = b->rx_fifo_errors;
+ a.rx_missed_errors = b->rx_missed_errors;
+
+ a.tx_aborted_errors = b->tx_aborted_errors;
+ a.tx_carrier_errors = b->tx_carrier_errors;
+ a.tx_fifo_errors = b->tx_fifo_errors;
+ a.tx_heartbeat_errors = b->tx_heartbeat_errors;
+ a.tx_window_errors = b->tx_window_errors;
+
+ a.rx_compressed = b->rx_compressed;
+ a.tx_compressed = b->tx_compressed;
+ } while (netdev_stats_fetch_retry(dev, start));
memcpy(v, &a, sizeof(a));
}
@@ -854,7 +860,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
sizeof(struct rtnl_link_stats64));
if (attr == NULL)
goto nla_put_failure;
- copy_rtnl_link_stats64(nla_data(attr), stats);
+ copy_rtnl_link_stats64(nla_data(attr), stats, dev);
if (dev->dev.parent)
NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent));
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures
2010-07-05 18:16 ` Eric Dumazet
@ 2010-07-05 18:31 ` Eric Dumazet
2010-07-05 20:05 ` [PATCH net-next-2.6 V2] net: fix 64 bit counters on 32 bit arches Eric Dumazet
2010-07-07 19:56 ` [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures David Miller
0 siblings, 2 replies; 11+ messages in thread
From: Eric Dumazet @ 2010-07-05 18:31 UTC (permalink / raw)
To: Ben Hutchings
Cc: David Miller, Stephen Hemminger, Arnd Bergmann, netdev,
linux-net-drivers
Le lundi 05 juillet 2010 à 20:16 +0200, Eric Dumazet a écrit :
> Le mardi 08 juin 2010 à 18:21 +0100, Ben Hutchings a écrit :
> > Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
> > ---
> > This is unchanged from v1.
> >
> > Ben.
> >
> > drivers/net/sfc/efx.c | 6 +++---
> > 1 files changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
> > index 26b0cc2..8ad476a 100644
> > --- a/drivers/net/sfc/efx.c
> > +++ b/drivers/net/sfc/efx.c
> > @@ -1492,11 +1492,11 @@ static int efx_net_stop(struct net_device *net_dev)
> > }
> >
> > /* Context: process, dev_base_lock or RTNL held, non-blocking. */
> > -static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
> > +static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev)
> > {
> > struct efx_nic *efx = netdev_priv(net_dev);
> > struct efx_mac_stats *mac_stats = &efx->mac_stats;
> > - struct net_device_stats *stats = &net_dev->stats;
> > + struct rtnl_link_stats64 *stats = &net_dev->stats64;
> >
> > spin_lock_bh(&efx->stats_lock);
> > efx->type->update_stats(efx);
> > @@ -1630,7 +1630,7 @@ static void efx_set_multicast_list(struct net_device *net_dev)
> > static const struct net_device_ops efx_netdev_ops = {
> > .ndo_open = efx_net_open,
> > .ndo_stop = efx_net_stop,
> > - .ndo_get_stats = efx_net_stats,
> > + .ndo_get_stats64 = efx_net_stats,
> > .ndo_tx_timeout = efx_watchdog,
> > .ndo_start_xmit = efx_hard_start_xmit,
> > .ndo_validate_addr = eth_validate_addr,
> > --
> > 1.6.2.5
> >
>
> Ben, David
>
> I believe following patch is needed after our recent commits.
> Not sure a seqlock is really needed, maybe a spinlock would be enough.
>
One other way would be to add a rtnl_link_stats64 param to
ndo_get_stats64() method, and ask drivers to copy their stats in this
zone, instead of returning &dev->stats64 or something...
And also change dev_get_stats() with this new parameter.
Each caller would use a private copy, with no risk of concurrent
updates.
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH net-next-2.6 V2] net: fix 64 bit counters on 32 bit arches
2010-07-05 18:31 ` Eric Dumazet
@ 2010-07-05 20:05 ` Eric Dumazet
2010-07-07 21:36 ` David Miller
2010-07-07 19:56 ` [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures David Miller
1 sibling, 1 reply; 11+ messages in thread
From: Eric Dumazet @ 2010-07-05 20:05 UTC (permalink / raw)
To: Ben Hutchings, David Miller
Cc: Stephen Hemminger, Arnd Bergmann, netdev, linux-net-drivers
Le lundi 05 juillet 2010 à 20:31 +0200, Eric Dumazet a écrit :
> One other way would be to add a rtnl_link_stats64 param to
> ndo_get_stats64() method, and ask drivers to copy their stats in this
> zone, instead of returning &dev->stats64 or something...
>
> And also change dev_get_stats() with this new parameter.
>
> Each caller would use a private copy, with no risk of concurrent
> updates.
>
>
Here is an updated patch, without added lock but temp storage.
Thanks
[PATCH net-next-2.6 V2] 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>
---
drivers/net/bonding/bond_main.c | 64 +++++++++++++---------------
drivers/net/ixgbe/ixgbe_ethtool.c | 8 ++-
drivers/net/loopback.c | 4 -
drivers/net/macvlan.c | 6 +-
drivers/net/sfc/efx.c | 3 -
drivers/net/sfc/ethtool.c | 3 -
include/linux/netdevice.h | 12 +++--
net/8021q/vlan_dev.c | 6 --
net/8021q/vlanproc.c | 3 -
net/bridge/br_device.c | 4 -
net/core/dev.c | 25 +++++++---
net/core/net-sysfs.c | 4 +
net/core/rtnetlink.c | 3 -
13 files changed, 79 insertions(+), 66 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a95a41b..9bb9bfa 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)
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;
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 5275e9c..7e85e61 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -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:
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 4dd0510..9a09967 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,
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;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index e6d626e..6112f14 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -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};
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 35b3f29..ba674c5 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)
}
/* Context: process, dev_base_lock or RTNL held, non-blocking. */
-static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev)
+static struct rtnl_link_stats64 *efx_net_stats(struct net_device *net_dev, struct rtnl_link_stats64 *stats)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_mac_stats *mac_stats = &efx->mac_stats;
- struct rtnl_link_stats64 *stats = &net_dev->stats64;
spin_lock_bh(&efx->stats_lock);
efx->type->update_stats(efx);
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 3b8b0a0..fd19d6a 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,
struct efx_mac_stats *mac_stats = &efx->mac_stats;
struct efx_ethtool_stat *stat;
struct efx_channel *channel;
+ struct rtnl_link_stats64 temp;
int i;
EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
/* Update MAC and NIC statistics */
- dev_get_stats(net_dev);
+ dev_get_stats(net_dev, &temp);
/* Fill detailed statistics buffer */
for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 4d27368..60de653 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -666,7 +666,8 @@ struct netdev_rx_queue {
* Callback uses when the transmitter has not made any progress
* for dev->watchdog ticks.
*
- * struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev);
+ * struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev
+ * struct rtnl_link_stats64 *storage);
* struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
* Called when a user wants to get the network device usage
* statistics. Drivers must do one of the following:
@@ -733,7 +734,8 @@ struct net_device_ops {
struct neigh_parms *);
void (*ndo_tx_timeout) (struct net_device *dev);
- struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev);
+ struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev,
+ struct rtnl_link_stats64 *storage);
struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
void (*ndo_vlan_rx_register)(struct net_device *dev,
@@ -2139,8 +2141,10 @@ extern void netdev_features_change(struct net_device *dev);
/* Load a device via the kmod */
extern void dev_load(struct net *net, const char *name);
extern void dev_mcast_init(void);
-extern const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev);
-extern void dev_txq_stats_fold(const struct net_device *dev, struct net_device_stats *stats);
+extern const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *storage);
+extern void dev_txq_stats_fold(const struct net_device *dev,
+ struct net_device_stats *stats);
extern int netdev_max_backlog;
extern int netdev_tstamp_prequeue;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index c6456cb..7865a4c 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)
return dev_ethtool_get_flags(vlan->real_dev);
}
-static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev)
+static struct rtnl_link_stats64 *vlan_dev_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
{
- struct rtnl_link_stats64 *stats = &dev->stats64;
-
- dev_txq_stats_fold(dev, &dev->stats);
+ dev_txq_stats_fold(dev, (struct net_device_stats *)stats);
if (vlan_dev_info(dev)->vlan_rx_stats) {
struct vlan_rx_stats *p, accum = {0};
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index df56f5c..80e280f 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)
{
struct net_device *vlandev = (struct net_device *) seq->private;
const struct vlan_dev_info *dev_info = vlan_dev_info(vlandev);
+ struct rtnl_link_stats64 temp;
const struct rtnl_link_stats64 *stats;
static const char fmt[] = "%30s %12lu\n";
static const char fmt64[] = "%30s %12llu\n";
@@ -286,7 +287,7 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
if (!is_vlan_dev(vlandev))
return 0;
- stats = dev_get_stats(vlandev);
+ stats = dev_get_stats(vlandev, &temp);
seq_printf(seq,
"%s VID: %d REORDER_HDR: %i dev->priv_flags: %hx\n",
vlandev->name, dev_info->vlan_id,
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index edf639e..075c435 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)
return 0;
}
-static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev)
+static struct rtnl_link_stats64 *br_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
{
struct net_bridge *br = netdev_priv(dev);
- struct rtnl_link_stats64 *stats = &dev->stats64;
struct br_cpu_netstats tmp, sum = { 0 };
unsigned int cpu;
diff --git a/net/core/dev.c b/net/core/dev.c
index 93b8929..b6d570a 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)
static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{
- const struct rtnl_link_stats64 *stats = dev_get_stats(dev);
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
"%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
@@ -5281,23 +5282,29 @@ EXPORT_SYMBOL(dev_txq_stats_fold);
/**
* dev_get_stats - get network device statistics
* @dev: device to get statistics from
+ * @storage: place to store stats
*
* Get network statistics from device. The device driver may provide
* its own method by setting dev->netdev_ops->get_stats64 or
* dev->netdev_ops->get_stats; otherwise the internal statistics
* structure is used.
*/
-const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev)
+const struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
+ struct rtnl_link_stats64 *storage)
{
const struct net_device_ops *ops = dev->netdev_ops;
- if (ops->ndo_get_stats64)
- return ops->ndo_get_stats64(dev);
- if (ops->ndo_get_stats)
- return (struct rtnl_link_stats64 *)ops->ndo_get_stats(dev);
-
- dev_txq_stats_fold(dev, &dev->stats);
- return &dev->stats64;
+ if (ops->ndo_get_stats64) {
+ memset(storage, 0, sizeof(*storage));
+ return ops->ndo_get_stats64(dev, storage);
+ }
+ if (ops->ndo_get_stats) {
+ memcpy(storage, ops->ndo_get_stats(dev), sizeof(*storage));
+ return storage;
+ }
+ memcpy(storage, &dev->stats, sizeof(*storage));
+ dev_txq_stats_fold(dev, (struct net_device_stats *)storage);
+ return storage;
}
EXPORT_SYMBOL(dev_get_stats);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index ea3bb4c..914f42b 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,
read_lock(&dev_base_lock);
if (dev_isalive(dev)) {
- const struct rtnl_link_stats64 *stats = dev_get_stats(dev);
+ struct rtnl_link_stats64 temp;
+ const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
+
ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset));
}
read_unlock(&dev_base_lock);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e645778..5e773ea 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,
{
struct ifinfomsg *ifm;
struct nlmsghdr *nlh;
+ struct rtnl_link_stats64 temp;
const struct rtnl_link_stats64 *stats;
struct nlattr *attr;
@@ -847,7 +848,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
if (attr == NULL)
goto nla_put_failure;
- stats = dev_get_stats(dev);
+ stats = dev_get_stats(dev, &temp);
copy_rtnl_link_stats(nla_data(attr), stats);
attr = nla_reserve(skb, IFLA_STATS64,
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures
2010-07-05 18:31 ` Eric Dumazet
2010-07-05 20:05 ` [PATCH net-next-2.6 V2] net: fix 64 bit counters on 32 bit arches Eric Dumazet
@ 2010-07-07 19:56 ` David Miller
1 sibling, 0 replies; 11+ messages in thread
From: David Miller @ 2010-07-07 19:56 UTC (permalink / raw)
To: eric.dumazet; +Cc: bhutchings, shemminger, arnd, netdev, linux-net-drivers
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 05 Jul 2010 20:31:22 +0200
> One other way would be to add a rtnl_link_stats64 param to
> ndo_get_stats64() method, and ask drivers to copy their stats in this
> zone, instead of returning &dev->stats64 or something...
>
> And also change dev_get_stats() with this new parameter.
>
> Each caller would use a private copy, with no risk of concurrent
> updates.
If this can be reliably be made at all call sites, I think such
an approach is preferable.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net-next-2.6 V2] net: fix 64 bit counters on 32 bit arches
2010-07-05 20:05 ` [PATCH net-next-2.6 V2] net: fix 64 bit counters on 32 bit arches Eric Dumazet
@ 2010-07-07 21:36 ` David Miller
2010-07-07 22:41 ` David Miller
0 siblings, 1 reply; 11+ messages in thread
From: David Miller @ 2010-07-07 21:36 UTC (permalink / raw)
To: eric.dumazet; +Cc: bhutchings, shemminger, arnd, netdev, linux-net-drivers
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 05 Jul 2010 22:05:22 +0200
> [PATCH net-next-2.6 V2] 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>
Looks great, applied, thanks Eric.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net-next-2.6 V2] net: fix 64 bit counters on 32 bit arches
2010-07-07 21:36 ` David Miller
@ 2010-07-07 22:41 ` David Miller
2010-07-08 5:18 ` Eric Dumazet
0 siblings, 1 reply; 11+ messages in thread
From: David Miller @ 2010-07-07 22:41 UTC (permalink / raw)
To: eric.dumazet; +Cc: bhutchings, shemminger, arnd, netdev, linux-net-drivers
From: David Miller <davem@davemloft.net>
Date: Wed, 07 Jul 2010 14:36:45 -0700 (PDT)
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Mon, 05 Jul 2010 22:05:22 +0200
>
>> [PATCH net-next-2.6 V2] net: fix 64 bit counters on 32 bit arches
Some dev_get_stats() conversions were missing, such as parisc/led,
some s390 code, usb rndis, etc.
I took care of this when integrating this patch.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH net-next-2.6 V2] net: fix 64 bit counters on 32 bit arches
2010-07-07 22:41 ` David Miller
@ 2010-07-08 5:18 ` Eric Dumazet
0 siblings, 0 replies; 11+ messages in thread
From: Eric Dumazet @ 2010-07-08 5:18 UTC (permalink / raw)
To: David Miller; +Cc: bhutchings, shemminger, arnd, netdev, linux-net-drivers
Le mercredi 07 juillet 2010 à 15:41 -0700, David Miller a écrit :
> Some dev_get_stats() conversions were missing, such as parisc/led,
> some s390 code, usb rndis, etc.
>
> I took care of this when integrating this patch.
Thats very kind of you David, thanks !
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2010-07-08 5:18 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-08 17:19 [PATCHv3 1/2] net: Enable 64-bit net device statistics on 32-bit architectures Ben Hutchings
2010-06-08 17:21 ` [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures Ben Hutchings
2010-06-12 22:55 ` David Miller
2010-07-05 18:16 ` Eric Dumazet
2010-07-05 18:31 ` Eric Dumazet
2010-07-05 20:05 ` [PATCH net-next-2.6 V2] net: fix 64 bit counters on 32 bit arches Eric Dumazet
2010-07-07 21:36 ` David Miller
2010-07-07 22:41 ` David Miller
2010-07-08 5:18 ` Eric Dumazet
2010-07-07 19:56 ` [PATCHv3 2/2] sfc: Implement 64-bit net device statistics on all architectures David Miller
2010-06-12 22:54 ` [PATCHv3 1/2] net: Enable 64-bit net device statistics on 32-bit architectures David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).