Commit 85e87870fa18ec9f5df98e2d3b48f3699560a570

Authored by Bjørn Mork
Committed by David S. Miller
1 parent 4c3a5bdae2

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>

Showing 1 changed file with 12 additions and 4 deletions Side-by-side Diff

drivers/net/usb/usbnet.c
... ... @@ -1201,19 +1201,26 @@
1201 1201 }
1202 1202 EXPORT_SYMBOL_GPL(usbnet_start_xmit);
1203 1203  
1204   -static void rx_alloc_submit(struct usbnet *dev, gfp_t flags)
  1204 +static int rx_alloc_submit(struct usbnet *dev, gfp_t flags)
1205 1205 {
1206 1206 struct urb *urb;
1207 1207 int i;
  1208 + int ret = 0;
1208 1209  
1209 1210 /* don't refill the queue all at once */
1210 1211 for (i = 0; i < 10 && dev->rxq.qlen < RX_QLEN(dev); i++) {
1211 1212 urb = usb_alloc_urb(0, flags);
1212 1213 if (urb != NULL) {
1213   - if (rx_submit(dev, urb, flags) == -ENOLINK)
1214   - return;
  1214 + ret = rx_submit(dev, urb, flags);
  1215 + if (ret)
  1216 + goto err;
  1217 + } else {
  1218 + ret = -ENOMEM;
  1219 + goto err;
1215 1220 }
1216 1221 }
  1222 +err:
  1223 + return ret;
1217 1224 }
1218 1225  
1219 1226 /*-------------------------------------------------------------------------*/
... ... @@ -1257,7 +1264,8 @@
1257 1264 int temp = dev->rxq.qlen;
1258 1265  
1259 1266 if (temp < RX_QLEN(dev)) {
1260   - rx_alloc_submit(dev, GFP_ATOMIC);
  1267 + if (rx_alloc_submit(dev, GFP_ATOMIC) == -ENOLINK)
  1268 + return;
1261 1269 if (temp != dev->rxq.qlen)
1262 1270 netif_dbg(dev, link, dev->net,
1263 1271 "rxqlen %d --> %d\n",