From: Paolo Bonzini <pbonzini@redhat.com>
To: Stefan Hajnoczi <stefanha@redhat.com>, qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>, Fam Zheng <famz@redhat.com>,
Michael Roth <mdroth@linux.vnet.ibm.com>
Subject: Re: [Qemu-devel] [PATCH v3 6/6] dataplane: replace internal thread with IOThread
Date: Thu, 20 Feb 2014 13:57:43 +0100 [thread overview]
Message-ID: <5305FBC7.5040106@redhat.com> (raw)
In-Reply-To: <1392900630-17608-7-git-send-email-stefanha@redhat.com>
Il 20/02/2014 13:50, Stefan Hajnoczi ha scritto:
> Today virtio-blk dataplane uses a 1:1 device-per-thread model. Now that
> IOThreads have been introduced we can generalize this to N:M devices per
> threads.
>
> This patch drops thread code from dataplane in favor of running inside
> an IOThread AioContext.
>
> As a bonus we solve the case where a guest keeps submitting I/O requests
> while dataplane is trying to stop. Previously the dataplane thread
> would continue to process requests until the request gave it a break.
> Now we can shut down in bounded time thanks to
> aio_context_acquire/release.
>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---
> hw/block/dataplane/virtio-blk.c | 96 +++++++++++++++++++++++------------------
> include/hw/virtio/virtio-blk.h | 8 +++-
> 2 files changed, 60 insertions(+), 44 deletions(-)
>
> diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
> index 2237edb..a5afc21 100644
> --- a/hw/block/dataplane/virtio-blk.c
> +++ b/hw/block/dataplane/virtio-blk.c
> @@ -23,6 +23,7 @@
> #include "virtio-blk.h"
> #include "block/aio.h"
> #include "hw/virtio/virtio-bus.h"
> +#include "monitor/monitor.h" /* for object_add() */
>
> enum {
> SEG_MAX = 126, /* maximum number of I/O segments */
> @@ -44,8 +45,6 @@ struct VirtIOBlockDataPlane {
> bool started;
> bool starting;
> bool stopping;
> - QEMUBH *start_bh;
> - QemuThread thread;
>
> VirtIOBlkConf *blk;
> int fd; /* image file descriptor */
> @@ -59,12 +58,14 @@ struct VirtIOBlockDataPlane {
> * (because you don't own the file descriptor or handle; you just
> * use it).
> */
> + IOThread *iothread;
> + bool internal_iothread;
> AioContext *ctx;
> EventNotifier io_notifier; /* Linux AIO completion */
> EventNotifier host_notifier; /* doorbell */
>
> IOQueue ioqueue; /* Linux AIO queue (should really be per
> - dataplane thread) */
> + IOThread) */
> VirtIOBlockRequest requests[REQ_MAX]; /* pool of requests, managed by the
> queue */
>
> @@ -342,26 +343,7 @@ static void handle_io(EventNotifier *e)
> }
> }
>
> -static void *data_plane_thread(void *opaque)
> -{
> - VirtIOBlockDataPlane *s = opaque;
> -
> - while (!s->stopping || s->num_reqs > 0) {
> - aio_poll(s->ctx, true);
> - }
> - 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);
> -}
> -
> +/* Context: QEMU global mutex held */
> void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
> VirtIOBlockDataPlane **dataplane,
> Error **errp)
> @@ -408,12 +390,33 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
> s->fd = fd;
> s->blk = blk;
>
> + if (blk->iothread) {
> + s->internal_iothread = false;
> + s->iothread = blk->iothread;
> + object_ref(OBJECT(s->iothread));
> + } else {
> + /* Create per-device IOThread if none specified */
> + Error *local_err = NULL;
> +
> + s->internal_iothread = true;
> + object_add(TYPE_IOTHREAD, vdev->name, NULL, NULL, &local_err);
> + if (error_is_set(&local_err)) {
> + error_propagate(errp, local_err);
> + g_free(s);
> + return;
> + }
> + s->iothread = iothread_find(vdev->name);
> + assert(s->iothread);
> + }
> + s->ctx = iothread_get_aio_context(s->iothread);
> +
> /* Prevent block operations that conflict with data plane thread */
> bdrv_set_in_use(blk->conf.bs, 1);
>
> *dataplane = s;
> }
>
> +/* Context: QEMU global mutex held */
> void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
> {
> if (!s) {
> @@ -422,9 +425,14 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
>
> virtio_blk_data_plane_stop(s);
> bdrv_set_in_use(s->blk->conf.bs, 0);
> + object_unref(OBJECT(s->iothread));
> + if (s->internal_iothread) {
> + object_unparent(OBJECT(s->iothread));
> + }
> g_free(s);
> }
>
> +/* Context: QEMU global mutex held */
> void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
> {
> BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
> @@ -448,8 +456,6 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
> return;
> }
>
> - s->ctx = aio_context_new();
> -
> /* Set up guest notifier (irq) */
> if (k->set_guest_notifiers(qbus->parent, 1, true) != 0) {
> fprintf(stderr, "virtio-blk failed to set guest notifier, "
> @@ -464,7 +470,6 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
> exit(1);
> }
> s->host_notifier = *virtio_queue_get_host_notifier(vq);
> - aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify);
>
> /* Set up ioqueue */
> ioq_init(&s->ioqueue, s->fd, REQ_MAX);
> @@ -472,7 +477,6 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
> ioq_put_iocb(&s->ioqueue, &s->requests[i].iocb);
> }
> s->io_notifier = *ioq_get_notifier(&s->ioqueue);
> - aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io);
>
> s->starting = false;
> s->started = true;
> @@ -481,11 +485,14 @@ 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);
> + /* Get this show started by hooking up our callbacks */
> + aio_context_acquire(s->ctx);
> + aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify);
> + aio_set_event_notifier(s->ctx, &s->io_notifier, handle_io);
> + aio_context_release(s->ctx);
> }
>
> +/* Context: QEMU global mutex held */
> void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
> {
> BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
> @@ -496,27 +503,32 @@ 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_context_acquire(s->ctx);
> +
> + /* Stop notifications for new requests from guest */
> + aio_set_event_notifier(s->ctx, &s->host_notifier, NULL);
> +
> + /* Complete pending requests */
> + while (s->num_reqs > 0) {
> + aio_poll(s->ctx, true);
> }
>
> + /* Stop ioq callbacks (there are no pending requests left) */
> aio_set_event_notifier(s->ctx, &s->io_notifier, NULL);
> - ioq_cleanup(&s->ioqueue);
>
> - aio_set_event_notifier(s->ctx, &s->host_notifier, NULL);
> - k->set_host_notifier(qbus->parent, 0, false);
> + aio_context_release(s->ctx);
>
> - aio_context_unref(s->ctx);
> + /* Sync vring state back to virtqueue so that non-dataplane request
> + * processing can continue when we disable the host notifier below.
> + */
> + vring_teardown(&s->vring, s->vdev, 0);
> +
> + ioq_cleanup(&s->ioqueue);
> + k->set_host_notifier(qbus->parent, 0, false);
>
> /* Clean up guest notifier (irq) */
> k->set_guest_notifiers(qbus->parent, 1, false);
>
> - vring_teardown(&s->vring, s->vdev, 0);
> s->started = false;
> s->stopping = false;
> }
> diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
> index 41885da..12193fd 100644
> --- a/include/hw/virtio/virtio-blk.h
> +++ b/include/hw/virtio/virtio-blk.h
> @@ -16,6 +16,7 @@
>
> #include "hw/virtio/virtio.h"
> #include "hw/block/block.h"
> +#include "sysemu/iothread.h"
>
> #define TYPE_VIRTIO_BLK "virtio-blk-device"
> #define VIRTIO_BLK(obj) \
> @@ -106,6 +107,7 @@ struct virtio_scsi_inhdr
> struct VirtIOBlkConf
> {
> BlockConf conf;
> + IOThread *iothread;
> char *serial;
> uint32_t scsi;
> uint32_t config_wce;
> @@ -140,13 +142,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_IOTHREAD("iothread", _state, _field.iothread)
> #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_IOTHREAD("iothread", _state, _field.iothread)
Please make this x-iothread. I think not-so-long term we should make
this a link<>, and I'd rather not have people rely on any ABI from
-device virtio-blk-pci,?
Paolo
prev parent reply other threads:[~2014-02-20 12:58 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-02-20 12:50 [Qemu-devel] [PATCH v3 0/6] dataplane: switch to N:M devices-per-thread model Stefan Hajnoczi
2014-02-20 12:50 ` [Qemu-devel] [PATCH v3 1/6] rfifolock: add recursive FIFO lock Stefan Hajnoczi
2014-02-20 12:50 ` [Qemu-devel] [PATCH v3 2/6] aio: add aio_context_acquire() and aio_context_release() Stefan Hajnoczi
2014-02-20 12:50 ` [Qemu-devel] [PATCH v3 3/6] iothread: add I/O thread object Stefan Hajnoczi
2014-02-20 12:50 ` [Qemu-devel] [PATCH v3 4/6] qdev: add get_pointer_and_free() for temporary strings Stefan Hajnoczi
2014-02-20 12:50 ` [Qemu-devel] [PATCH v3 5/6] iothread: add "iothread" qdev property type Stefan Hajnoczi
2014-02-20 12:58 ` Paolo Bonzini
2014-02-21 11:03 ` Stefan Hajnoczi
2014-02-21 11:33 ` Paolo Bonzini
2014-02-21 12:45 ` Stefan Hajnoczi
2014-02-21 13:01 ` Paolo Bonzini
2014-02-21 13:25 ` Stefan Hajnoczi
2014-02-21 13:29 ` Paolo Bonzini
2014-02-21 14:15 ` Stefan Hajnoczi
2014-02-20 12:50 ` [Qemu-devel] [PATCH v3 6/6] dataplane: replace internal thread with IOThread Stefan Hajnoczi
2014-02-20 12:57 ` Paolo Bonzini [this message]
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=5305FBC7.5040106@redhat.com \
--to=pbonzini@redhat.com \
--cc=famz@redhat.com \
--cc=kwolf@redhat.com \
--cc=mdroth@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.