Commit 85e87870fa18ec9f5df98e2d3b48f3699560a570
Committed by
David S. Miller
1 parent
4c3a5bdae2
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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", |