Commit 85e87870 authored by Bjørn Mork's avatar Bjørn Mork Committed by David S. Miller

net: usbnet: fix softirq storm on suspend

Suspending an open usbnet device results in constant
rescheduling of usbnet_bh.

commit 65841fd5 "usbnet: handle remote wakeup asap"
refactored the usbnet_bh code to allow sharing the
urb allocate and submit code with usbnet_resume. In
this process, a test for, and immediate return on,
ENOLINK from rx_submit was unintentionally dropped.

The rx queue will not grow if rx_submit fails,
making usbnet_bh reschedule itself.  This results
in a softirq storm if the error is persistent.
rx_submit translates the usb_submit_urb error
EHOSTUNREACH into ENOLINK, so this is an expected
and persistent error for a suspended device. The
old code tested for this condition and avoided
rescheduling.  Putting this test back.

Cc: <stable@vger.kernel.org> # v3.5
Cc: Ming Lei <ming.lei@canonical.com>
Cc: Oliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarBjørn Mork <bjorn@mork.no>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4c3a5bda
...@@ -1201,19 +1201,26 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, ...@@ -1201,19 +1201,26 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
} }
EXPORT_SYMBOL_GPL(usbnet_start_xmit); EXPORT_SYMBOL_GPL(usbnet_start_xmit);
static void rx_alloc_submit(struct usbnet *dev, gfp_t flags) static int rx_alloc_submit(struct usbnet *dev, gfp_t flags)
{ {
struct urb *urb; struct urb *urb;
int i; int i;
int ret = 0;
/* don't refill the queue all at once */ /* don't refill the queue all at once */
for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) { for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) {
urb = usb_alloc_urb(0, flags); urb = usb_alloc_urb(0, flags);
if (urb != NULL) { if (urb != NULL) {
if (rx_submit(dev, urb, flags) == -ENOLINK) ret = rx_submit(dev, urb, flags);
return; if (ret)
goto err;
} else {
ret = -ENOMEM;
goto err;
} }
} }
err:
return ret;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -1257,7 +1264,8 @@ static void usbnet_bh (unsigned long param) ...@@ -1257,7 +1264,8 @@ static void usbnet_bh (unsigned long param)
int temp = dev->rxq.qlen; int temp = dev->rxq.qlen;
if (temp < RX_QLEN(dev)) { if (temp < RX_QLEN(dev)) {
rx_alloc_submit(dev, GFP_ATOMIC); if (rx_alloc_submit(dev, GFP_ATOMIC) == -ENOLINK)
return;
if (temp != dev->rxq.qlen) if (temp != dev->rxq.qlen)
netif_dbg(dev, link, dev->net, netif_dbg(dev, link, dev->net,
"rxqlen %d --> %d\n", "rxqlen %d --> %d\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment