]> Git Repo - qemu.git/blame - hw/block/dataplane/virtio-blk.c
virtio-blk: add VirtIOBlockConf->num_queues
[qemu.git] / hw / block / dataplane / virtio-blk.c
CommitLineData
e72f66a0
SH
1/*
2 * Dedicated thread for virtio-blk I/O processing
3 *
4 * Copyright 2012 IBM, Corp.
5 * Copyright 2012 Red Hat, Inc. and/or its affiliates
6 *
7 * Authors:
8 * Stefan Hajnoczi <[email protected]>
9 *
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
12 *
13 */
14
80c71a24 15#include "qemu/osdep.h"
da34e65c 16#include "qapi/error.h"
e72f66a0
SH
17#include "trace.h"
18#include "qemu/iov.h"
e72f66a0 19#include "qemu/thread.h"
b4a42f81 20#include "qemu/error-report.h"
b0e5d90e 21#include "hw/virtio/virtio-access.h"
4be74634 22#include "sysemu/block-backend.h"
0d09e41a
PB
23#include "hw/virtio/virtio-blk.h"
24#include "virtio-blk.h"
2c20e711 25#include "block/aio.h"
1c819449 26#include "hw/virtio/virtio-bus.h"
54bee5c2 27#include "qom/object_interfaces.h"
e72f66a0 28
e72f66a0 29struct VirtIOBlockDataPlane {
8caf907f 30 bool starting;
cd7fdfe5 31 bool stopping;
e72f66a0 32
2a30307f 33 VirtIOBlkConf *conf;
e72f66a0
SH
34
35 VirtIODevice *vdev;
03de2f52 36 VirtQueue *vq; /* virtqueue vring */
e72f66a0 37 EventNotifier *guest_notifier; /* irq */
5b2ffbe4 38 QEMUBH *bh; /* bh for guest notification */
e72f66a0 39
2c20e711
PB
40 /* Note that these EventNotifiers are assigned by value. This is
41 * fine as long as you do not call event_notifier_cleanup on them
42 * (because you don't own the file descriptor or handle; you just
43 * use it).
44 */
48ff2692 45 IOThread *iothread;
2c20e711 46 AioContext *ctx;
e72f66a0
SH
47};
48
49/* Raise an interrupt to signal guest, if necessary */
03de2f52 50void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s)
e72f66a0 51{
03de2f52 52 qemu_bh_schedule(s->bh);
e72f66a0
SH
53}
54
5b2ffbe4
ML
55static void notify_guest_bh(void *opaque)
56{
57 VirtIOBlockDataPlane *s = opaque;
58
03de2f52
PB
59 if (!virtio_should_notify(s->vdev, s->vq)) {
60 return;
e72f66a0 61 }
03de2f52
PB
62
63 event_notifier_set(s->guest_notifier);
e72f66a0
SH
64}
65
48ff2692 66/* Context: QEMU global mutex held */
2a30307f 67void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
3ffeeef7
AF
68 VirtIOBlockDataPlane **dataplane,
69 Error **errp)
e72f66a0
SH
70{
71 VirtIOBlockDataPlane *s;
a9968c77
CH
72 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
73 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
e72f66a0
SH
74
75 *dataplane = NULL;
76
a616fb75 77 if (!conf->iothread) {
3ffeeef7 78 return;
e72f66a0
SH
79 }
80
a9968c77 81 /* Don't try if transport does not support notifiers. */
21a4d962 82 if (!k->set_guest_notifiers || !k->ioeventfd_started) {
a9968c77 83 error_setg(errp,
a616fb75 84 "device is incompatible with dataplane "
a9968c77
CH
85 "(transport does not support notifiers)");
86 return;
87 }
88
b0f2027c
SH
89 /* If dataplane is (re-)enabled while the guest is running there could be
90 * block jobs that can conflict.
91 */
e43bfd9c
MA
92 if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
93 error_prepend(errp, "cannot start dataplane thread: ");
3ffeeef7 94 return;
b0f2027c
SH
95 }
96
e72f66a0
SH
97 s = g_new0(VirtIOBlockDataPlane, 1);
98 s->vdev = vdev;
2a30307f 99 s->conf = conf;
e72f66a0 100
2a30307f
MA
101 if (conf->iothread) {
102 s->iothread = conf->iothread;
54bee5c2 103 object_ref(OBJECT(s->iothread));
48ff2692
SH
104 }
105 s->ctx = iothread_get_aio_context(s->iothread);
5b2ffbe4 106 s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
48ff2692 107
e72f66a0 108 *dataplane = s;
e72f66a0
SH
109}
110
48ff2692 111/* Context: QEMU global mutex held */
e72f66a0
SH
112void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
113{
114 if (!s) {
115 return;
116 }
117
118 virtio_blk_data_plane_stop(s);
5b2ffbe4 119 qemu_bh_delete(s->bh);
fed105e2 120 object_unref(OBJECT(s->iothread));
e72f66a0
SH
121 g_free(s);
122}
123
8a2fad57
MT
124static void virtio_blk_data_plane_handle_output(VirtIODevice *vdev,
125 VirtQueue *vq)
126{
127 VirtIOBlock *s = (VirtIOBlock *)vdev;
128
129 assert(s->dataplane);
130 assert(s->dataplane_started);
131
132 virtio_blk_handle_vq(s, vq);
133}
134
48ff2692 135/* Context: QEMU global mutex held */
e72f66a0
SH
136void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
137{
1c819449
FK
138 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
139 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
e926d9b8 140 VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
267e1a20 141 int r;
e72f66a0 142
2906cddf 143 if (vblk->dataplane_started || s->starting) {
8caf907f
CH
144 return;
145 }
146
147 s->starting = true;
03de2f52 148 s->vq = virtio_get_queue(s->vdev, 0);
e72f66a0 149
e72f66a0 150 /* Set up guest notifier (irq) */
267e1a20
CH
151 r = k->set_guest_notifiers(qbus->parent, 1, true);
152 if (r != 0) {
153 fprintf(stderr, "virtio-blk failed to set guest notifier (%d), "
154 "ensure -enable-kvm is set\n", r);
f9907ebc 155 goto fail_guest_notifiers;
e72f66a0 156 }
03de2f52 157 s->guest_notifier = virtio_queue_get_guest_notifier(s->vq);
e72f66a0
SH
158
159 /* Set up virtqueue notify */
b1f0a33d 160 r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 0, true);
267e1a20
CH
161 if (r != 0) {
162 fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
f9907ebc 163 goto fail_host_notifier;
e72f66a0 164 }
e926d9b8 165
8caf907f 166 s->starting = false;
2906cddf 167 vblk->dataplane_started = true;
e72f66a0
SH
168 trace_virtio_blk_data_plane_start(s);
169
4be74634 170 blk_set_aio_context(s->conf->conf.blk, s->ctx);
580b6b2a 171
e72f66a0 172 /* Kick right away to begin processing requests already in vring */
03de2f52 173 event_notifier_set(virtio_queue_get_host_notifier(s->vq));
e72f66a0 174
48ff2692
SH
175 /* Get this show started by hooking up our callbacks */
176 aio_context_acquire(s->ctx);
a378b49a
PB
177 virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx,
178 virtio_blk_data_plane_handle_output);
48ff2692 179 aio_context_release(s->ctx);
f9907ebc
CH
180 return;
181
182 fail_host_notifier:
183 k->set_guest_notifiers(qbus->parent, 1, false);
184 fail_guest_notifiers:
eb41cf78 185 vblk->dataplane_disabled = true;
f9907ebc 186 s->starting = false;
2906cddf 187 vblk->dataplane_started = true;
e72f66a0
SH
188}
189
48ff2692 190/* Context: QEMU global mutex held */
e72f66a0
SH
191void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
192{
1c819449
FK
193 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
194 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
b002254d 195 VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
2f5f70fa 196
2906cddf
PB
197 if (!vblk->dataplane_started || s->stopping) {
198 return;
199 }
2f5f70fa
CH
200
201 /* Better luck next time. */
eb41cf78
PB
202 if (vblk->dataplane_disabled) {
203 vblk->dataplane_disabled = false;
2906cddf 204 vblk->dataplane_started = false;
e72f66a0
SH
205 return;
206 }
cd7fdfe5 207 s->stopping = true;
e72f66a0
SH
208 trace_virtio_blk_data_plane_stop(s);
209
48ff2692
SH
210 aio_context_acquire(s->ctx);
211
212 /* Stop notifications for new requests from guest */
a378b49a 213 virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, NULL);
48ff2692 214
580b6b2a 215 /* Drain and switch bs back to the QEMU main loop */
4be74634 216 blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
e72f66a0 217
48ff2692 218 aio_context_release(s->ctx);
e72f66a0 219
21a4d962 220 virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 0, false);
e72f66a0
SH
221
222 /* Clean up guest notifier (irq) */
1c819449 223 k->set_guest_notifiers(qbus->parent, 1, false);
e72f66a0 224
2906cddf 225 vblk->dataplane_started = false;
cd7fdfe5 226 s->stopping = false;
e72f66a0 227}
This page took 0.267125 seconds and 4 git commands to generate.