diff options
| author | Alan Stern <stern@rowland.harvard.edu> | 2011-11-17 16:41:35 -0500 | 
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-11-18 11:09:07 -0800 | 
| commit | 3f5eb8d5688a5266ab943cf94aebe4c0eea726a3 (patch) | |
| tree | f91c3a0743c1c7058704b20517f4c533c4a6dbb8 /drivers/usb/core/devio.c | |
| parent | add1aaeabe6b08ed26381a2a06e505b2f09c3ba5 (diff) | |
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>
Diffstat (limited to 'drivers/usb/core/devio.c')
| -rw-r--r-- | drivers/usb/core/devio.c | 26 | 
1 files changed, 22 insertions, 4 deletions
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;  	}  | 
