[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 06/18] dataplane: add Linux AIO request queue
From: |
Stefan Hajnoczi |
Subject: |
[Qemu-devel] [PATCH 06/18] dataplane: add Linux AIO request queue |
Date: |
Wed, 19 Dec 2012 16:38:07 +0100 |
The IOQueue has a pool of iocb structs and a function to add new
read/write requests. Multiple requests can be added before calling the
submit function to actually tell the host kernel to begin I/O. This
allows callers to batch requests and submit them in one go.
The actual I/O is performed using Linux AIO.
Signed-off-by: Stefan Hajnoczi <address@hidden>
---
hw/dataplane/Makefile.objs | 2 +-
hw/dataplane/ioq.c | 117 +++++++++++++++++++++++++++++++++++++++++++++
hw/dataplane/ioq.h | 57 ++++++++++++++++++++++
3 files changed, 175 insertions(+), 1 deletion(-)
create mode 100644 hw/dataplane/ioq.c
create mode 100644 hw/dataplane/ioq.h
diff --git a/hw/dataplane/Makefile.objs b/hw/dataplane/Makefile.objs
index e26bd7d..abd408f 100644
--- a/hw/dataplane/Makefile.objs
+++ b/hw/dataplane/Makefile.objs
@@ -1,3 +1,3 @@
ifeq ($(CONFIG_VIRTIO), y)
-common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o
+common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += hostmem.o vring.o event-poll.o
ioq.o
endif
diff --git a/hw/dataplane/ioq.c b/hw/dataplane/ioq.c
new file mode 100644
index 0000000..0c9f5c4
--- /dev/null
+++ b/hw/dataplane/ioq.c
@@ -0,0 +1,117 @@
+/*
+ * Linux AIO request queue
+ *
+ * Copyright 2012 IBM, Corp.
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Stefan Hajnoczi <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hw/dataplane/ioq.h"
+
+void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs)
+{
+ int rc;
+
+ ioq->fd = fd;
+ ioq->max_reqs = max_reqs;
+
+ memset(&ioq->io_ctx, 0, sizeof ioq->io_ctx);
+ rc = io_setup(max_reqs, &ioq->io_ctx);
+ if (rc != 0) {
+ fprintf(stderr, "ioq io_setup failed %d\n", rc);
+ exit(1);
+ }
+
+ rc = event_notifier_init(&ioq->io_notifier, 0);
+ if (rc != 0) {
+ fprintf(stderr, "ioq io event notifier creation failed %d\n", rc);
+ exit(1);
+ }
+
+ ioq->freelist = g_malloc0(sizeof ioq->freelist[0] * max_reqs);
+ ioq->freelist_idx = 0;
+
+ ioq->queue = g_malloc0(sizeof ioq->queue[0] * max_reqs);
+ ioq->queue_idx = 0;
+}
+
+void ioq_cleanup(IOQueue *ioq)
+{
+ g_free(ioq->freelist);
+ g_free(ioq->queue);
+
+ event_notifier_cleanup(&ioq->io_notifier);
+ io_destroy(ioq->io_ctx);
+}
+
+EventNotifier *ioq_get_notifier(IOQueue *ioq)
+{
+ return &ioq->io_notifier;
+}
+
+struct iocb *ioq_get_iocb(IOQueue *ioq)
+{
+ /* Underflow cannot happen since ioq is sized for max_reqs */
+ assert(ioq->freelist_idx != 0);
+
+ struct iocb *iocb = ioq->freelist[--ioq->freelist_idx];
+ ioq->queue[ioq->queue_idx++] = iocb;
+ return iocb;
+}
+
+void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb)
+{
+ /* Overflow cannot happen since ioq is sized for max_reqs */
+ assert(ioq->freelist_idx != ioq->max_reqs);
+
+ ioq->freelist[ioq->freelist_idx++] = iocb;
+}
+
+struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov,
+ unsigned int count, long long offset)
+{
+ struct iocb *iocb = ioq_get_iocb(ioq);
+
+ if (read) {
+ io_prep_preadv(iocb, ioq->fd, iov, count, offset);
+ } else {
+ io_prep_pwritev(iocb, ioq->fd, iov, count, offset);
+ }
+ io_set_eventfd(iocb, event_notifier_get_fd(&ioq->io_notifier));
+ return iocb;
+}
+
+int ioq_submit(IOQueue *ioq)
+{
+ int rc = io_submit(ioq->io_ctx, ioq->queue_idx, ioq->queue);
+ ioq->queue_idx = 0; /* reset */
+ return rc;
+}
+
+int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion,
+ void *opaque)
+{
+ struct io_event events[ioq->max_reqs];
+ int nevents, i;
+
+ do {
+ nevents = io_getevents(ioq->io_ctx, 0, ioq->max_reqs, events, NULL);
+ } while (nevents < 0 && errno == EINTR);
+ if (nevents < 0) {
+ return nevents;
+ }
+
+ for (i = 0; i < nevents; i++) {
+ ssize_t ret = ((uint64_t)events[i].res2 << 32) | events[i].res;
+
+ completion(events[i].obj, ret, opaque);
+ ioq_put_iocb(ioq, events[i].obj);
+ }
+ return nevents;
+}
diff --git a/hw/dataplane/ioq.h b/hw/dataplane/ioq.h
new file mode 100644
index 0000000..890db22
--- /dev/null
+++ b/hw/dataplane/ioq.h
@@ -0,0 +1,57 @@
+/*
+ * Linux AIO request queue
+ *
+ * Copyright 2012 IBM, Corp.
+ * Copyright 2012 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Stefan Hajnoczi <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef IOQ_H
+#define IOQ_H
+
+#include <libaio.h>
+#include "event_notifier.h"
+
+typedef struct {
+ int fd; /* file descriptor */
+ unsigned int max_reqs; /* max length of freelist and queue */
+
+ io_context_t io_ctx; /* Linux AIO context */
+ EventNotifier io_notifier; /* Linux AIO eventfd */
+
+ /* Requests can complete in any order so a free list is necessary to manage
+ * available iocbs.
+ */
+ struct iocb **freelist; /* free iocbs */
+ unsigned int freelist_idx;
+
+ /* Multiple requests are queued up before submitting them all in one go */
+ struct iocb **queue; /* queued iocbs */
+ unsigned int queue_idx;
+} IOQueue;
+
+void ioq_init(IOQueue *ioq, int fd, unsigned int max_reqs);
+void ioq_cleanup(IOQueue *ioq);
+EventNotifier *ioq_get_notifier(IOQueue *ioq);
+struct iocb *ioq_get_iocb(IOQueue *ioq);
+void ioq_put_iocb(IOQueue *ioq, struct iocb *iocb);
+struct iocb *ioq_rdwr(IOQueue *ioq, bool read, struct iovec *iov,
+ unsigned int count, long long offset);
+int ioq_submit(IOQueue *ioq);
+
+static inline unsigned int ioq_num_queued(IOQueue *ioq)
+{
+ return ioq->queue_idx;
+}
+
+typedef void IOQueueCompletion(struct iocb *iocb, ssize_t ret, void *opaque);
+int ioq_run_completion(IOQueue *ioq, IOQueueCompletion *completion,
+ void *opaque);
+
+#endif /* IOQ_H */
--
1.8.0.2
- [Qemu-devel] [PULL 00/18] Block patches, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 01/18] raw-posix: add raw_get_aio_fd() for virtio-blk-data-plane, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 02/18] configure: add CONFIG_VIRTIO_BLK_DATA_PLANE, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 03/18] dataplane: add host memory mapping code, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 04/18] dataplane: add virtqueue vring code, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 06/18] dataplane: add Linux AIO request queue,
Stefan Hajnoczi <=
- [Qemu-devel] [PATCH 05/18] dataplane: add event loop, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 10/18] virtio-blk: restore VirtIOBlkConf->config_wce flag, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 09/18] iov: add qemu_iovec_concat_iov(), Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 12/18] virtio-blk: add x-data-plane=on|off performance feature, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 11/18] dataplane: add virtio-blk data plane code, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 13/18] virtio-blk: Return UNSUPP for unknown request types, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 14/18] cutils: change strtosz_suffix_unit function, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 16/18] block/raw-win32: Fix compiler warnings (wrong format specifiers), Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 15/18] qemu-img: report size overflow error message, Stefan Hajnoczi, 2012/12/19
- [Qemu-devel] [PATCH 08/18] test-iov: add iov_discard_front/back() testcases, Stefan Hajnoczi, 2012/12/19