diff options
author | Ming Lei <ming.lei@canonical.com> | 2012-11-14 01:26:09 +0800 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2012-11-14 01:26:09 +0800 |
commit | 0f3ee319c32f50aa263a0806eedbc90dc2666b1f (patch) | |
tree | 9ae7303a8367d49aedce7503edd622608ef6c4c6 | |
parent | a393db071edd3ea8b3ab1232f05f6e5d07d8bdd3 (diff) |
usbnet oom limit rx skbs in flight
via https://launchpadlibrarian.net/73187150/usbnet_oom_3.0-rc1.patch
Updated for 3.4 by Andy Green
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
-rw-r--r-- | drivers/net/usb/usbnet.c | 18 | ||||
-rw-r--r-- | include/linux/usb/usbnet.h | 3 |
2 files changed, 15 insertions, 6 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index b38db48b1ce0..948828b7c85b 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -345,14 +345,20 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) unsigned long lockflags; size_t size = dev->rx_urb_size; - skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); - if (!skb) { - netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); + if (atomic_read(&dev->rx_skb_on_fly) > MAX_RX_SKB_ON_FLY && + flags == GFP_ATOMIC) { + netif_dbg(dev, rx_err, dev->net, + "too many rx skbs on the fly\n"); +fail_rx_memory: usbnet_defer_kevent (dev, EVENT_RX_MEMORY); usb_free_urb (urb); return -ENOMEM; } - + skb = __netdev_alloc_skb_ip_align(dev->net, size, flags); + if (!skb) { + netif_dbg(dev, rx_err, dev->net, "no rx skb\n"); + goto fail_rx_memory; + } entry = (struct skb_data *) skb->cb; entry->urb = urb; entry->dev = dev; @@ -395,6 +401,7 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) } spin_unlock_irqrestore (&dev->rxq.lock, lockflags); if (retval) { + atomic_dec(&dev->rx_skb_on_fly); dev_kfree_skb_any (skb); usb_free_urb (urb); } @@ -1218,8 +1225,9 @@ static void usbnet_bh (unsigned long param) entry->state = rx_cleanup; rx_process (dev, skb); continue; - case tx_done: case rx_cleanup: + atomic_dec(&dev->rx_skb_on_fly); + case tx_done: usb_free_urb (entry->urb); dev_kfree_skb (skb); continue; diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 76f439647c4b..1bbf7c274d6a 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -33,7 +33,8 @@ struct usbnet { wait_queue_head_t *wait; struct mutex phy_mutex; unsigned char suspend_count; - + atomic_t rx_skb_on_fly; +#define MAX_RX_SKB_ON_FLY 2048 /* i/o info: pipes etc */ unsigned in, out; struct usb_host_endpoint *status; |