Commit f88f0bdf authored by Anton Ivanov's avatar Anton Ivanov Committed by Richard Weinberger

um: UBD Improvements

UBD at present is extremely slow because it handles only
one request at a time in the IO thread and IRQ handler.

The single request at a time is replaced by handling multiple
requests as well as necessary workarounds for short reads/writes.

Resulting performance improvement in disk IO - 30%
Signed-off-by: default avatarAnton Ivanov <aivanov@kot-begemot.co.uk>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 69973b83
......@@ -11,5 +11,10 @@ extern int start_io_thread(unsigned long sp, int *fds_out);
extern int io_thread(void *arg);
extern int kernel_fd;
extern int ubd_read_poll(int timeout);
extern int ubd_write_poll(int timeout);
#define UBD_REQ_BUFFER_SIZE 64
#endif
/*
* Copyright (C) 2015-2016 Anton Ivanov (aivanov@brocade.com)
* Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
......@@ -58,6 +59,17 @@ struct io_thread_req {
int error;
};
static struct io_thread_req * (*irq_req_buffer)[];
static struct io_thread_req *irq_remainder;
static int irq_remainder_size;
static struct io_thread_req * (*io_req_buffer)[];
static struct io_thread_req *io_remainder;
static int io_remainder_size;
static inline int ubd_test_bit(__u64 bit, unsigned char *data)
{
__u64 n;
......@@ -442,29 +454,91 @@ static void do_ubd_request(struct request_queue * q);
static int thread_fd = -1;
static LIST_HEAD(restart);
/* XXX - move this inside ubd_intr. */
/* Function to read several request pointers at a time
* handling fractional reads if (and as) needed
*/
static int bulk_req_safe_read(
int fd,
struct io_thread_req * (*request_buffer)[],
struct io_thread_req **remainder,
int *remainder_size,
int max_recs
)
{
int n = 0;
int res = 0;
if (*remainder_size > 0) {
memmove(
(char *) request_buffer,
(char *) remainder, *remainder_size
);
n = *remainder_size;
}
res = os_read_file(
fd,
((char *) request_buffer) + *remainder_size,
sizeof(struct io_thread_req *)*max_recs
- *remainder_size
);
if (res > 0) {
n += res;
if ((n % sizeof(struct io_thread_req *)) > 0) {
/*
* Read somehow returned not a multiple of dword
* theoretically possible, but never observed in the
* wild, so read routine must be able to handle it
*/
*remainder_size = n % sizeof(struct io_thread_req *);
WARN(*remainder_size > 0, "UBD IPC read returned a partial result");
memmove(
remainder,
((char *) request_buffer) +
(n/sizeof(struct io_thread_req *))*sizeof(struct io_thread_req *),
*remainder_size
);
n = n - *remainder_size;
}
} else {
n = res;
}
return n;
}
/* Called without dev->lock held, and only in interrupt context. */
static void ubd_handler(void)
{
struct io_thread_req *req;
struct ubd *ubd;
struct list_head *list, *next_ele;
unsigned long flags;
int n;
int count;
while(1){
n = os_read_file(thread_fd, &req,
sizeof(struct io_thread_req *));
if(n != sizeof(req)){
n = bulk_req_safe_read(
thread_fd,
irq_req_buffer,
&irq_remainder,
&irq_remainder_size,
UBD_REQ_BUFFER_SIZE
);
if (n < 0) {
if(n == -EAGAIN)
break;
printk(KERN_ERR "spurious interrupt in ubd_handler, "
"err = %d\n", -n);
return;
}
blk_end_request(req->req, 0, req->length);
kfree(req);
for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
blk_end_request(
(*irq_req_buffer)[count]->req,
0,
(*irq_req_buffer)[count]->length
);
kfree((*irq_req_buffer)[count]);
}
}
reactivate_fd(thread_fd, UBD_IRQ);
......@@ -1064,6 +1138,28 @@ static int __init ubd_init(void)
if (register_blkdev(fake_major, "ubd"))
return -1;
}
irq_req_buffer = kmalloc(
sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE,
GFP_KERNEL
);
irq_remainder = 0;
if (irq_req_buffer == NULL) {
printk(KERN_ERR "Failed to initialize ubd buffering\n");
return -1;
}
io_req_buffer = kmalloc(
sizeof(struct io_thread_req *) * UBD_REQ_BUFFER_SIZE,
GFP_KERNEL
);
io_remainder = 0;
if (io_req_buffer == NULL) {
printk(KERN_ERR "Failed to initialize ubd buffering\n");
return -1;
}
platform_driver_register(&ubd_driver);
mutex_lock(&ubd_lock);
for (i = 0; i < MAX_DEV; i++){
......@@ -1458,31 +1554,51 @@ static int io_count = 0;
int io_thread(void *arg)
{
struct io_thread_req *req;
int n;
int n, count, written, res;
os_fix_helper_signals();
while(1){
n = os_read_file(kernel_fd, &req,
sizeof(struct io_thread_req *));
if(n != sizeof(struct io_thread_req *)){
if(n < 0)
n = bulk_req_safe_read(
kernel_fd,
io_req_buffer,
&io_remainder,
&io_remainder_size,
UBD_REQ_BUFFER_SIZE
);
if (n < 0) {
if (n == -EAGAIN) {
ubd_read_poll(-1);
continue;
} else {
printk("io_thread - read failed, fd = %d, "
"err = %d\n", kernel_fd, -n);
else {
printk("io_thread - short read, fd = %d, "
"length = %d\n", kernel_fd, n);
"err = %d,"
"reminder = %d\n",
kernel_fd, -n, io_remainder_size);
}
continue;
}
for (count = 0; count < n/sizeof(struct io_thread_req *); count++) {
io_count++;
do_io(req);
n = os_write_file(kernel_fd, &req,
sizeof(struct io_thread_req *));
if(n != sizeof(struct io_thread_req *))
printk("io_thread - write failed, fd = %d, err = %d\n",
kernel_fd, -n);
do_io((*io_req_buffer)[count]);
}
written = 0;
do {
res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n);
if (res > 0) {
written += res;
} else {
if (res != -EAGAIN) {
printk("io_thread - read failed, fd = %d, "
"err = %d\n", kernel_fd, -n);
}
}
if (written < n) {
ubd_write_poll(-1);
}
} while (written < n);
}
return 0;
......
/*
* Copyright (C) 2016 Anton Ivanov (aivanov@brocade.com)
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com)
* Licensed under the GPL
......@@ -20,6 +21,9 @@
#include "ubd.h"
#include <os.h>
#include <poll.h>
struct pollfd kernel_pollfd;
int start_io_thread(unsigned long sp, int *fd_out)
{
......@@ -32,9 +36,12 @@ int start_io_thread(unsigned long sp, int *fd_out)
}
kernel_fd = fds[0];
kernel_pollfd.fd = kernel_fd;
kernel_pollfd.events = POLLIN;
*fd_out = fds[1];
err = os_set_fd_block(*fd_out, 0);
err = os_set_fd_block(kernel_fd, 0);
if (err) {
printk("start_io_thread - failed to set nonblocking I/O.\n");
goto out_close;
......@@ -57,3 +64,15 @@ int start_io_thread(unsigned long sp, int *fd_out)
out:
return err;
}
int ubd_read_poll(int timeout)
{
kernel_pollfd.events = POLLIN;
return poll(&kernel_pollfd, 1, timeout);
}
int ubd_write_poll(int timeout)
{
kernel_pollfd.events = POLLOUT;
return poll(&kernel_pollfd, 1, timeout);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment