aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/loopback.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-06-14 01:59:22 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-15 02:13:07 -0400
commit6b10de38f0ef4e921a1f6e5cba2b6c92d6b46ecd (patch)
tree76e914c5097cb80cf65bf9ce1e48acff8e46795c /drivers/net/loopback.c
parentc68f24cc354050415c5ea543cd19ea5424463a2f (diff)
loopback: Implement 64bit stats on 32bit arches
Uses a seqcount_t to synchronize stat producer and consumer, for packets and bytes counter, now u64 types. (dropped counter being rarely used, stay a native "unsigned long" type) No noticeable performance impact on x86, as it only adds two increments per frame. It might be more expensive on arches where smp_wmb() is not free. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/loopback.c')
-rw-r--r--drivers/net/loopback.c61
1 files changed, 51 insertions, 10 deletions
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 72b7949c91b1..09334f8f148b 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -60,11 +60,51 @@
60#include <net/net_namespace.h> 60#include <net/net_namespace.h>
61 61
62struct pcpu_lstats { 62struct pcpu_lstats {
63 unsigned long packets; 63 u64 packets;
64 unsigned long bytes; 64 u64 bytes;
65#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
66 seqcount_t seq;
67#endif
65 unsigned long drops; 68 unsigned long drops;
66}; 69};
67 70
71#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
72static void inline lstats_update_begin(struct pcpu_lstats *lstats)
73{
74 write_seqcount_begin(&lstats->seq);
75}
76static void inline lstats_update_end(struct pcpu_lstats *lstats)
77{
78 write_seqcount_end(&lstats->seq);
79}
80static void inline lstats_fetch_and_add(u64 *packets, u64 *bytes, const struct pcpu_lstats *lstats)
81{
82 u64 tpackets, tbytes;
83 unsigned int seq;
84
85 do {
86 seq = read_seqcount_begin(&lstats->seq);
87 tpackets = lstats->packets;
88 tbytes = lstats->bytes;
89 } while (read_seqcount_retry(&lstats->seq, seq));
90
91 *packets += tpackets;
92 *bytes += tbytes;
93}
94#else
95static void inline lstats_update_begin(struct pcpu_lstats *lstats)
96{
97}
98static void inline lstats_update_end(struct pcpu_lstats *lstats)
99{
100}
101static void inline lstats_fetch_and_add(u64 *packets, u64 *bytes, const struct pcpu_lstats *lstats)
102{
103 *packets += lstats->packets;
104 *bytes += lstats->bytes;
105}
106#endif
107
68/* 108/*
69 * The higher levels take care of making this non-reentrant (it's 109 * The higher levels take care of making this non-reentrant (it's
70 * called with bh's disabled). 110 * called with bh's disabled).
@@ -86,21 +126,23 @@ static netdev_tx_t loopback_xmit(struct sk_buff *skb,
86 126
87 len = skb->len; 127 len = skb->len;
88 if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { 128 if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
129 lstats_update_begin(lb_stats);
89 lb_stats->bytes += len; 130 lb_stats->bytes += len;
90 lb_stats->packets++; 131 lb_stats->packets++;
132 lstats_update_end(lb_stats);
91 } else 133 } else
92 lb_stats->drops++; 134 lb_stats->drops++;
93 135
94 return NETDEV_TX_OK; 136 return NETDEV_TX_OK;
95} 137}
96 138
97static struct net_device_stats *loopback_get_stats(struct net_device *dev) 139static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev)
98{ 140{
99 const struct pcpu_lstats __percpu *pcpu_lstats; 141 const struct pcpu_lstats __percpu *pcpu_lstats;
100 struct net_device_stats *stats = &dev->stats; 142 struct rtnl_link_stats64 *stats = &dev->stats64;
101 unsigned long bytes = 0; 143 u64 bytes = 0;
102 unsigned long packets = 0; 144 u64 packets = 0;
103 unsigned long drops = 0; 145 u64 drops = 0;
104 int i; 146 int i;
105 147
106 pcpu_lstats = (void __percpu __force *)dev->ml_priv; 148 pcpu_lstats = (void __percpu __force *)dev->ml_priv;
@@ -108,8 +150,7 @@ static struct net_device_stats *loopback_get_stats(struct net_device *dev)
108 const struct pcpu_lstats *lb_stats; 150 const struct pcpu_lstats *lb_stats;
109 151
110 lb_stats = per_cpu_ptr(pcpu_lstats, i); 152 lb_stats = per_cpu_ptr(pcpu_lstats, i);
111 bytes += lb_stats->bytes; 153 lstats_fetch_and_add(&packets, &bytes, lb_stats);
112 packets += lb_stats->packets;
113 drops += lb_stats->drops; 154 drops += lb_stats->drops;
114 } 155 }
115 stats->rx_packets = packets; 156 stats->rx_packets = packets;
@@ -158,7 +199,7 @@ static void loopback_dev_free(struct net_device *dev)
158static const struct net_device_ops loopback_ops = { 199static const struct net_device_ops loopback_ops = {
159 .ndo_init = loopback_dev_init, 200 .ndo_init = loopback_dev_init,
160 .ndo_start_xmit= loopback_xmit, 201 .ndo_start_xmit= loopback_xmit,
161 .ndo_get_stats = loopback_get_stats, 202 .ndo_get_stats64 = loopback_get_stats64,
162}; 203};
163 204
164/* 205/*