On SMP, usbnet_skb_return() can pass the test_bit(EVENT_RX_PAUSED) check on CPU0 while usbnet_resume_rx() clears the flag and drains rxq_pause on CPU1, leaving the skb stranded until the next MTU change or device stop. Protect the flag check and enqueue with a double-check pattern under rxq_pause.lock on the slow path, keeping the normal RX fast path lock-free. Wrap clear_bit() in usbnet_resume_rx() under the same lock. Fixes: 43daa96b166c ("usbnet: Stop RX Q on MTU change") Signed-off-by: Ă–mer Mete Kaya --- v3: Use spin_lock() inside existing local_bh_disable() section in usbnet_resume_rx() instead of spin_lock_bh(); move local_bh_enable() before queue_work() to restore BH context correctly. drivers/net/usb/usbnet.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 84f97f448b2d..d138d353fd98 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_bh(&dev->rxq_pause.lock); + if (test_bit(EVENT_RX_PAUSED, &dev->flags)) { + __skb_queue_tail(&dev->rxq_pause, skb); + spin_unlock_bh(&dev->rxq_pause.lock); + return; + } + spin_unlock_bh(&dev->rxq_pause.lock); } /* only update if unset to allow minidriver rx_fixup override */ @@ -702,15 +707,16 @@ void usbnet_resume_rx(struct usbnet *dev) int num = 0; local_bh_disable(); + spin_lock(&dev->rxq_pause.lock); clear_bit(EVENT_RX_PAUSED, &dev->flags); - + spin_unlock(&dev->rxq_pause.lock); while ((skb = skb_dequeue(&dev->rxq_pause)) != NULL) { usbnet_skb_return(dev, skb); num++; } - queue_work(system_bh_wq, &dev->bh_work); local_bh_enable(); + queue_work(system_bh_wq, &dev->bh_work); netif_dbg(dev, rx_status, dev->net, "paused rx queue disabled, %d skbs requeued\n", num); -- 2.56.0