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: Bjørn Mork <bjorn@mork.no>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4c3a5bdae2
commit
85e87870fa
1 changed files with 12 additions and 4 deletions
|
@ -1201,19 +1201,26 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
|
|||
}
|
||||
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;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
/* don't refill the queue all at once */
|
||||
for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) {
|
||||
urb = usb_alloc_urb(0, flags);
|
||||
if (urb != NULL) {
|
||||
if (rx_submit(dev, urb, flags) == -ENOLINK)
|
||||
return;
|
||||
ret = rx_submit(dev, urb, flags);
|
||||
if (ret)
|
||||
goto err;
|
||||
} else {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
@ -1257,7 +1264,8 @@ static void usbnet_bh (unsigned long param)
|
|||
int temp = dev->rxq.qlen;
|
||||
|
||||
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)
|
||||
netif_dbg(dev, link, dev->net,
|
||||
"rxqlen %d --> %d\n",
|
||||
|
|
Loading…
Reference in a new issue