From 4a9ac977fdceaa8b82958c35fe849c5c6c3ec3d3 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 14 Nov 2012 01:26:09 +0800 Subject: 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 Signed-off-by: Andy Green --- drivers/net/usb/usbnet.c | 18 +++++++++++++----- 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 174aece3b90a..c61fe51e8998 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); } @@ -1219,8 +1226,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; -- cgit v1.2.3