Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+167 -27
+5
arch/um/drivers/ubd.h
··· 11 11 extern int io_thread(void *arg); 12 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 19 #endif 15 20
+142 -26
arch/um/drivers/ubd_kern.c
··· 1 1 /* 2 + * Copyright (C) 2015-2016 Anton Ivanov (aivanov@brocade.com) 2 3 * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) 3 4 * Licensed under the GPL 4 5 */ ··· 58 57 unsigned long bitmap_words[2]; 59 58 int error; 60 59 }; 60 + 61 + 62 + static struct io_thread_req * (*irq_req_buffer)[]; 63 + static struct io_thread_req *irq_remainder; 64 + static int irq_remainder_size; 65 + 66 + static struct io_thread_req * (*io_req_buffer)[]; 67 + static struct io_thread_req *io_remainder; 68 + static int io_remainder_size; 69 + 70 + 61 71 62 72 static inline int ubd_test_bit(__u64 bit, unsigned char *data) 63 73 { ··· 454 442 static int thread_fd = -1; 455 443 static LIST_HEAD(restart); 456 444 457 - /* XXX - move this inside ubd_intr. */ 445 + /* Function to read several request pointers at a time 446 + * handling fractional reads if (and as) needed 447 + */ 448 + 449 + static int bulk_req_safe_read( 450 + int fd, 451 + struct io_thread_req * (*request_buffer)[], 452 + struct io_thread_req **remainder, 453 + int *remainder_size, 454 + int max_recs 455 + ) 456 + { 457 + int n = 0; 458 + int res = 0; 459 + 460 + if (*remainder_size > 0) { 461 + memmove( 462 + (char *) request_buffer, 463 + (char *) remainder, *remainder_size 464 + ); 465 + n = *remainder_size; 466 + } 467 + 468 + res = os_read_file( 469 + fd, 470 + ((char *) request_buffer) + *remainder_size, 471 + sizeof(struct io_thread_req *)*max_recs 472 + - *remainder_size 473 + ); 474 + if (res > 0) { 475 + n += res; 476 + if ((n % sizeof(struct io_thread_req *)) > 0) { 477 + /* 478 + * Read somehow returned not a multiple of dword 479 + * theoretically possible, but never observed in the 480 + * wild, so read routine must be able to handle it 481 + */ 482 + *remainder_size = n % sizeof(struct io_thread_req *); 483 + WARN(*remainder_size > 0, "UBD IPC read returned a partial result"); 484 + memmove( 485 + remainder, 486 + ((char *) request_buffer) + 487 + (n/sizeof(struct io_thread_req *))*sizeof(struct io_thread_req *), 488 + *remainder_size 489 + ); 490 + n = n - *remainder_size; 491 + } 492 + } else { 493 + n = res; 494 + } 495 + return n; 496 + } 497 + 458 498 /* Called without dev->lock held, and only in interrupt context. */ 459 499 static void ubd_handler(void) 460 500 { 461 - struct io_thread_req *req; 462 501 struct ubd *ubd; 463 502 struct list_head *list, *next_ele; 464 503 unsigned long flags; 465 504 int n; 505 + int count; 466 506 467 507 while(1){ 468 - n = os_read_file(thread_fd, &req, 469 - sizeof(struct io_thread_req *)); 470 - if(n != sizeof(req)){ 508 + n = bulk_req_safe_read( 509 + thread_fd, 510 + irq_req_buffer, 511 + &irq_remainder, 512 + &irq_remainder_size, 513 + UBD_REQ_BUFFER_SIZE 514 + ); 515 + if (n < 0) { 471 516 if(n == -EAGAIN) 472 517 break; 473 518 printk(KERN_ERR "spurious interrupt in ubd_handler, " 474 519 "err = %d\n", -n); 475 520 return; 476 521 } 477 - 478 - blk_end_request(req->req, 0, req->length); 479 - kfree(req); 522 + for (count = 0; count < n/sizeof(struct io_thread_req *); count++) { 523 + blk_end_request( 524 + (*irq_req_buffer)[count]->req, 525 + 0, 526 + (*irq_req_buffer)[count]->length 527 + ); 528 + kfree((*irq_req_buffer)[count]); 529 + } 480 530 } 481 531 reactivate_fd(thread_fd, UBD_IRQ); 482 532 ··· 1138 1064 if (register_blkdev(fake_major, "ubd")) 1139 1065 return -1; 1140 1066 } 1067 + 1068 + irq_req_buffer = kmalloc( 1069 + sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE, 1070 + GFP_KERNEL 1071 + ); 1072 + irq_remainder = 0; 1073 + 1074 + if (irq_req_buffer == NULL) { 1075 + printk(KERN_ERR "Failed to initialize ubd buffering\n"); 1076 + return -1; 1077 + } 1078 + io_req_buffer = kmalloc( 1079 + sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE, 1080 + GFP_KERNEL 1081 + ); 1082 + 1083 + io_remainder = 0; 1084 + 1085 + if (io_req_buffer == NULL) { 1086 + printk(KERN_ERR "Failed to initialize ubd buffering\n"); 1087 + return -1; 1088 + } 1141 1089 platform_driver_register(&ubd_driver); 1142 1090 mutex_lock(&ubd_lock); 1143 1091 for (i = 0; i < MAX_DEV; i++){ ··· 1554 1458 1555 1459 int io_thread(void *arg) 1556 1460 { 1557 - struct io_thread_req *req; 1558 - int n; 1461 + int n, count, written, res; 1559 1462 1560 1463 os_fix_helper_signals(); 1561 1464 1562 1465 while(1){ 1563 - n = os_read_file(kernel_fd, &req, 1564 - sizeof(struct io_thread_req *)); 1565 - if(n != sizeof(struct io_thread_req *)){ 1566 - if(n < 0) 1466 + n = bulk_req_safe_read( 1467 + kernel_fd, 1468 + io_req_buffer, 1469 + &io_remainder, 1470 + &io_remainder_size, 1471 + UBD_REQ_BUFFER_SIZE 1472 + ); 1473 + if (n < 0) { 1474 + if (n == -EAGAIN) { 1475 + ubd_read_poll(-1); 1476 + continue; 1477 + } else { 1567 1478 printk("io_thread - read failed, fd = %d, " 1568 - "err = %d\n", kernel_fd, -n); 1569 - else { 1570 - printk("io_thread - short read, fd = %d, " 1571 - "length = %d\n", kernel_fd, n); 1479 + "err = %d," 1480 + "reminder = %d\n", 1481 + kernel_fd, -n, io_remainder_size); 1572 1482 } 1573 - continue; 1574 1483 } 1575 - io_count++; 1576 - do_io(req); 1577 - n = os_write_file(kernel_fd, &req, 1578 - sizeof(struct io_thread_req *)); 1579 - if(n != sizeof(struct io_thread_req *)) 1580 - printk("io_thread - write failed, fd = %d, err = %d\n", 1581 - kernel_fd, -n); 1484 + 1485 + for (count = 0; count < n/sizeof(struct io_thread_req *); count++) { 1486 + io_count++; 1487 + do_io((*io_req_buffer)[count]); 1488 + } 1489 + 1490 + written = 0; 1491 + 1492 + do { 1493 + res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n); 1494 + if (res > 0) { 1495 + written += res; 1496 + } else { 1497 + if (res != -EAGAIN) { 1498 + printk("io_thread - read failed, fd = %d, " 1499 + "err = %d\n", kernel_fd, -n); 1500 + } 1501 + } 1502 + if (written < n) { 1503 + ubd_write_poll(-1); 1504 + } 1505 + } while (written < n); 1582 1506 } 1583 1507 1584 1508 return 0;
+20 -1
arch/um/drivers/ubd_user.c
··· 1 - /* 1 + /* 2 + * Copyright (C) 2016 Anton Ivanov (aivanov@brocade.com) 2 3 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) 3 4 * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com) 4 5 * Licensed under the GPL ··· 21 20 22 21 #include "ubd.h" 23 22 #include <os.h> 23 + #include <poll.h> 24 + 25 + struct pollfd kernel_pollfd; 24 26 25 27 int start_io_thread(unsigned long sp, int *fd_out) 26 28 { ··· 36 32 } 37 33 38 34 kernel_fd = fds[0]; 35 + kernel_pollfd.fd = kernel_fd; 36 + kernel_pollfd.events = POLLIN; 39 37 *fd_out = fds[1]; 40 38 41 39 err = os_set_fd_block(*fd_out, 0); 40 + err = os_set_fd_block(kernel_fd, 0); 42 41 if (err) { 43 42 printk("start_io_thread - failed to set nonblocking I/O.\n"); 44 43 goto out_close; ··· 64 57 out: 65 58 return err; 66 59 } 60 + 61 + int ubd_read_poll(int timeout) 62 + { 63 + kernel_pollfd.events = POLLIN; 64 + return poll(&kernel_pollfd, 1, timeout); 65 + } 66 + int ubd_write_poll(int timeout) 67 + { 68 + kernel_pollfd.events = POLLOUT; 69 + return poll(&kernel_pollfd, 1, timeout); 70 + } 71 +