aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorRuslan Bilovol <ruslan.bilovol@ti.com>2012-07-31 17:30:34 +0300
committerDmytro Kedrovskyi <x0169235@ti.com>2012-08-08 20:16:59 +0300
commit6b67035734f91d50bf8f1a5a8e6956247fe2182c (patch)
tree4ef1da6cd7531af9018933859500be2c45ad55a3 /drivers/net/usb
parent2d343dcecb3bab6cfc919e99669d42b79058d4e9 (diff)
downloadkernel_samsung_espresso10-6b67035734f91d50bf8f1a5a8e6956247fe2182c.tar.gz
kernel_samsung_espresso10-6b67035734f91d50bf8f1a5a8e6956247fe2182c.tar.bz2
kernel_samsung_espresso10-6b67035734f91d50bf8f1a5a8e6956247fe2182c.zip
net: usbnet: limit 'tx' and 'done' queue size
The dev->done queue size was not controlled Thus under heavy load (usually UDP transfers) if upper layer reads the data from this queue slowly, it may be increased to fatal size, eating all accessible memory. Now the 'done' queue size is limited by RX_QLEN + TX_QLEN Change-Id: Ie6253c07d6fa7adfccab3af66c19448c920e42a1 Signed-off-by: Ruslan Bilovol <ruslan.bilovol@ti.com>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/usbnet.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 5fd06e230c0..912ff115e99 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -68,6 +68,7 @@
(RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4)
#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
(RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4)
+#define DONE_QLEN(dev) (RX_QLEN(dev) + TX_QLEN(dev))
// reawaken network queue this soon after stopping; else watchdog barks
#define TX_TIMEOUT_JIFFIES (5*HZ)
@@ -329,6 +330,13 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
dev->udev->bus->dma_align)
net_ip_align = 0;
+ if (dev->rxq.qlen >= RX_QLEN(dev)) {
+ netif_dbg(dev, rx_err, dev->net, "rx queue full\n");
+ usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
+ usb_free_urb (urb);
+ return -ENOMEM;
+ }
+
if ((skb = alloc_skb (size + net_ip_align, flags)) == NULL) {
netif_dbg(dev, rx_err, dev->net, "no rx skb\n");
usbnet_defer_kevent (dev, EVENT_RX_MEMORY);
@@ -493,7 +501,8 @@ block:
if (urb) {
if (netif_running (dev->net) &&
- !test_bit (EVENT_RX_HALT, &dev->flags)) {
+ !test_bit (EVENT_RX_HALT, &dev->flags) &&
+ (dev->done.qlen < DONE_QLEN(dev))) {
rx_submit (dev, urb, GFP_ATOMIC);
return;
}