aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2013-01-28 18:51:28 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-30 17:35:44 -0500
commit70c37bf97f2a91accba76080db69144f3b69f736 (patch)
tree2c5b72a06bba90a0cfbf4b1ae93c4ba5d41278ef /drivers
parent6cdd20c380eb62eab757c5a6ccc90dac7ecd774b (diff)
net: usbnet: prevent buggy devices from killing us
A device sending 0 length frames as fast as it can has been observed killing the host system due to the resulting memory pressure. Temporarily disable RX skb allocation and URB submission when the current error ratio is high, preventing us from trying to allocate an infinite number of skbs. Reenable as soon as we are finished processing the done queue, allowing the device to continue working after short error bursts. Signed-off-by: Bjørn Mork <bjorn@mork.no> Acked-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/usb/usbnet.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index f34b2ebee815..977837725726 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -380,6 +380,12 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
380 unsigned long lockflags; 380 unsigned long lockflags;
381 size_t size = dev->rx_urb_size; 381 size_t size = dev->rx_urb_size;
382 382
383 /* prevent rx skb allocation when error ratio is high */
384 if (test_bit(EVENT_RX_KILL, &dev->flags)) {
385 usb_free_urb(urb);
386 return -ENOLINK;
387 }
388
383 skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); 389 skb = __netdev_alloc_skb_ip_align(dev->net, size, flags);
384 if (!skb) { 390 if (!skb) {
385 netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); 391 netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
@@ -539,6 +545,17 @@ block:
539 break; 545 break;
540 } 546 }
541 547
548 /* stop rx if packet error rate is high */
549 if (++dev->pkt_cnt > 30) {
550 dev->pkt_cnt = 0;
551 dev->pkt_err = 0;
552 } else {
553 if (state == rx_cleanup)
554 dev->pkt_err++;
555 if (dev->pkt_err > 20)
556 set_bit(EVENT_RX_KILL, &dev->flags);
557 }
558
542 state = defer_bh(dev, skb, &dev->rxq, state); 559 state = defer_bh(dev, skb, &dev->rxq, state);
543 560
544 if (urb) { 561 if (urb) {
@@ -791,6 +808,11 @@ int usbnet_open (struct net_device *net)
791 (dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" : 808 (dev->driver_info->flags & FLAG_FRAMING_AX) ? "ASIX" :
792 "simple"); 809 "simple");
793 810
811 /* reset rx error state */
812 dev->pkt_cnt = 0;
813 dev->pkt_err = 0;
814 clear_bit(EVENT_RX_KILL, &dev->flags);
815
794 // delay posting reads until we're fully open 816 // delay posting reads until we're fully open
795 tasklet_schedule (&dev->bh); 817 tasklet_schedule (&dev->bh);
796 if (info->manage_power) { 818 if (info->manage_power) {
@@ -1254,6 +1276,9 @@ static void usbnet_bh (unsigned long param)
1254 } 1276 }
1255 } 1277 }
1256 1278
1279 /* restart RX again after disabling due to high error rate */
1280 clear_bit(EVENT_RX_KILL, &dev->flags);
1281
1257 // waiting for all pending urbs to complete? 1282 // waiting for all pending urbs to complete?
1258 if (dev->wait) { 1283 if (dev->wait) {
1259 if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { 1284 if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {