diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-16 12:35:03 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-16 12:35:03 -0500 |
commit | 9936f44add987355a7d79d52e48cd12255651c0d (patch) | |
tree | 4c876efd9f14a939534689ed89b1221467046d56 | |
parent | 70f56cbbdc4ffccbea77e6f51ce9afcbda5fc20f (diff) | |
parent | f88f0bdfc32f3d1e2fd03ec8a7f7b456df4db725 (diff) |
Merge branch 'for-linus-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML update from Richard Weinberger:
"A performance enhancement for UML's block driver"
* 'for-linus-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml:
um: UBD Improvements
-rw-r--r-- | arch/um/drivers/ubd.h | 5 | ||||
-rw-r--r-- | arch/um/drivers/ubd_kern.c | 168 | ||||
-rw-r--r-- | arch/um/drivers/ubd_user.c | 21 |
3 files changed, 167 insertions, 27 deletions
diff --git a/arch/um/drivers/ubd.h b/arch/um/drivers/ubd.h index 3b48cd2081ee..cc1cc85f5afc 100644 --- a/arch/um/drivers/ubd.h +++ b/arch/um/drivers/ubd.h | |||
@@ -11,5 +11,10 @@ extern int start_io_thread(unsigned long sp, int *fds_out); | |||
11 | extern int io_thread(void *arg); | 11 | extern int io_thread(void *arg); |
12 | extern int kernel_fd; | 12 | extern int kernel_fd; |
13 | 13 | ||
14 | extern int ubd_read_poll(int timeout); | ||
15 | extern int ubd_write_poll(int timeout); | ||
16 | |||
17 | #define UBD_REQ_BUFFER_SIZE 64 | ||
18 | |||
14 | #endif | 19 | #endif |
15 | 20 | ||
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index f3540270d096..85410279beab 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2015-2016 Anton Ivanov (aivanov@brocade.com) | ||
2 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) | 3 | * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) |
3 | * Licensed under the GPL | 4 | * Licensed under the GPL |
4 | */ | 5 | */ |
@@ -58,6 +59,17 @@ struct io_thread_req { | |||
58 | int error; | 59 | int error; |
59 | }; | 60 | }; |
60 | 61 | ||
62 | |||
63 | static struct io_thread_req * (*irq_req_buffer)[]; | ||
64 | static struct io_thread_req *irq_remainder; | ||
65 | static int irq_remainder_size; | ||
66 | |||
67 | static struct io_thread_req * (*io_req_buffer)[]; | ||
68 | static struct io_thread_req *io_remainder; | ||
69 | static int io_remainder_size; | ||
70 | |||
71 | |||
72 | |||
61 | static inline int ubd_test_bit(__u64 bit, unsigned char *data) | 73 | static inline int ubd_test_bit(__u64 bit, unsigned char *data) |
62 | { | 74 | { |
63 | __u64 n; | 75 | __u64 n; |
@@ -442,29 +454,91 @@ static void do_ubd_request(struct request_queue * q); | |||
442 | static int thread_fd = -1; | 454 | static int thread_fd = -1; |
443 | static LIST_HEAD(restart); | 455 | static LIST_HEAD(restart); |
444 | 456 | ||
445 | /* XXX - move this inside ubd_intr. */ | 457 | /* Function to read several request pointers at a time |
458 | * handling fractional reads if (and as) needed | ||
459 | */ | ||
460 | |||
461 | static int bulk_req_safe_read( | ||
462 | int fd, | ||
463 | struct io_thread_req * (*request_buffer)[], | ||
464 | struct io_thread_req **remainder, | ||
465 | int *remainder_size, | ||
466 | int max_recs | ||
467 | ) | ||
468 | { | ||
469 | int n = 0; | ||
470 | int res = 0; | ||
471 | |||
472 | if (*remainder_size > 0) { | ||
473 | memmove( | ||
474 | (char *) request_buffer, | ||
475 | (char *) remainder, *remainder_size | ||
476 | ); | ||
477 | n = *remainder_size; | ||
478 | } | ||
479 | |||
480 | res = os_read_file( | ||
481 | fd, | ||
482 | ((char *) request_buffer) + *remainder_size, | ||
483 | sizeof(struct io_thread_req *)*max_recs | ||
484 | - *remainder_size | ||
485 | ); | ||
486 | if (res > 0) { | ||
487 | n += res; | ||
488 | if ((n % sizeof(struct io_thread_req *)) > 0) { | ||
489 | /* | ||
490 | * Read somehow returned not a multiple of dword | ||
491 | * theoretically possible, but never observed in the | ||
492 | * wild, so read routine must be able to handle it | ||
493 | */ | ||
494 | *remainder_size = n % sizeof(struct io_thread_req *); | ||
495 | WARN(*remainder_size > 0, "UBD IPC read returned a partial result"); | ||
496 | memmove( | ||
497 | remainder, | ||
498 | ((char *) request_buffer) + | ||
499 | (n/sizeof(struct io_thread_req *))*sizeof(struct io_thread_req *), | ||
500 | *remainder_size | ||
501 | ); | ||
502 | n = n - *remainder_size; | ||
503 | } | ||
504 | } else { | ||
505 | n = res; | ||
506 | } | ||
507 | return n; | ||
508 | } | ||
509 | |||
446 | /* Called without dev->lock held, and only in interrupt context. */ | 510 | /* Called without dev->lock held, and only in interrupt context. */ |
447 | static void ubd_handler(void) | 511 | static void ubd_handler(void) |
448 | { | 512 | { |
449 | struct io_thread_req *req; | ||
450 | struct ubd *ubd; | 513 | struct ubd *ubd; |
451 | struct list_head *list, *next_ele; | 514 | struct list_head *list, *next_ele; |
452 | unsigned long flags; | 515 | unsigned long flags; |
453 | int n; | 516 | int n; |
517 | int count; | ||
454 | 518 | ||
455 | while(1){ | 519 | while(1){ |
456 | n = os_read_file(thread_fd, &req, | 520 | n = bulk_req_safe_read( |
457 | sizeof(struct io_thread_req *)); | 521 | thread_fd, |
458 | if(n != sizeof(req)){ | 522 | irq_req_buffer, |
523 | &irq_remainder, | ||
524 | &irq_remainder_size, | ||
525 | UBD_REQ_BUFFER_SIZE | ||
526 | ); | ||
527 | if (n < 0) { | ||
459 | if(n == -EAGAIN) | 528 | if(n == -EAGAIN) |
460 | break; | 529 | break; |
461 | printk(KERN_ERR "spurious interrupt in ubd_handler, " | 530 | printk(KERN_ERR "spurious interrupt in ubd_handler, " |
462 | "err = %d\n", -n); | 531 | "err = %d\n", -n); |
463 | return; | 532 | return; |
464 | } | 533 | } |
465 | 534 | for (count = 0; count < n/sizeof(struct io_thread_req *); count++) { | |
466 | blk_end_request(req->req, 0, req->length); | 535 | blk_end_request( |
467 | kfree(req); | 536 | (*irq_req_buffer)[count]->req, |
537 | 0, | ||
538 | (*irq_req_buffer)[count]->length | ||
539 | ); | ||
540 | kfree((*irq_req_buffer)[count]); | ||
541 | } | ||
468 | } | 542 | } |
469 | reactivate_fd(thread_fd, UBD_IRQ); | 543 | reactivate_fd(thread_fd, UBD_IRQ); |
470 | 544 | ||
@@ -1064,6 +1138,28 @@ static int __init ubd_init(void) | |||
1064 | if (register_blkdev(fake_major, "ubd")) | 1138 | if (register_blkdev(fake_major, "ubd")) |
1065 | return -1; | 1139 | return -1; |
1066 | } | 1140 | } |
1141 | |||
1142 | irq_req_buffer = kmalloc( | ||
1143 | sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE, | ||
1144 | GFP_KERNEL | ||
1145 | ); | ||
1146 | irq_remainder = 0; | ||
1147 | |||
1148 | if (irq_req_buffer == NULL) { | ||
1149 | printk(KERN_ERR "Failed to initialize ubd buffering\n"); | ||
1150 | return -1; | ||
1151 | } | ||
1152 | io_req_buffer = kmalloc( | ||
1153 | sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE, | ||
1154 | GFP_KERNEL | ||
1155 | ); | ||
1156 | |||
1157 | io_remainder = 0; | ||
1158 | |||
1159 | if (io_req_buffer == NULL) { | ||
1160 | printk(KERN_ERR "Failed to initialize ubd buffering\n"); | ||
1161 | return -1; | ||
1162 | } | ||
1067 | platform_driver_register(&ubd_driver); | 1163 | platform_driver_register(&ubd_driver); |
1068 | mutex_lock(&ubd_lock); | 1164 | mutex_lock(&ubd_lock); |
1069 | for (i = 0; i < MAX_DEV; i++){ | 1165 | for (i = 0; i < MAX_DEV; i++){ |
@@ -1458,31 +1554,51 @@ static int io_count = 0; | |||
1458 | 1554 | ||
1459 | int io_thread(void *arg) | 1555 | int io_thread(void *arg) |
1460 | { | 1556 | { |
1461 | struct io_thread_req *req; | 1557 | int n, count, written, res; |
1462 | int n; | ||
1463 | 1558 | ||
1464 | os_fix_helper_signals(); | 1559 | os_fix_helper_signals(); |
1465 | 1560 | ||
1466 | while(1){ | 1561 | while(1){ |
1467 | n = os_read_file(kernel_fd, &req, | 1562 | n = bulk_req_safe_read( |
1468 | sizeof(struct io_thread_req *)); | 1563 | kernel_fd, |
1469 | if(n != sizeof(struct io_thread_req *)){ | 1564 | io_req_buffer, |
1470 | if(n < 0) | 1565 | &io_remainder, |
1566 | &io_remainder_size, | ||
1567 | UBD_REQ_BUFFER_SIZE | ||
1568 | ); | ||
1569 | if (n < 0) { | ||
1570 | if (n == -EAGAIN) { | ||
1571 | ubd_read_poll(-1); | ||
1572 | continue; | ||
1573 | } else { | ||
1471 | printk("io_thread - read failed, fd = %d, " | 1574 | printk("io_thread - read failed, fd = %d, " |
1472 | "err = %d\n", kernel_fd, -n); | 1575 | "err = %d," |
1473 | else { | 1576 | "reminder = %d\n", |
1474 | printk("io_thread - short read, fd = %d, " | 1577 | kernel_fd, -n, io_remainder_size); |
1475 | "length = %d\n", kernel_fd, n); | ||
1476 | } | 1578 | } |
1477 | continue; | ||
1478 | } | 1579 | } |
1479 | io_count++; | 1580 | |
1480 | do_io(req); | 1581 | for (count = 0; count < n/sizeof(struct io_thread_req *); count++) { |
1481 | n = os_write_file(kernel_fd, &req, | 1582 | io_count++; |
1482 | sizeof(struct io_thread_req *)); | 1583 | do_io((*io_req_buffer)[count]); |
1483 | if(n != sizeof(struct io_thread_req *)) | 1584 | } |
1484 | printk("io_thread - write failed, fd = %d, err = %d\n", | 1585 | |
1485 | kernel_fd, -n); | 1586 | written = 0; |
1587 | |||
1588 | do { | ||
1589 | res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n); | ||
1590 | if (res > 0) { | ||
1591 | written += res; | ||
1592 | } else { | ||
1593 | if (res != -EAGAIN) { | ||
1594 | printk("io_thread - read failed, fd = %d, " | ||
1595 | "err = %d\n", kernel_fd, -n); | ||
1596 | } | ||
1597 | } | ||
1598 | if (written < n) { | ||
1599 | ubd_write_poll(-1); | ||
1600 | } | ||
1601 | } while (written < n); | ||
1486 | } | 1602 | } |
1487 | 1603 | ||
1488 | return 0; | 1604 | return 0; |
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index e376f9b9c68d..6f744794d141 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c | |||
@@ -1,4 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2016 Anton Ivanov (aivanov@brocade.com) | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | 3 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) |
3 | * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com) | 4 | * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com) |
4 | * Licensed under the GPL | 5 | * Licensed under the GPL |
@@ -20,6 +21,9 @@ | |||
20 | 21 | ||
21 | #include "ubd.h" | 22 | #include "ubd.h" |
22 | #include <os.h> | 23 | #include <os.h> |
24 | #include <poll.h> | ||
25 | |||
26 | struct pollfd kernel_pollfd; | ||
23 | 27 | ||
24 | int start_io_thread(unsigned long sp, int *fd_out) | 28 | int start_io_thread(unsigned long sp, int *fd_out) |
25 | { | 29 | { |
@@ -32,9 +36,12 @@ int start_io_thread(unsigned long sp, int *fd_out) | |||
32 | } | 36 | } |
33 | 37 | ||
34 | kernel_fd = fds[0]; | 38 | kernel_fd = fds[0]; |
39 | kernel_pollfd.fd = kernel_fd; | ||
40 | kernel_pollfd.events = POLLIN; | ||
35 | *fd_out = fds[1]; | 41 | *fd_out = fds[1]; |
36 | 42 | ||
37 | err = os_set_fd_block(*fd_out, 0); | 43 | err = os_set_fd_block(*fd_out, 0); |
44 | err = os_set_fd_block(kernel_fd, 0); | ||
38 | if (err) { | 45 | if (err) { |
39 | printk("start_io_thread - failed to set nonblocking I/O.\n"); | 46 | printk("start_io_thread - failed to set nonblocking I/O.\n"); |
40 | goto out_close; | 47 | goto out_close; |
@@ -57,3 +64,15 @@ int start_io_thread(unsigned long sp, int *fd_out) | |||
57 | out: | 64 | out: |
58 | return err; | 65 | return err; |
59 | } | 66 | } |
67 | |||
68 | int ubd_read_poll(int timeout) | ||
69 | { | ||
70 | kernel_pollfd.events = POLLIN; | ||
71 | return poll(&kernel_pollfd, 1, timeout); | ||
72 | } | ||
73 | int ubd_write_poll(int timeout) | ||
74 | { | ||
75 | kernel_pollfd.events = POLLOUT; | ||
76 | return poll(&kernel_pollfd, 1, timeout); | ||
77 | } | ||
78 | |||