]>
Commit | Line | Data |
---|---|---|
6179048a GKH |
1 | From 1129d270cbfbb7e2b1ec3dede4a13930bdd10e41 Mon Sep 17 00:00:00 2001 |
2 | From: Mateusz Berezecki <mateuszb@fastmail.fm> | |
3 | Date: Wed, 21 Dec 2016 09:19:14 -0800 | |
4 | Subject: USB: Increase usbfs transfer limit | |
5 | ||
6 | From: Mateusz Berezecki <mateuszb@fastmail.fm> | |
7 | ||
8 | commit 1129d270cbfbb7e2b1ec3dede4a13930bdd10e41 upstream. | |
9 | ||
10 | Promote a variable keeping track of USB transfer memory usage to a | |
11 | wider data type and allow for higher bandwidth transfers from a large | |
12 | number of USB devices connected to a single host. | |
13 | ||
14 | Signed-off-by: Mateusz Berezecki <mateuszb@fastmail.fm> | |
15 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
16 | ||
17 | --- | |
18 | drivers/usb/core/devio.c | 43 ++++++++++++++++--------------------------- | |
19 | 1 file changed, 16 insertions(+), 27 deletions(-) | |
20 | ||
21 | --- a/drivers/usb/core/devio.c | |
22 | +++ b/drivers/usb/core/devio.c | |
23 | @@ -134,42 +134,35 @@ enum snoop_when { | |
24 | #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) | |
25 | ||
26 | /* Limit on the total amount of memory we can allocate for transfers */ | |
27 | -static unsigned usbfs_memory_mb = 16; | |
28 | +static u32 usbfs_memory_mb = 16; | |
29 | module_param(usbfs_memory_mb, uint, 0644); | |
30 | MODULE_PARM_DESC(usbfs_memory_mb, | |
31 | "maximum MB allowed for usbfs buffers (0 = no limit)"); | |
32 | ||
33 | -/* Hard limit, necessary to avoid arithmetic overflow */ | |
34 | -#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) | |
35 | - | |
36 | -static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ | |
37 | +static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */ | |
38 | ||
39 | /* Check whether it's okay to allocate more memory for a transfer */ | |
40 | -static int usbfs_increase_memory_usage(unsigned amount) | |
41 | +static int usbfs_increase_memory_usage(u64 amount) | |
42 | { | |
43 | - unsigned lim; | |
44 | + u64 lim; | |
45 | ||
46 | - /* | |
47 | - * Convert usbfs_memory_mb to bytes, avoiding overflows. | |
48 | - * 0 means use the hard limit (effectively unlimited). | |
49 | - */ | |
50 | lim = ACCESS_ONCE(usbfs_memory_mb); | |
51 | - if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) | |
52 | - lim = USBFS_XFER_MAX; | |
53 | - else | |
54 | - lim <<= 20; | |
55 | + lim <<= 20; | |
56 | ||
57 | - atomic_add(amount, &usbfs_memory_usage); | |
58 | - if (atomic_read(&usbfs_memory_usage) <= lim) | |
59 | - return 0; | |
60 | - atomic_sub(amount, &usbfs_memory_usage); | |
61 | - return -ENOMEM; | |
62 | + atomic64_add(amount, &usbfs_memory_usage); | |
63 | + | |
64 | + if (lim > 0 && atomic64_read(&usbfs_memory_usage) > lim) { | |
65 | + atomic64_sub(amount, &usbfs_memory_usage); | |
66 | + return -ENOMEM; | |
67 | + } | |
68 | + | |
69 | + return 0; | |
70 | } | |
71 | ||
72 | /* Memory for a transfer is being deallocated */ | |
73 | -static void usbfs_decrease_memory_usage(unsigned amount) | |
74 | +static void usbfs_decrease_memory_usage(u64 amount) | |
75 | { | |
76 | - atomic_sub(amount, &usbfs_memory_usage); | |
77 | + atomic64_sub(amount, &usbfs_memory_usage); | |
78 | } | |
79 | ||
80 | static int connected(struct usb_dev_state *ps) | |
81 | @@ -1191,7 +1184,7 @@ static int proc_bulk(struct usb_dev_stat | |
82 | if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) | |
83 | return -EINVAL; | |
84 | len1 = bulk.len; | |
85 | - if (len1 >= USBFS_XFER_MAX) | |
86 | + if (len1 >= (INT_MAX - sizeof(struct urb))) | |
87 | return -EINVAL; | |
88 | ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); | |
89 | if (ret) | |
90 | @@ -1584,10 +1577,6 @@ static int proc_do_submiturb(struct usb_ | |
91 | return -EINVAL; | |
92 | } | |
93 | ||
94 | - if (uurb->buffer_length >= USBFS_XFER_MAX) { | |
95 | - ret = -EINVAL; | |
96 | - goto error; | |
97 | - } | |
98 | if (uurb->buffer_length > 0 && | |
99 | !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, | |
100 | uurb->buffer, uurb->buffer_length)) { |