diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 84f97f448b2d..97a30dd22c54 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -329,9 +329,14 @@ void usbnet_skb_return(struct usbnet *dev, struct sk_buff *skb) unsigned long flags; int status; - if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { - skb_queue_tail(&dev->rxq_pause, skb); - return; + if (unlikely(test_bit(EVENT_RX_PAUSED, &dev->flags))) { + spin_lock_irqsave(&dev->rxq_pause.lock, flags); + if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { + __skb_queue_tail(&dev->rxq_pause, skb); + spin_unlock_irqrestore(&dev->rxq_pause.lock, flags); + return; + } + spin_unlock_irqrestore(&dev->rxq_pause.lock, flags); } /* only update if unset to allow minidriver rx_fixup override */ @@ -698,13 +703,20 @@ EXPORT_SYMBOL_GPL(usbnet_pause_rx); void usbnet_resume_rx(struct usbnet *dev) { + struct sk_buff_head q; struct sk_buff *skb; + unsigned long flags; int num = 0; - local_bh_disable(); - clear_bit(EVENT_RX_PAUSED, &dev->flags); + __skb_queue_head_init(&q); - while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) { + local_bh_disable(); + spin_lock_irqsave(&dev->rxq_pause.lock, flags); + clear_bit(EVENT_RX_PAUSED, &dev->flags); + skb_queue_splice_init(&dev->rxq_pause, &q); + spin_unlock_irqrestore(&dev->rxq_pause.lock, flags); + + while ((skb = __skb_dequeue(&q))) { usbnet_skb_return(dev, skb); num++; }