aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/loopback.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/loopback.c')
-rw-r--r--drivers/net/loopback.c39
1 files changed, 21 insertions, 18 deletions
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 4178b4b1d2df..82c10dec1b5a 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -58,7 +58,11 @@
58#include <linux/tcp.h> 58#include <linux/tcp.h>
59#include <linux/percpu.h> 59#include <linux/percpu.h>
60 60
61static DEFINE_PER_CPU(struct net_device_stats, loopback_stats); 61struct pcpu_lstats {
62 unsigned long packets;
63 unsigned long bytes;
64};
65static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats);
62 66
63#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) 67#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
64 68
@@ -128,7 +132,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
128 */ 132 */
129static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) 133static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
130{ 134{
131 struct net_device_stats *lb_stats; 135 struct pcpu_lstats *lb_stats;
132 136
133 skb_orphan(skb); 137 skb_orphan(skb);
134 138
@@ -149,16 +153,14 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
149#endif 153#endif
150 dev->last_rx = jiffies; 154 dev->last_rx = jiffies;
151 155
152 lb_stats = &per_cpu(loopback_stats, get_cpu()); 156 /* it's OK to use __get_cpu_var() because BHs are off */
153 lb_stats->rx_bytes += skb->len; 157 lb_stats = &__get_cpu_var(pcpu_lstats);
154 lb_stats->tx_bytes = lb_stats->rx_bytes; 158 lb_stats->bytes += skb->len;
155 lb_stats->rx_packets++; 159 lb_stats->packets++;
156 lb_stats->tx_packets = lb_stats->rx_packets;
157 put_cpu();
158 160
159 netif_rx(skb); 161 netif_rx(skb);
160 162
161 return(0); 163 return 0;
162} 164}
163 165
164static struct net_device_stats loopback_stats; 166static struct net_device_stats loopback_stats;
@@ -166,20 +168,21 @@ static struct net_device_stats loopback_stats;
166static struct net_device_stats *get_stats(struct net_device *dev) 168static struct net_device_stats *get_stats(struct net_device *dev)
167{ 169{
168 struct net_device_stats *stats = &loopback_stats; 170 struct net_device_stats *stats = &loopback_stats;
171 unsigned long bytes = 0;
172 unsigned long packets = 0;
169 int i; 173 int i;
170 174
171 memset(stats, 0, sizeof(struct net_device_stats));
172
173 for_each_possible_cpu(i) { 175 for_each_possible_cpu(i) {
174 struct net_device_stats *lb_stats; 176 const struct pcpu_lstats *lb_stats;
175 177
176 lb_stats = &per_cpu(loopback_stats, i); 178 lb_stats = &per_cpu(pcpu_lstats, i);
177 stats->rx_bytes += lb_stats->rx_bytes; 179 bytes += lb_stats->bytes;
178 stats->tx_bytes += lb_stats->tx_bytes; 180 packets += lb_stats->packets;
179 stats->rx_packets += lb_stats->rx_packets;
180 stats->tx_packets += lb_stats->tx_packets;
181 } 181 }
182 182 stats->rx_packets = packets;
183 stats->tx_packets = packets;
184 stats->rx_bytes = bytes;
185 stats->tx_bytes = bytes;
183 return stats; 186 return stats;
184} 187}
185 188