From: Anton Ivanov <aivanov@brocade.com>
To: user-mode-linux-devel@lists.sourceforge.net
Cc: richard@nod.at, Anton Ivanov <aivanov@brocade.com>
Subject: [uml-devel] [PATCH 2/2] Bulk IO Transaction support part 1
Date: Mon, 21 Dec 2015 18:54:01 +0000 [thread overview]
Message-ID: <1450724041-708451-2-git-send-email-aivanov@brocade.com> (raw)
In-Reply-To: <1450724041-708451-1-git-send-email-aivanov@brocade.com>
This patch adds support for merging notifications on the ubd
notification file descriptor. Multiple transactions are processed
at a time resulting in 10-15% virtual disk speed improvement.
The mechanics are rather primitive - no ring buffers, primitive
guaranteed flush and guaranteed to-record-size read.
Signed-off-by: Anton Ivanov <aivanov@brocade.com>
---
arch/um/drivers/ubd.h | 2 +
arch/um/drivers/ubd_kern.c | 156 ++++++++++++++++++++++++++++++++++++--------
arch/um/drivers/ubd_user.c | 19 +++++-
arch/um/include/shared/os.h | 1 +
arch/um/os-Linux/file.c | 12 ++++
5 files changed, 161 insertions(+), 29 deletions(-)
diff --git a/arch/um/drivers/ubd.h b/arch/um/drivers/ubd.h
index 3b48cd2..2c5e6fd 100644
--- a/arch/um/drivers/ubd.h
+++ b/arch/um/drivers/ubd.h
@@ -10,6 +10,8 @@
extern int start_io_thread(unsigned long sp, int *fds_out);
extern int io_thread(void *arg);
extern int kernel_fd;
+extern void setup_ubd_pollfd(void * fds, int fd);
+extern int size_of_pollfd(void);
#endif
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 39ba207..9f30c50 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -58,6 +58,12 @@ struct io_thread_req {
int error;
};
+static void * kernel_pfd = NULL;
+
+struct io_thread_req **kernel_reqs;
+
+struct io_thread_req **helper_reqs;
+
static inline int ubd_test_bit(__u64 bit, unsigned char *data)
{
__u64 n;
@@ -442,6 +448,32 @@ static void do_ubd_request(struct request_queue * q);
static int thread_fd = -1;
static LIST_HEAD(restart);
+
+static int do_safe_read(int fd, void * buffer, int max_size, int record_size){
+ unsigned char * buf;
+ int n, size;
+
+ size = 0;
+ buf = (unsigned char *) buffer;
+
+ return os_read_file(fd, buf + size, max_size - size);
+
+ do {
+ n = os_read_file(fd, buf, max_size - size);
+ if ((size == 0) && (n == -EAGAIN))
+ return n;
+ if (n > 0)
+ size = size + n;
+ if ((n < 0) && (n != -EAGAIN))
+ return n;
+ if (size == max_size)
+ break;
+ } while ((size % record_size) != 0);
+
+ return size;
+}
+
+
/* XXX - move this inside ubd_intr. */
/* Called without dev->lock held, and only in interrupt context. */
static void ubd_handler(void)
@@ -450,21 +482,37 @@ static void ubd_handler(void)
struct ubd *ubd;
struct list_head *list, *next_ele;
unsigned long flags;
- int n;
+ int n, rcount, i;
while(1){
- n = os_read_file(thread_fd, &req,
- sizeof(struct io_thread_req *));
- if(n != sizeof(req)){
- if(n == -EAGAIN)
- break;
- printk(KERN_ERR "spurious interrupt in ubd_handler, "
- "err = %d\n", -n);
- return;
+ n = do_safe_read(thread_fd, helper_reqs,
+ sizeof(struct io_thread_req *) * MAX_SG,
+ sizeof(struct io_thread_req *)
+ );
+
+ if(n == -EAGAIN){
+ break;
+ }
+ if(n < 0){
+ printk("io_thread - read failed, fd = %d, "
+ "err = %d\n", thread_fd, -n);
+ }
+
+ if(n % sizeof(struct io_thread_req *) != 0){
+ printk("kernel_ubd_io - invalid read, fd = %d, "
+ "read = %d\n", thread_fd, n);
+ continue;
}
- blk_end_request(req->req, 0, req->length);
- kfree(req);
+ rcount = n / sizeof(struct io_thread_req *);
+
+ for (i = 0; i < rcount; i++) {
+
+ req = * (helper_reqs + i);
+ blk_end_request(req->req, 0, req->length);
+ kfree(req);
+
+ }
}
reactivate_fd(thread_fd, UBD_IRQ);
@@ -1080,6 +1128,26 @@ late_initcall(ubd_init);
static int __init ubd_driver_init(void){
unsigned long stack;
int err;
+
+ kernel_reqs = kmalloc(MAX_SG * sizeof(struct io_thread_req *), GFP_KERNEL);
+ if (kernel_reqs == NULL) {
+ printk("Failed to allocate memory for req buffer\n");
+ return 0;
+ }
+
+
+ kernel_pfd = kmalloc(size_of_pollfd(), GFP_KERNEL);
+ if (kernel_pfd == NULL) {
+ printk("Failed to allocate memory for pollfd\n");
+ return 0;
+ }
+
+ helper_reqs = kmalloc(MAX_SG * sizeof(struct io_thread_req *), GFP_KERNEL);
+ if (helper_reqs == NULL) {
+ printk("Failed to allocate memory for req buffer\n");
+ return 0;
+ }
+
/* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/
if(global_openflags.s){
@@ -1458,30 +1526,62 @@ static int io_count = 0;
int io_thread(void *arg)
{
struct io_thread_req *req;
- int n;
+ unsigned char * buffer;
+ int n, rcount, i;
os_fix_helper_signals();
+ printk("Starting UBD helper thread\n");
+
while(1){
- n = os_read_file(kernel_fd, &req,
- sizeof(struct io_thread_req *));
- if(n != sizeof(struct io_thread_req *)){
- if(n < 0)
- 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);
- }
+ setup_ubd_pollfd(kernel_pfd, kernel_fd);
+ os_poll(kernel_pfd, 1, -1);
+ n = do_safe_read(kernel_fd, kernel_reqs,
+ sizeof(struct io_thread_req *) * MAX_SG,
+ sizeof(struct io_thread_req *) * MAX_SG
+ );
+ if(n == -EAGAIN){
continue;
}
- io_count++;
- do_io(req);
- n = os_write_file(kernel_fd, &req,
- sizeof(struct io_thread_req *));
- if(n != sizeof(struct io_thread_req *))
+ if(n < 0){
+ printk("io_thread - read failed, fd = %d, "
+ "err = %d\n", kernel_fd, -n);
+ }
+
+ if(n % sizeof(struct io_thread_req *) != 0){
+ printk("io_thread - invalid read, fd = %d, "
+ "read = %d\n", kernel_fd, n);
+ continue;
+ }
+
+ rcount = n / sizeof(struct io_thread_req *);
+
+ for (i = 0; i < rcount; i++) {
+
+ io_count++;
+
+ req = * (kernel_reqs + i);
+
+ do_io(req);
+
+ }
+
+ buffer = (unsigned char *) kernel_reqs;
+
+ while (n > 0) {
+ i = os_write_file(kernel_fd, buffer, n);
+ if(i >= 0){
+ buffer = buffer + i;
+ n = n - i;
+ } else {
+ if(i != -EAGAIN)
+ break;
+ }
+ }
+
+ if(n > 0)
printk("io_thread - write failed, fd = %d, err = %d\n",
- kernel_fd, -n);
+ kernel_fd, -i);
}
return 0;
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
index e376f9b..3abec4f 100644
--- a/arch/um/drivers/ubd_user.c
+++ b/arch/um/drivers/ubd_user.c
@@ -17,10 +17,22 @@
#include <sys/param.h>
#include <endian.h>
#include <byteswap.h>
+#include <poll.h>
#include "ubd.h"
#include <os.h>
+void setup_ubd_pollfd(void * fds, int fd) {
+ struct pollfd * pfds = (struct pollfd *) fds;
+ pfds->fd = fd;
+ pfds->events = POLLIN | POLLPRI;
+ pfds->revents = 0;
+}
+
+int size_of_pollfd(void) {
+ return sizeof(struct pollfd);
+}
+
int start_io_thread(unsigned long sp, int *fd_out)
{
int pid, fds[2], err;
@@ -36,10 +48,15 @@ int start_io_thread(unsigned long sp, int *fd_out)
err = os_set_fd_block(*fd_out, 0);
if (err) {
- printk("start_io_thread - failed to set nonblocking I/O.\n");
+ printk("start_io_thread - failed to set nonblocking I/O - kernel_fd.\n");
goto out_close;
}
+ err = os_set_fd_block(kernel_fd, 0);
+ if (err) {
+ printk("start_io_thread - failed to set nonblocking I/O - user_fd.\n");
+ goto out_close;
+ }
pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM, NULL);
if(pid < 0){
err = -errno;
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index 7a04ddd..0b75efa 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -149,6 +149,7 @@ extern int os_file_size(const char *file, unsigned long long *size_out);
extern int os_pread_file(int fd, void *buf, int len, unsigned long long offset);
extern int os_pwrite_file(int fd, const void *buf, int count, unsigned long long offset);
extern int os_file_modtime(const char *file, unsigned long *modtime);
+extern int os_poll(void *fds, unsigned int nfds, int timeout);
extern int os_pipe(int *fd, int stream, int close_on_exec);
extern int os_set_fd_async(int fd);
extern int os_clear_fd_async(int fd);
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 2db18cb..726b1e1 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -14,6 +14,7 @@
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/types.h>
+#include <poll.h>
#include <os.h>
static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
@@ -355,6 +356,17 @@ int os_file_modtime(const char *file, unsigned long *modtime)
return 0;
}
+int os_poll(void *fds, unsigned int nfds, int timeout)
+{
+ int n;
+
+ CATCH_EINTR(n = poll((struct pollfd *) fds, nfds, timeout));
+ if (n < 0)
+ return -errno;
+
+ return n;
+}
+
int os_set_exec_close(int fd)
{
int err;
--
2.1.4
------------------------------------------------------------------------------
_______________________________________________
User-mode-linux-devel mailing list
User-mode-linux-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/user-mode-linux-devel
next prev parent reply other threads:[~2015-12-21 18:54 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-21 18:54 [uml-devel] [PATCH 1/2] Update UBD to use pread/pwrite family of functions Anton Ivanov
2015-12-21 18:54 ` Anton Ivanov [this message]
2015-12-21 19:04 ` [uml-devel] [PATCH 2/2] Bulk IO Transaction support part 1 Anton Ivanov
2016-01-10 16:00 ` Richard Weinberger
2016-01-10 16:36 ` Anton Ivanov
2016-01-10 21:51 ` Richard Weinberger
2016-01-12 21:25 ` James McMechan
2016-01-12 21:39 ` Anton Ivanov
2016-01-10 15:57 ` [uml-devel] [PATCH 1/2] Update UBD to use pread/pwrite family of functions Richard Weinberger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1450724041-708451-2-git-send-email-aivanov@brocade.com \
--to=aivanov@brocade.com \
--cc=richard@nod.at \
--cc=user-mode-linux-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).