diff options
Diffstat (limited to 'drivers/net/loopback.c')
-rw-r--r-- | drivers/net/loopback.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 4b6f7b2abea5..f3018bb7570d 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 | }; |
65 | static 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 | */ |
135 | static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) | 134 | static 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 | ||
167 | static struct net_device_stats *get_stats(struct net_device *dev) | 167 | static 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 | ||
203 | static 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 | |||
215 | static 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. */ |