virtio-blk dataplane currently creates/manages it's own thread to offload work to a separate event loop.
This patch insteads allows us to specify a QContext-based event loop by adding a "context" property for virtio-blk we can use like so: qemu ... \ -object glib-qcontext,id=ctx0,threaded=yes -drive file=file.raw,id=drive0,aio=native,cache=none \ -device virtio-blk,drive=drive0,scsi=off,x-data-plane=on,context=ctx0 virtio-blk dataplane then simply attachs/detaches it's AioContext to the ctx0 event loop on start/stop. This also makes available the option to drive a virtio-blk dataplane via the default main loop: qemu ... \ -drive file=file.raw,id=drive0,aio=native,cache=none \ -device virtio-blk,drive=drive0,scsi=off,x-data-plane=on,context=main This doesn't do much in and of itself, but helps to demonstrate how we might model a general mechanism to offload device workloads to separate threads. Signed-off-by: Michael Roth <mdr...@linux.vnet.ibm.com> --- hw/block/dataplane/virtio-blk.c | 46 ++++++++++++--------------------------- include/hw/virtio/virtio-blk.h | 7 ++++-- 2 files changed, 19 insertions(+), 34 deletions(-) diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 0356665..08ea10f 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -24,6 +24,8 @@ #include "virtio-blk.h" #include "block/aio.h" #include "hw/virtio/virtio-bus.h" +#include "qcontext/qcontext.h" +#include "qcontext/glib-qcontext.h" enum { SEG_MAX = 126, /* maximum number of I/O segments */ @@ -60,6 +62,7 @@ struct VirtIOBlockDataPlane { * use it). */ AioContext *ctx; + QContext *qctx; EventNotifier io_notifier; /* Linux AIO completion */ EventNotifier host_notifier; /* doorbell */ @@ -375,26 +378,6 @@ static void handle_io(EventNotifier *e) } } -static void *data_plane_thread(void *opaque) -{ - VirtIOBlockDataPlane *s = opaque; - - do { - aio_poll(s->ctx, true); - } while (!s->stopping || s->num_reqs > 0); - return NULL; -} - -static void start_data_plane_bh(void *opaque) -{ - VirtIOBlockDataPlane *s = opaque; - - qemu_bh_delete(s->start_bh); - s->start_bh = NULL; - qemu_thread_create(&s->thread, data_plane_thread, - s, QEMU_THREAD_JOINABLE); -} - bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, VirtIOBlockDataPlane **dataplane) { @@ -460,6 +443,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtQueue *vq; int i; + Error *err = NULL; if (s->started) { return; @@ -502,9 +486,16 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s) /* Kick right away to begin processing requests already in vring */ event_notifier_set(virtio_queue_get_host_notifier(vq)); - /* Spawn thread in BH so it inherits iothread cpusets */ - s->start_bh = qemu_bh_new(start_data_plane_bh, s); - qemu_bh_schedule(s->start_bh); + /* use QEMU main loop/context by default */ + if (!s->blk->context) { + s->blk->context = g_strdup("main"); + } + s->qctx = qcontext_find_by_name(s->blk->context, &err); + if (err) { + fprintf(stderr, "virtio-blk failed to start: %s", error_get_pretty(err)); + exit(1); + } + aio_context_attach(s->ctx, s->qctx); } void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) @@ -517,15 +508,6 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s) s->stopping = true; trace_virtio_blk_data_plane_stop(s); - /* Stop thread or cancel pending thread creation BH */ - if (s->start_bh) { - qemu_bh_delete(s->start_bh); - s->start_bh = NULL; - } else { - aio_notify(s->ctx); - qemu_thread_join(&s->thread); - } - aio_set_event_notifier(s->ctx, &s->io_notifier, NULL, NULL); ioq_cleanup(&s->ioqueue); diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h index fc71853..c5514a4 100644 --- a/include/hw/virtio/virtio-blk.h +++ b/include/hw/virtio/virtio-blk.h @@ -110,6 +110,7 @@ struct VirtIOBlkConf uint32_t scsi; uint32_t config_wce; uint32_t data_plane; + char *context; }; struct VirtIOBlockDataPlane; @@ -138,13 +139,15 @@ typedef struct VirtIOBlock { DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \ DEFINE_PROP_STRING("serial", _state, _field.serial), \ DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true), \ - DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true) + DEFINE_PROP_BIT("scsi", _state, _field.scsi, 0, true), \ + DEFINE_PROP_STRING("context", _state, _field.context) #else #define DEFINE_VIRTIO_BLK_PROPERTIES(_state, _field) \ DEFINE_BLOCK_PROPERTIES(_state, _field.conf), \ DEFINE_BLOCK_CHS_PROPERTIES(_state, _field.conf), \ DEFINE_PROP_STRING("serial", _state, _field.serial), \ - DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true) + DEFINE_PROP_BIT("config-wce", _state, _field.config_wce, 0, true), \ + DEFINE_PROP_STRING("context", _state, _field.context) #endif /* __linux__ */ void virtio_blk_set_conf(DeviceState *dev, VirtIOBlkConf *blk); -- 1.7.9.5