diff options
| -rw-r--r-- | net/core/dev.c | 23 |
1 files changed, 16 insertions, 7 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index cbf80098980c..fc6c9881eca8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -1909,7 +1909,6 @@ int netif_rx(struct sk_buff *skb) | |||
| 1909 | if (queue->input_pkt_queue.qlen <= netdev_max_backlog) { | 1909 | if (queue->input_pkt_queue.qlen <= netdev_max_backlog) { |
| 1910 | if (queue->input_pkt_queue.qlen) { | 1910 | if (queue->input_pkt_queue.qlen) { |
| 1911 | enqueue: | 1911 | enqueue: |
| 1912 | dev_hold(skb->dev); | ||
| 1913 | __skb_queue_tail(&queue->input_pkt_queue, skb); | 1912 | __skb_queue_tail(&queue->input_pkt_queue, skb); |
| 1914 | local_irq_restore(flags); | 1913 | local_irq_restore(flags); |
| 1915 | return NET_RX_SUCCESS; | 1914 | return NET_RX_SUCCESS; |
| @@ -2270,6 +2269,20 @@ out: | |||
| 2270 | return ret; | 2269 | return ret; |
| 2271 | } | 2270 | } |
| 2272 | 2271 | ||
| 2272 | /* Network device is going away, flush any packets still pending */ | ||
| 2273 | static void flush_backlog(void *arg) | ||
| 2274 | { | ||
| 2275 | struct net_device *dev = arg; | ||
| 2276 | struct softnet_data *queue = &__get_cpu_var(softnet_data); | ||
| 2277 | struct sk_buff *skb, *tmp; | ||
| 2278 | |||
| 2279 | skb_queue_walk_safe(&queue->input_pkt_queue, skb, tmp) | ||
| 2280 | if (skb->dev == dev) { | ||
| 2281 | __skb_unlink(skb, &queue->input_pkt_queue); | ||
| 2282 | kfree_skb(skb); | ||
| 2283 | } | ||
| 2284 | } | ||
| 2285 | |||
| 2273 | static int process_backlog(struct napi_struct *napi, int quota) | 2286 | static int process_backlog(struct napi_struct *napi, int quota) |
| 2274 | { | 2287 | { |
| 2275 | int work = 0; | 2288 | int work = 0; |
| @@ -2279,7 +2292,6 @@ static int process_backlog(struct napi_struct *napi, int quota) | |||
| 2279 | napi->weight = weight_p; | 2292 | napi->weight = weight_p; |
| 2280 | do { | 2293 | do { |
| 2281 | struct sk_buff *skb; | 2294 | struct sk_buff *skb; |
| 2282 | struct net_device *dev; | ||
| 2283 | 2295 | ||
| 2284 | local_irq_disable(); | 2296 | local_irq_disable(); |
| 2285 | skb = __skb_dequeue(&queue->input_pkt_queue); | 2297 | skb = __skb_dequeue(&queue->input_pkt_queue); |
| @@ -2288,14 +2300,9 @@ static int process_backlog(struct napi_struct *napi, int quota) | |||
| 2288 | local_irq_enable(); | 2300 | local_irq_enable(); |
| 2289 | break; | 2301 | break; |
| 2290 | } | 2302 | } |
| 2291 | |||
| 2292 | local_irq_enable(); | 2303 | local_irq_enable(); |
| 2293 | 2304 | ||
| 2294 | dev = skb->dev; | ||
| 2295 | |||
| 2296 | netif_receive_skb(skb); | 2305 | netif_receive_skb(skb); |
| 2297 | |||
| 2298 | dev_put(dev); | ||
| 2299 | } while (++work < quota && jiffies == start_time); | 2306 | } while (++work < quota && jiffies == start_time); |
| 2300 | 2307 | ||
| 2301 | return work; | 2308 | return work; |
| @@ -4169,6 +4176,8 @@ void netdev_run_todo(void) | |||
| 4169 | 4176 | ||
| 4170 | dev->reg_state = NETREG_UNREGISTERED; | 4177 | dev->reg_state = NETREG_UNREGISTERED; |
| 4171 | 4178 | ||
| 4179 | on_each_cpu(flush_backlog, dev, 1); | ||
| 4180 | |||
| 4172 | netdev_wait_allrefs(dev); | 4181 | netdev_wait_allrefs(dev); |
| 4173 | 4182 | ||
| 4174 | /* paranoia */ | 4183 | /* paranoia */ |
