From 3f5eb8d5688a5266ab943cf94aebe4c0eea726a3 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Nov 2011 16:41:35 -0500 Subject: [PATCH] USB: make the usbfs memory limit configurable The 16-MB global limit on memory used by usbfs isn't suitable for all people. It's a reasonable default, but there are applications (especially for SuperSpeed devices) that need a lot more. This patch (as1498) creates a writable module parameter for usbcore to control the global limit. The default is still 16 MB, but users can change it at runtime, even after usbcore has been loaded. As a special case, setting the value to 0 is treated the same as the hard limit of 2047 MB. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- Documentation/kernel-parameters.txt | 4 ++++ drivers/usb/core/devio.c | 26 ++++++++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index a0c5c5f4fce..72c68bbec5d 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2632,6 +2632,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. [USB] Start with the old device initialization scheme (default 0 = off). + usbcore.usbfs_memory_mb= + [USB] Memory limit (in MB) for buffers allocated by + usbfs (default = 16, 0 = max = 2047). + usbcore.use_both_schemes= [USB] Try the other device initialization scheme if the first one fails (default 1 = enabled). diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index b69768b7d22..d8cf06f186f 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -110,15 +110,33 @@ enum snoop_when { #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) /* Limit on the total amount of memory we can allocate for transfers */ -#define MAX_USBFS_MEMORY_USAGE 16777216 /* 16 MB */ +static unsigned usbfs_memory_mb = 16; +module_param(usbfs_memory_mb, uint, 0644); +MODULE_PARM_DESC(usbfs_memory_mb, + "maximum MB allowed for usbfs buffers (0 = no limit)"); + +/* Hard limit, necessary to avoid aithmetic overflow */ +#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ /* Check whether it's okay to allocate more memory for a transfer */ static int usbfs_increase_memory_usage(unsigned amount) { + unsigned lim; + + /* + * Convert usbfs_memory_mb to bytes, avoiding overflows. + * 0 means use the hard limit (effectively unlimited). + */ + lim = ACCESS_ONCE(usbfs_memory_mb); + if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) + lim = USBFS_XFER_MAX; + else + lim <<= 20; + atomic_add(amount, &usbfs_memory_usage); - if (atomic_read(&usbfs_memory_usage) <= MAX_USBFS_MEMORY_USAGE) + if (atomic_read(&usbfs_memory_usage) <= lim) return 0; atomic_sub(amount, &usbfs_memory_usage); return -ENOMEM; @@ -907,7 +925,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; - if (len1 > MAX_USBFS_MEMORY_USAGE) + if (len1 >= USBFS_XFER_MAX) return -EINVAL; ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); if (ret) @@ -1227,7 +1245,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, return -EINVAL; } - if (uurb->buffer_length > MAX_USBFS_MEMORY_USAGE) { + if (uurb->buffer_length >= USBFS_XFER_MAX) { ret = -EINVAL; goto error; } -- 2.11.4.GIT