diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-03-13 15:33:04 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-03-13 15:33:04 +0000 |
commit | 57fac92c2d4487d5c45e1ca96df6790f96c9e64c (patch) | |
tree | bd6d23260932db3f7663102a5222bc0b6d5bffe2 /hw | |
parent | 41975b269cf1503c735f8233f8ef373d74f1f137 (diff) | |
parent | 57ed25b1b08a43f29326df064d43b6420a23b5ba (diff) |
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging
Block pull request
# gpg: Signature made Thu 13 Mar 2014 13:50:49 GMT using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35 775A 9CA4 ABB3 81AB 73C8
* remotes/stefanha/tags/block-pull-request: (24 commits)
block/raw-win32: bdrv_parse_filename() for hdev
block/raw-posix: Strip protocol prefix on creation
block/raw-posix: bdrv_parse_filename() for cdrom
block/raw-posix: bdrv_parse_filename() for floppy
block/raw-posix: bdrv_parse_filename() for hdev
qemu-io: Fix warnings from static code analysis
block: Unlink temporary file
qcow2: Don't write with BDRV_O_INCOMING
qcow2: Keep option in qcow2_invalidate_cache()
qmp: add query-iothreads command
iothread: stash thread ID away
dataplane: replace internal thread with IOThread
iothread: add "iothread" qdev property type
qdev: make get_pointer() handle temporary strings
iothread: add I/O thread object
aio: add aio_context_acquire() and aio_context_release()
rfifolock: add recursive FIFO lock
object: add object_get_canonical_path_component()
block: Rewrite the snapshot authorization mechanism for block filters.
iotests: Test corruption during COW request
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/block/dataplane/virtio-blk.c | 96 | ||||
-rw-r--r-- | hw/core/qdev-properties-system.c | 70 |
2 files changed, 116 insertions, 50 deletions
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index d1c7ad4574..a5afc217c0 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", 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/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index 5f5957ed8e..de835612f0 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -18,17 +18,19 @@ #include "net/hub.h" #include "qapi/visitor.h" #include "sysemu/char.h" +#include "sysemu/iothread.h" static void get_pointer(Object *obj, Visitor *v, Property *prop, - const char *(*print)(void *ptr), + char *(*print)(void *ptr), const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); void **ptr = qdev_get_prop_ptr(dev, prop); char *p; - p = (char *) (*ptr ? print(*ptr) : ""); + p = *ptr ? print(*ptr) : g_strdup(""); visit_type_str(v, &p, name, errp); + g_free(p); } static void set_pointer(Object *obj, Visitor *v, Property *prop, @@ -91,9 +93,9 @@ static void release_drive(Object *obj, const char *name, void *opaque) } } -static const char *print_drive(void *ptr) +static char *print_drive(void *ptr) { - return bdrv_get_device_name(ptr); + return g_strdup(bdrv_get_device_name(ptr)); } static void get_drive(Object *obj, Visitor *v, void *opaque, @@ -145,11 +147,12 @@ static void release_chr(Object *obj, const char *name, void *opaque) } -static const char *print_chr(void *ptr) +static char *print_chr(void *ptr) { CharDriverState *chr = ptr; + const char *val = chr->label ? chr->label : ""; - return chr->label ? chr->label : ""; + return g_strdup(val); } static void get_chr(Object *obj, Visitor *v, void *opaque, @@ -224,11 +227,12 @@ err: return ret; } -static const char *print_netdev(void *ptr) +static char *print_netdev(void *ptr) { NetClientState *netdev = ptr; + const char *val = netdev->name ? netdev->name : ""; - return netdev->name ? netdev->name : ""; + return g_strdup(val); } static void get_netdev(Object *obj, Visitor *v, void *opaque, @@ -382,6 +386,56 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) nd->instantiated = 1; } +/* --- iothread --- */ + +static char *print_iothread(void *ptr) +{ + return iothread_get_id(ptr); +} + +static int parse_iothread(DeviceState *dev, const char *str, void **ptr) +{ + IOThread *iothread; + + iothread = iothread_find(str); + if (!iothread) { + return -ENOENT; + } + object_ref(OBJECT(iothread)); + *ptr = iothread; + return 0; +} + +static void get_iothread(Object *obj, struct Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_iothread, name, errp); +} + +static void set_iothread(Object *obj, struct Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_iothread, name, errp); +} + +static void release_iothread(Object *obj, const char *name, void *opaque) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + IOThread **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { + object_unref(OBJECT(*ptr)); + } +} + +PropertyInfo qdev_prop_iothread = { + .name = "iothread", + .get = get_iothread, + .set = set_iothread, + .release = release_iothread, +}; + static int qdev_add_one_global(QemuOpts *opts, void *opaque) { GlobalProperty *g; |