aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-07-04 03:18:03 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-06 13:53:20 -0400
commit3d97ff63f8997761f12c8fbe8082996c6eeaba1a (patch)
treea32cd04584cf59dac78be5b2f69bb9865b69f6ea /drivers/usb/core
parent19181bc50e1b8e92a7a3b3d78637c6dc5c0b5a1b (diff)
usbdevfs: Use scatter-gather lists for large bulk transfers
When using urb->transfer_buffer we need to allocate physical contiguous buffers for the entire transfer, which is pretty much guaranteed to fail with large transfers. Currently userspace works around this by breaking large transfers into multiple urbs. For large bulk transfers this leads to all kind of complications. This patch makes it possible for userspace to reliable submit large bulk transfers to scatter-gather capable host controllers in one go, by using a scatterlist to break the transfer up in managable chunks. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/devio.c152
1 files changed, 121 insertions, 31 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 0b387c1a8b7e..ebb8a9de8b5f 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -47,6 +47,7 @@
47#include <linux/notifier.h> 47#include <linux/notifier.h>
48#include <linux/security.h> 48#include <linux/security.h>
49#include <linux/user_namespace.h> 49#include <linux/user_namespace.h>
50#include <linux/scatterlist.h>
50#include <asm/uaccess.h> 51#include <asm/uaccess.h>
51#include <asm/byteorder.h> 52#include <asm/byteorder.h>
52#include <linux/moduleparam.h> 53#include <linux/moduleparam.h>
@@ -55,6 +56,7 @@
55 56
56#define USB_MAXBUS 64 57#define USB_MAXBUS 64
57#define USB_DEVICE_MAX USB_MAXBUS * 128 58#define USB_DEVICE_MAX USB_MAXBUS * 128
59#define USB_SG_SIZE 16384 /* split-size for large txs */
58 60
59/* Mutual exclusion for removal, open, and release */ 61/* Mutual exclusion for removal, open, and release */
60DEFINE_MUTEX(usbfs_mutex); 62DEFINE_MUTEX(usbfs_mutex);
@@ -285,9 +287,16 @@ static struct async *alloc_async(unsigned int numisoframes)
285 287
286static void free_async(struct async *as) 288static void free_async(struct async *as)
287{ 289{
290 int i;
291
288 put_pid(as->pid); 292 put_pid(as->pid);
289 if (as->cred) 293 if (as->cred)
290 put_cred(as->cred); 294 put_cred(as->cred);
295 for (i = 0; i < as->urb->num_sgs; i++) {
296 if (sg_page(&as->urb->sg[i]))
297 kfree(sg_virt(&as->urb->sg[i]));
298 }
299 kfree(as->urb->sg);
291 kfree(as->urb->transfer_buffer); 300 kfree(as->urb->transfer_buffer);
292 kfree(as->urb->setup_packet); 301 kfree(as->urb->setup_packet);
293 usb_free_urb(as->urb); 302 usb_free_urb(as->urb);
@@ -388,6 +397,53 @@ static void snoop_urb(struct usb_device *udev,
388 } 397 }
389} 398}
390 399
400static void snoop_urb_data(struct urb *urb, unsigned len)
401{
402 int i, size;
403
404 if (!usbfs_snoop)
405 return;
406
407 if (urb->num_sgs == 0) {
408 print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
409 urb->transfer_buffer, len, 1);
410 return;
411 }
412
413 for (i = 0; i < urb->num_sgs && len; i++) {
414 size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
415 print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
416 sg_virt(&urb->sg[i]), size, 1);
417 len -= size;
418 }
419}
420
421static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)
422{
423 unsigned i, len, size;
424
425 if (urb->number_of_packets > 0) /* Isochronous */
426 len = urb->transfer_buffer_length;
427 else /* Non-Isoc */
428 len = urb->actual_length;
429
430 if (urb->num_sgs == 0) {
431 if (copy_to_user(userbuffer, urb->transfer_buffer, len))
432 return -EFAULT;
433 return 0;
434 }
435
436 for (i = 0; i < urb->num_sgs && len; i++) {
437 size = (len > USB_SG_SIZE) ? USB_SG_SIZE : len;
438 if (copy_to_user(userbuffer, sg_virt(&urb->sg[i]), size))
439 return -EFAULT;
440 userbuffer += size;
441 len -= size;
442 }
443
444 return 0;
445}
446
391#define AS_CONTINUATION 1 447#define AS_CONTINUATION 1
392#define AS_UNLINK 2 448#define AS_UNLINK 2
393 449
@@ -454,9 +510,10 @@ static void async_completed(struct urb *urb)
454 } 510 }
455 snoop(&urb->dev->dev, "urb complete\n"); 511 snoop(&urb->dev->dev, "urb complete\n");
456 snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length, 512 snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
457 as->status, COMPLETE, 513 as->status, COMPLETE, NULL, 0);
458 ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_OUT) ? 514 if ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_IN)
459 NULL : urb->transfer_buffer, urb->actual_length); 515 snoop_urb_data(urb, urb->actual_length);
516
460 if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET && 517 if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
461 as->status != -ENOENT) 518 as->status != -ENOENT)
462 cancel_bulk_urbs(ps, as->bulk_addr); 519 cancel_bulk_urbs(ps, as->bulk_addr);
@@ -1114,8 +1171,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
1114 struct async *as = NULL; 1171 struct async *as = NULL;
1115 struct usb_ctrlrequest *dr = NULL; 1172 struct usb_ctrlrequest *dr = NULL;
1116 unsigned int u, totlen, isofrmlen; 1173 unsigned int u, totlen, isofrmlen;
1117 int ret, ifnum = -1; 1174 int i, ret, is_in, num_sgs = 0, ifnum = -1;
1118 int is_in; 1175 void *buf;
1119 1176
1120 if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | 1177 if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
1121 USBDEVFS_URB_SHORT_NOT_OK | 1178 USBDEVFS_URB_SHORT_NOT_OK |
@@ -1199,6 +1256,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
1199 goto interrupt_urb; 1256 goto interrupt_urb;
1200 } 1257 }
1201 uurb->number_of_packets = 0; 1258 uurb->number_of_packets = 0;
1259 num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);
1260 if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)
1261 num_sgs = 0;
1202 break; 1262 break;
1203 1263
1204 case USBDEVFS_URB_TYPE_INTERRUPT: 1264 case USBDEVFS_URB_TYPE_INTERRUPT:
@@ -1255,26 +1315,67 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
1255 ret = -ENOMEM; 1315 ret = -ENOMEM;
1256 goto error; 1316 goto error;
1257 } 1317 }
1258 u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length; 1318
1319 u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length +
1320 num_sgs * sizeof(struct scatterlist);
1259 ret = usbfs_increase_memory_usage(u); 1321 ret = usbfs_increase_memory_usage(u);
1260 if (ret) 1322 if (ret)
1261 goto error; 1323 goto error;
1262 as->mem_usage = u; 1324 as->mem_usage = u;
1263 1325
1264 if (uurb->buffer_length > 0) { 1326 if (num_sgs) {
1327 as->urb->sg = kmalloc(num_sgs * sizeof(struct scatterlist),
1328 GFP_KERNEL);
1329 if (!as->urb->sg) {
1330 ret = -ENOMEM;
1331 goto error;
1332 }
1333 as->urb->num_sgs = num_sgs;
1334 sg_init_table(as->urb->sg, as->urb->num_sgs);
1335
1336 totlen = uurb->buffer_length;
1337 for (i = 0; i < as->urb->num_sgs; i++) {
1338 u = (totlen > USB_SG_SIZE) ? USB_SG_SIZE : totlen;
1339 buf = kmalloc(u, GFP_KERNEL);
1340 if (!buf) {
1341 ret = -ENOMEM;
1342 goto error;
1343 }
1344 sg_set_buf(&as->urb->sg[i], buf, u);
1345
1346 if (!is_in) {
1347 if (copy_from_user(buf, uurb->buffer, u)) {
1348 ret = -EFAULT;
1349 goto error;
1350 }
1351 }
1352 totlen -= u;
1353 }
1354 } else if (uurb->buffer_length > 0) {
1265 as->urb->transfer_buffer = kmalloc(uurb->buffer_length, 1355 as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
1266 GFP_KERNEL); 1356 GFP_KERNEL);
1267 if (!as->urb->transfer_buffer) { 1357 if (!as->urb->transfer_buffer) {
1268 ret = -ENOMEM; 1358 ret = -ENOMEM;
1269 goto error; 1359 goto error;
1270 } 1360 }
1271 /* Isochronous input data may end up being discontiguous 1361
1272 * if some of the packets are short. Clear the buffer so 1362 if (!is_in) {
1273 * that the gaps don't leak kernel data to userspace. 1363 if (copy_from_user(as->urb->transfer_buffer,
1274 */ 1364 uurb->buffer,
1275 if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO) 1365 uurb->buffer_length)) {
1366 ret = -EFAULT;
1367 goto error;
1368 }
1369 } else if (uurb->type == USBDEVFS_URB_TYPE_ISO) {
1370 /*
1371 * Isochronous input data may end up being
1372 * discontiguous if some of the packets are short.
1373 * Clear the buffer so that the gaps don't leak
1374 * kernel data to userspace.
1375 */
1276 memset(as->urb->transfer_buffer, 0, 1376 memset(as->urb->transfer_buffer, 0,
1277 uurb->buffer_length); 1377 uurb->buffer_length);
1378 }
1278 } 1379 }
1279 as->urb->dev = ps->dev; 1380 as->urb->dev = ps->dev;
1280 as->urb->pipe = (uurb->type << 30) | 1381 as->urb->pipe = (uurb->type << 30) |
@@ -1328,17 +1429,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
1328 as->pid = get_pid(task_pid(current)); 1429 as->pid = get_pid(task_pid(current));
1329 as->cred = get_current_cred(); 1430 as->cred = get_current_cred();
1330 security_task_getsecid(current, &as->secid); 1431 security_task_getsecid(current, &as->secid);
1331 if (!is_in && uurb->buffer_length > 0) {
1332 if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
1333 uurb->buffer_length)) {
1334 ret = -EFAULT;
1335 goto error;
1336 }
1337 }
1338 snoop_urb(ps->dev, as->userurb, as->urb->pipe, 1432 snoop_urb(ps->dev, as->userurb, as->urb->pipe,
1339 as->urb->transfer_buffer_length, 0, SUBMIT, 1433 as->urb->transfer_buffer_length, 0, SUBMIT,
1340 is_in ? NULL : as->urb->transfer_buffer, 1434 NULL, 0);
1341 uurb->buffer_length); 1435 if (!is_in)
1436 snoop_urb_data(as->urb, as->urb->transfer_buffer_length);
1437
1342 async_newpending(as); 1438 async_newpending(as);
1343 1439
1344 if (usb_endpoint_xfer_bulk(&ep->desc)) { 1440 if (usb_endpoint_xfer_bulk(&ep->desc)) {
@@ -1433,11 +1529,7 @@ static int processcompl(struct async *as, void __user * __user *arg)
1433 unsigned int i; 1529 unsigned int i;
1434 1530
1435 if (as->userbuffer && urb->actual_length) { 1531 if (as->userbuffer && urb->actual_length) {
1436 if (urb->number_of_packets > 0) /* Isochronous */ 1532 if (copy_urb_data_to_user(as->userbuffer, urb))
1437 i = urb->transfer_buffer_length;
1438 else /* Non-Isoc */
1439 i = urb->actual_length;
1440 if (copy_to_user(as->userbuffer, urb->transfer_buffer, i))
1441 goto err_out; 1533 goto err_out;
1442 } 1534 }
1443 if (put_user(as->status, &userurb->status)) 1535 if (put_user(as->status, &userurb->status))
@@ -1605,11 +1697,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
1605 unsigned int i; 1697 unsigned int i;
1606 1698
1607 if (as->userbuffer && urb->actual_length) { 1699 if (as->userbuffer && urb->actual_length) {
1608 if (urb->number_of_packets > 0) /* Isochronous */ 1700 if (copy_urb_data_to_user(as->userbuffer, urb))
1609 i = urb->transfer_buffer_length;
1610 else /* Non-Isoc */
1611 i = urb->actual_length;
1612 if (copy_to_user(as->userbuffer, urb->transfer_buffer, i))
1613 return -EFAULT; 1701 return -EFAULT;
1614 } 1702 }
1615 if (put_user(as->status, &userurb->status)) 1703 if (put_user(as->status, &userurb->status))
@@ -1831,6 +1919,8 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg)
1831 caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM; 1919 caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM;
1832 if (!ps->dev->bus->no_stop_on_short) 1920 if (!ps->dev->bus->no_stop_on_short)
1833 caps |= USBDEVFS_CAP_BULK_CONTINUATION; 1921 caps |= USBDEVFS_CAP_BULK_CONTINUATION;
1922 if (ps->dev->bus->sg_tablesize)
1923 caps |= USBDEVFS_CAP_BULK_SCATTER_GATHER;
1834 1924
1835 if (put_user(caps, (__u32 __user *)arg)) 1925 if (put_user(caps, (__u32 __user *)arg))
1836 return -EFAULT; 1926 return -EFAULT;