From 661db034e3423f4b538a1f64ca1d6b295c1916da Mon Sep 17 00:00:00 2001 Message-Id: <661db034e3423f4b538a1f64ca1d6b295c1916da.1427300678.git.jen@redhat.com> In-Reply-To: References: From: Vlad Yasevich Date: Thu, 12 Mar 2015 19:13:04 -0500 Subject: [CHANGE 08/33] aio: add I/O handlers to the AioContext interface To: rhvirt-patches@redhat.com, jen@redhat.com RH-Author: Vlad Yasevich Message-id: <1426187601-21396-9-git-send-email-vyasevic@redhat.com> Patchwork-id: 64348 O-Subject: [RHEL6.7 qemu-kvm PATCH v2 08/25] aio: add I/O handlers to the AioContext interface Bugzilla: 1005016 RH-Acked-by: Michael S. Tsirkin RH-Acked-by: Juan Quintela RH-Acked-by: Paolo Bonzini From: Paolo Bonzini With this patch, I/O handlers (including event notifier handlers) can be attached to a single AioContext. Signed-off-by: Paolo Bonzini (cherry picked from commit a915f4bc977c4f3aab08a78023c1303664d1c606) Signed-off-by: Jeff E. Nelson Conflicts: aio.c async.c main-loop.c qemu-aio.h Signed-off-by: Vladislav Yasevich --- aio.c | 56 ++++++++++++++++++++------------------------------------ async.c | 30 ++++++++++++++++++++++++++++++ qemu-aio.h | 38 ++++++++++++++++++++++++++++++-------- 3 files changed, 80 insertions(+), 44 deletions(-) Signed-off-by: Jeff E. Nelson --- aio.c | 56 ++++++++++++++++++++------------------------------------ async.c | 30 ++++++++++++++++++++++++++++++ qemu-aio.h | 38 ++++++++++++++++++++++++++++++-------- 3 files changed, 80 insertions(+), 44 deletions(-) diff --git a/aio.c b/aio.c index aba0d9b..91302f9 100644 --- a/aio.c +++ b/aio.c @@ -16,15 +16,6 @@ #include "qemu-queue.h" #include "qemu_socket.h" -/* The list of registered AIO handlers */ -static QLIST_HEAD(, AioHandler) aio_handlers; - -/* This is a simple lock used to protect the aio_handlers list. Specifically, - * it's used to ensure that no callbacks are removed while we're walking and - * dispatching callbacks. - */ -static int walking_handlers; - struct AioHandler { int fd; @@ -36,11 +27,11 @@ struct AioHandler QLIST_ENTRY(AioHandler) node; }; -static AioHandler *find_aio_handler(int fd) +static AioHandler *find_aio_handler(AioContext *ctx, int fd) { AioHandler *node; - QLIST_FOREACH(node, &aio_handlers, node) { + QLIST_FOREACH(node, &ctx->aio_handlers, node) { if (node->fd == fd) if (!node->deleted) return node; @@ -49,21 +40,22 @@ static AioHandler *find_aio_handler(int fd) return NULL; } -int qemu_aio_set_fd_handler(int fd, - IOHandler *io_read, - IOHandler *io_write, - AioFlushHandler *io_flush, - void *opaque) +void aio_set_fd_handler(AioContext *ctx, + int fd, + IOHandler *io_read, + IOHandler *io_write, + AioFlushHandler *io_flush, + void *opaque) { AioHandler *node; - node = find_aio_handler(fd); + node = find_aio_handler(ctx, fd); /* Are we deleting the fd handler? */ if (!io_read && !io_write) { if (node) { /* If the lock is held, just mark the node as deleted */ - if (walking_handlers) + if (ctx->walking_handlers) node->deleted = 1; else { /* Otherwise, delete it for real. We can't just mark it as @@ -79,7 +71,7 @@ int qemu_aio_set_fd_handler(int fd, /* Alloc and insert if it's not already there */ node = qemu_mallocz(sizeof(AioHandler)); node->fd = fd; - QLIST_INSERT_HEAD(&aio_handlers, node, node); + QLIST_INSERT_HEAD(&ctx->aio_handlers, node, node); } /* Update handler with latest information */ node->io_read = io_read; @@ -87,18 +79,10 @@ int qemu_aio_set_fd_handler(int fd, node->io_flush = io_flush; node->opaque = opaque; } - - qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque); - - return 0; } -void qemu_aio_flush(void) -{ - while (qemu_aio_wait()); -} -bool qemu_aio_wait(void) +bool aio_wait(AioContext *ctx) { AioHandler *node; fd_set rdfds, wrfds; @@ -111,18 +95,18 @@ bool qemu_aio_wait(void) * Do not call select in this case, because it is possible that the caller * does not need a complete flush (as is the case for qemu_aio_wait loops). */ - if (qemu_bh_poll()) { + if (aio_bh_poll(ctx)) { return true; } - walking_handlers++; + ctx->walking_handlers++; FD_ZERO(&rdfds); FD_ZERO(&wrfds); /* fill fd sets */ busy = false; - QLIST_FOREACH(node, &aio_handlers, node) { + QLIST_FOREACH(node, &ctx->aio_handlers, node) { /* If there aren't pending AIO operations, don't invoke callbacks. * Otherwise, if there are no AIO requests, qemu_aio_wait() would * wait indefinitely. @@ -143,7 +127,7 @@ bool qemu_aio_wait(void) } } - walking_handlers--; + ctx->walking_handlers--; /* No AIO operations? Get us out of here */ if (!busy) { @@ -157,11 +141,11 @@ bool qemu_aio_wait(void) if (ret > 0) { /* we have to walk very carefully in case * qemu_aio_set_fd_handler is called while we're walking */ - node = QLIST_FIRST(&aio_handlers); + node = QLIST_FIRST(&ctx->aio_handlers); while (node) { AioHandler *tmp; - walking_handlers++; + ctx->walking_handlers++; if (!node->deleted && FD_ISSET(node->fd, &rdfds) && @@ -177,9 +161,9 @@ bool qemu_aio_wait(void) tmp = node; node = QLIST_NEXT(node, node); - walking_handlers--; + ctx->walking_handlers--; - if (!walking_handlers && tmp->deleted) { + if (!ctx->walking_handlers && tmp->deleted) { QLIST_REMOVE(tmp, node); g_free(tmp); } diff --git a/async.c b/async.c index db614a0..7d4ffac 100644 --- a/async.c +++ b/async.c @@ -24,6 +24,7 @@ #include "qemu-common.h" #include "qemu-aio.h" +#include "qemu-char.h" /***********************************************************/ /* bottom halves (can be seen as timers which expire ASAP) */ @@ -135,11 +136,17 @@ void aio_bh_update_timeout(AioContext *ctx, uint32_t *timeout) } } + AioContext *aio_context_new(void) { return g_new0(AioContext, 1); } +void aio_flush(AioContext *ctx) +{ + while (aio_wait(ctx)); +} + /* * Wrappers using a static global context. */ @@ -167,3 +174,26 @@ void qemu_bh_update_timeout(uint32_t *timeout) { aio_bh_update_timeout(qemu_aio_context(), timeout); } + + +void qemu_aio_flush(void) +{ + aio_flush(qemu_aio_context()); +} + +bool qemu_aio_wait(void) +{ + return aio_wait(qemu_aio_context()); +} + +void qemu_aio_set_fd_handler(int fd, + IOHandler *io_read, + IOHandler *io_write, + AioFlushHandler *io_flush, + void *opaque) +{ + aio_set_fd_handler(qemu_aio_context(), fd, io_read, io_write, io_flush, + opaque); + + qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque); +} diff --git a/qemu-aio.h b/qemu-aio.h index 5282778..3f2821f 100644 --- a/qemu-aio.h +++ b/qemu-aio.h @@ -16,6 +16,7 @@ #include "qemu-common.h" #include "qerror.h" +#include "qemu-queue.h" typedef struct BlockDriverAIOCB BlockDriverAIOCB; typedef void BlockDriverCompletionFunc(void *opaque, int ret); @@ -42,6 +43,15 @@ typedef struct AioHandler AioHandler; typedef void IOHandler(void *opaque); typedef struct AioContext { + /* The list of registered AIO handlers */ + QLIST_HEAD(, AioHandler) aio_handlers; + + /* This is a simple lock used to protect the aio_handlers list. + * Specifically, it's used to ensure that no callbacks are removed while + * we're walking and dispatching callbacks. + */ + int walking_handlers; + /* Anchor of the list of Bottom Halves belonging to the context */ struct QEMUBH *first_bh; @@ -125,15 +135,16 @@ void qemu_bh_delete(QEMUBH *bh); /* Flush any pending AIO operation. This function will block until all * outstanding AIO operations have been completed or cancelled. */ -void qemu_aio_flush(void); +void aio_flush(AioContext *ctx); /* Wait for a single AIO completion to occur. This function will wait * until a single AIO event has completed and it will ensure something * has moved before returning. This can issue new pending aio as * result of executing I/O completion or bh callbacks. * - * Return whether there is still any pending AIO operation. */ -bool qemu_aio_wait(void); + * Return whether there is still any pending AIO operation. + */ +bool aio_wait(AioContext *ctx); /* Register a file descriptor and associated callbacks. Behaves very similarly * to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will @@ -142,10 +153,21 @@ bool qemu_aio_wait(void); * Code that invokes AIO completion functions should rely on this function * instead of qemu_set_fd_handler[2]. */ -int qemu_aio_set_fd_handler(int fd, - IOHandler *io_read, - IOHandler *io_write, - AioFlushHandler *io_flush, - void *opaque); +void aio_set_fd_handler(AioContext *ctx, + int fd, + IOHandler *io_read, + IOHandler *io_write, + AioFlushHandler *io_flush, + void *opaque); +/* Functions to operate on the main QEMU AioContext. */ + +void qemu_aio_flush(void); +bool qemu_aio_wait(void); + +void qemu_aio_set_fd_handler(int fd, + IOHandler *io_read, + IOHandler *io_write, + AioFlushHandler *io_flush, + void *opaque); #endif -- 2.1.0