aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-16 12:35:03 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-16 12:35:03 -0500
commit9936f44add987355a7d79d52e48cd12255651c0d (patch)
tree4c876efd9f14a939534689ed89b1221467046d56
parent70f56cbbdc4ffccbea77e6f51ce9afcbda5fc20f (diff)
parentf88f0bdfc32f3d1e2fd03ec8a7f7b456df4db725 (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.h5
-rw-r--r--arch/um/drivers/ubd_kern.c168
-rw-r--r--arch/um/drivers/ubd_user.c21
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);
11extern int io_thread(void *arg); 11extern int io_thread(void *arg);
12extern int kernel_fd; 12extern int kernel_fd;
13 13
14extern int ubd_read_poll(int timeout);
15extern 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
63static struct io_thread_req * (*irq_req_buffer)[];
64static struct io_thread_req *irq_remainder;
65static int irq_remainder_size;
66
67static struct io_thread_req * (*io_req_buffer)[];
68static struct io_thread_req *io_remainder;
69static int io_remainder_size;
70
71
72
61static inline int ubd_test_bit(__u64 bit, unsigned char *data) 73static 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);
442static int thread_fd = -1; 454static int thread_fd = -1;
443static LIST_HEAD(restart); 455static 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
461static 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. */
447static void ubd_handler(void) 511static 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
1459int io_thread(void *arg) 1555int 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
26struct pollfd kernel_pollfd;
23 27
24int start_io_thread(unsigned long sp, int *fd_out) 28int 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
68int ubd_read_poll(int timeout)
69{
70 kernel_pollfd.events = POLLIN;
71 return poll(&kernel_pollfd, 1, timeout);
72}
73int ubd_write_poll(int timeout)
74{
75 kernel_pollfd.events = POLLOUT;
76 return poll(&kernel_pollfd, 1, timeout);
77}
78