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 <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index a0c5c5f..72c68bb 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2632,6 +2632,10 @@
[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 b69768b..d8cf06f 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -110,15 +110,33 @@
#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 @@
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 @@
return -EINVAL;
}
- if (uurb->buffer_length > MAX_USBFS_MEMORY_USAGE) {
+ if (uurb->buffer_length >= USBFS_XFER_MAX) {
ret = -EINVAL;
goto error;
}