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 14:09:07 -0500 |
commit | 3f5eb8d5688a5266ab943cf94aebe4c0eea726a3 (patch) | |
tree | f91c3a0743c1c7058704b20517f4c533c4a6dbb8 /drivers/usb/core | |
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')
-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 b69768b7d226..d8cf06f186f2 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -110,15 +110,33 @@ enum snoop_when { | |||
110 | #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) | 110 | #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) |
111 | 111 | ||
112 | /* Limit on the total amount of memory we can allocate for transfers */ | 112 | /* Limit on the total amount of memory we can allocate for transfers */ |
113 | #define MAX_USBFS_MEMORY_USAGE 16777216 /* 16 MB */ | 113 | static unsigned usbfs_memory_mb = 16; |
114 | module_param(usbfs_memory_mb, uint, 0644); | ||
115 | MODULE_PARM_DESC(usbfs_memory_mb, | ||
116 | "maximum MB allowed for usbfs buffers (0 = no limit)"); | ||
117 | |||
118 | /* Hard limit, necessary to avoid aithmetic overflow */ | ||
119 | #define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) | ||
114 | 120 | ||
115 | static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ | 121 | static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ |
116 | 122 | ||
117 | /* Check whether it's okay to allocate more memory for a transfer */ | 123 | /* Check whether it's okay to allocate more memory for a transfer */ |
118 | static int usbfs_increase_memory_usage(unsigned amount) | 124 | static int usbfs_increase_memory_usage(unsigned amount) |
119 | { | 125 | { |
126 | unsigned lim; | ||
127 | |||
128 | /* | ||
129 | * Convert usbfs_memory_mb to bytes, avoiding overflows. | ||
130 | * 0 means use the hard limit (effectively unlimited). | ||
131 | */ | ||
132 | lim = ACCESS_ONCE(usbfs_memory_mb); | ||
133 | if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) | ||
134 | lim = USBFS_XFER_MAX; | ||
135 | else | ||
136 | lim <<= 20; | ||
137 | |||
120 | atomic_add(amount, &usbfs_memory_usage); | 138 | atomic_add(amount, &usbfs_memory_usage); |
121 | if (atomic_read(&usbfs_memory_usage) <= MAX_USBFS_MEMORY_USAGE) | 139 | if (atomic_read(&usbfs_memory_usage) <= lim) |
122 | return 0; | 140 | return 0; |
123 | atomic_sub(amount, &usbfs_memory_usage); | 141 | atomic_sub(amount, &usbfs_memory_usage); |
124 | return -ENOMEM; | 142 | return -ENOMEM; |
@@ -907,7 +925,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) | |||
907 | if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) | 925 | if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) |
908 | return -EINVAL; | 926 | return -EINVAL; |
909 | len1 = bulk.len; | 927 | len1 = bulk.len; |
910 | if (len1 > MAX_USBFS_MEMORY_USAGE) | 928 | if (len1 >= USBFS_XFER_MAX) |
911 | return -EINVAL; | 929 | return -EINVAL; |
912 | ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); | 930 | ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); |
913 | if (ret) | 931 | if (ret) |
@@ -1227,7 +1245,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
1227 | return -EINVAL; | 1245 | return -EINVAL; |
1228 | } | 1246 | } |
1229 | 1247 | ||
1230 | if (uurb->buffer_length > MAX_USBFS_MEMORY_USAGE) { | 1248 | if (uurb->buffer_length >= USBFS_XFER_MAX) { |
1231 | ret = -EINVAL; | 1249 | ret = -EINVAL; |
1232 | goto error; | 1250 | goto error; |
1233 | } | 1251 | } |