aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-09-27 01:08:12 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:52:47 -0400
commit5f6d88b9149d537f3db0798f7d312be632422e15 (patch)
tree8e85e14c152a5b6c7f61ef2176cb6ed53854e280
parent9dd776b6d7b0b85966b6ddd03e2b2aae59012ab1 (diff)
[NET]: Dynamically allocate the per cpu counters for the loopback device.
This patch add support for dynamically allocating the statistics counters for the loopback device and adds appropriate device methods for allocating and freeing the loopback device. This completes support for creating multiple instances of the loopback device, in preparation for creating per network namespace instances. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/loopback.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 4b6f7b2abea..f3018bb7570 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -62,7 +62,6 @@ struct pcpu_lstats {
62 unsigned long packets; 62 unsigned long packets;
63 unsigned long bytes; 63 unsigned long bytes;
64}; 64};
65static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats);
66 65
67#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16) 66#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
68 67
@@ -134,7 +133,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
134 */ 133 */
135static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) 134static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
136{ 135{
137 struct pcpu_lstats *lb_stats; 136 struct pcpu_lstats *pcpu_lstats, *lb_stats;
138 137
139 skb_orphan(skb); 138 skb_orphan(skb);
140 139
@@ -155,7 +154,8 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
155 dev->last_rx = jiffies; 154 dev->last_rx = jiffies;
156 155
157 /* it's OK to use __get_cpu_var() because BHs are off */ 156 /* it's OK to use __get_cpu_var() because BHs are off */
158 lb_stats = &__get_cpu_var(pcpu_lstats); 157 pcpu_lstats = netdev_priv(dev);
158 lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());
159 lb_stats->bytes += skb->len; 159 lb_stats->bytes += skb->len;
160 lb_stats->packets++; 160 lb_stats->packets++;
161 161
@@ -166,15 +166,17 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
166 166
167static struct net_device_stats *get_stats(struct net_device *dev) 167static struct net_device_stats *get_stats(struct net_device *dev)
168{ 168{
169 const struct pcpu_lstats *pcpu_lstats;
169 struct net_device_stats *stats = &dev->stats; 170 struct net_device_stats *stats = &dev->stats;
170 unsigned long bytes = 0; 171 unsigned long bytes = 0;
171 unsigned long packets = 0; 172 unsigned long packets = 0;
172 int i; 173 int i;
173 174
175 pcpu_lstats = netdev_priv(dev);
174 for_each_possible_cpu(i) { 176 for_each_possible_cpu(i) {
175 const struct pcpu_lstats *lb_stats; 177 const struct pcpu_lstats *lb_stats;
176 178
177 lb_stats = &per_cpu(pcpu_lstats, i); 179 lb_stats = per_cpu_ptr(pcpu_lstats, i);
178 bytes += lb_stats->bytes; 180 bytes += lb_stats->bytes;
179 packets += lb_stats->packets; 181 packets += lb_stats->packets;
180 } 182 }
@@ -198,6 +200,26 @@ static const struct ethtool_ops loopback_ethtool_ops = {
198 .get_rx_csum = always_on, 200 .get_rx_csum = always_on,
199}; 201};
200 202
203static int loopback_dev_init(struct net_device *dev)
204{
205 struct pcpu_lstats *lstats;
206
207 lstats = alloc_percpu(struct pcpu_lstats);
208 if (!lstats)
209 return -ENOMEM;
210
211 dev->priv = lstats;
212 return 0;
213}
214
215static void loopback_dev_free(struct net_device *dev)
216{
217 struct pcpu_lstats *lstats = netdev_priv(dev);
218
219 free_percpu(lstats);
220 free_netdev(dev);
221}
222
201/* 223/*
202 * The loopback device is special. There is only one instance and 224 * The loopback device is special. There is only one instance and
203 * it is statically allocated. Don't do this for other devices. 225 * it is statically allocated. Don't do this for other devices.
@@ -225,6 +247,8 @@ static void loopback_setup(struct net_device *dev)
225 | NETIF_F_LLTX 247 | NETIF_F_LLTX
226 | NETIF_F_NETNS_LOCAL, 248 | NETIF_F_NETNS_LOCAL,
227 dev->ethtool_ops = &loopback_ethtool_ops; 249 dev->ethtool_ops = &loopback_ethtool_ops;
250 dev->init = loopback_dev_init;
251 dev->destructor = loopback_dev_free;
228} 252}
229 253
230/* Setup and register the loopback device. */ 254/* Setup and register the loopback device. */