Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: Fix locking in flush_backlog

Need to take spinlocks when dequeuing from input_pkt_queue in flush_backlog.
Also, flush_backlog can now be called directly from netdev_run_todo.

Signed-off-by: Tom Herbert <therbert@google.com>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Tom Herbert and committed by
David S. Miller
e51d739a ec43b1a6

+8 -4
+8 -4
net/core/dev.c
··· 2766 2766 EXPORT_SYMBOL(netif_receive_skb); 2767 2767 2768 2768 /* Network device is going away, flush any packets still pending */ 2769 - static void flush_backlog(void *arg) 2769 + static void flush_backlog(struct net_device *dev, int cpu) 2770 2770 { 2771 - struct net_device *dev = arg; 2772 - struct softnet_data *queue = &__get_cpu_var(softnet_data); 2771 + struct softnet_data *queue = &per_cpu(softnet_data, cpu); 2773 2772 struct sk_buff *skb, *tmp; 2773 + unsigned long flags; 2774 2774 2775 + spin_lock_irqsave(&queue->input_pkt_queue.lock, flags); 2775 2776 skb_queue_walk_safe(&queue->input_pkt_queue, skb, tmp) 2776 2777 if (skb->dev == dev) { 2777 2778 __skb_unlink(skb, &queue->input_pkt_queue); 2778 2779 kfree_skb(skb); 2779 2780 } 2781 + spin_unlock_irqrestore(&queue->input_pkt_queue.lock, flags); 2780 2782 } 2781 2783 2782 2784 static int napi_gro_complete(struct sk_buff *skb) ··· 5547 5545 while (!list_empty(&list)) { 5548 5546 struct net_device *dev 5549 5547 = list_first_entry(&list, struct net_device, todo_list); 5548 + int i; 5550 5549 list_del(&dev->todo_list); 5551 5550 5552 5551 if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) { ··· 5559 5556 5560 5557 dev->reg_state = NETREG_UNREGISTERED; 5561 5558 5562 - on_each_cpu(flush_backlog, dev, 1); 5559 + for_each_online_cpu(i) 5560 + flush_backlog(dev, i); 5563 5561 5564 5562 netdev_wait_allrefs(dev); 5565 5563