]> git.proxmox.com Git - mirror_qemu.git/blob - hw/block/dataplane/virtio-blk.c
include/qemu/osdep.h: Don't include qapi/error.h
[mirror_qemu.git] / hw / block / dataplane / virtio-blk.c
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 <stefanha@redhat.com>
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
15 #include "qemu/osdep.h"
16 #include "qapi/error.h"
17 #include "trace.h"
18 #include "qemu/iov.h"
19 #include "qemu/thread.h"
20 #include "qemu/error-report.h"
21 #include "hw/virtio/virtio-access.h"
22 #include "sysemu/block-backend.h"
23 #include "hw/virtio/virtio-blk.h"
24 #include "virtio-blk.h"
25 #include "block/aio.h"
26 #include "hw/virtio/virtio-bus.h"
27 #include "qom/object_interfaces.h"
28
29 struct VirtIOBlockDataPlane {
30 bool starting;
31 bool stopping;
32 bool disabled;
33
34 VirtIOBlkConf *conf;
35
36 VirtIODevice *vdev;
37 VirtQueue *vq; /* virtqueue vring */
38 EventNotifier *guest_notifier; /* irq */
39 QEMUBH *bh; /* bh for guest notification */
40
41 Notifier insert_notifier, remove_notifier;
42
43 /* Note that these EventNotifiers are assigned by value. This is
44 * fine as long as you do not call event_notifier_cleanup on them
45 * (because you don't own the file descriptor or handle; you just
46 * use it).
47 */
48 IOThread *iothread;
49 AioContext *ctx;
50
51 /* Operation blocker on BDS */
52 Error *blocker;
53 };
54
55 /* Raise an interrupt to signal guest, if necessary */
56 void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s)
57 {
58 qemu_bh_schedule(s->bh);
59 }
60
61 static void notify_guest_bh(void *opaque)
62 {
63 VirtIOBlockDataPlane *s = opaque;
64
65 if (!virtio_should_notify(s->vdev, s->vq)) {
66 return;
67 }
68
69 event_notifier_set(s->guest_notifier);
70 }
71
72 static void data_plane_set_up_op_blockers(VirtIOBlockDataPlane *s)
73 {
74 assert(!s->blocker);
75 error_setg(&s->blocker, "block device is in use by data plane");
76 blk_op_block_all(s->conf->conf.blk, s->blocker);
77 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
78 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
79 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
80 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
81 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
82 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
83 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
84 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT,
85 s->blocker);
86 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT,
87 s->blocker);
88 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
89 s->blocker);
90 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_MIRROR_SOURCE, s->blocker);
91 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
92 blk_op_unblock(s->conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
93 }
94
95 static void data_plane_remove_op_blockers(VirtIOBlockDataPlane *s)
96 {
97 if (s->blocker) {
98 blk_op_unblock_all(s->conf->conf.blk, s->blocker);
99 error_free(s->blocker);
100 s->blocker = NULL;
101 }
102 }
103
104 static void data_plane_blk_insert_notifier(Notifier *n, void *data)
105 {
106 VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane,
107 insert_notifier);
108 assert(s->conf->conf.blk == data);
109 data_plane_set_up_op_blockers(s);
110 }
111
112 static void data_plane_blk_remove_notifier(Notifier *n, void *data)
113 {
114 VirtIOBlockDataPlane *s = container_of(n, VirtIOBlockDataPlane,
115 remove_notifier);
116 assert(s->conf->conf.blk == data);
117 data_plane_remove_op_blockers(s);
118 }
119
120 /* Context: QEMU global mutex held */
121 void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
122 VirtIOBlockDataPlane **dataplane,
123 Error **errp)
124 {
125 VirtIOBlockDataPlane *s;
126 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
127 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
128
129 *dataplane = NULL;
130
131 if (!conf->iothread) {
132 return;
133 }
134
135 /* Don't try if transport does not support notifiers. */
136 if (!k->set_guest_notifiers || !k->set_host_notifier) {
137 error_setg(errp,
138 "device is incompatible with dataplane "
139 "(transport does not support notifiers)");
140 return;
141 }
142
143 /* If dataplane is (re-)enabled while the guest is running there could be
144 * block jobs that can conflict.
145 */
146 if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE, errp)) {
147 error_prepend(errp, "cannot start dataplane thread: ");
148 return;
149 }
150
151 s = g_new0(VirtIOBlockDataPlane, 1);
152 s->vdev = vdev;
153 s->conf = conf;
154
155 if (conf->iothread) {
156 s->iothread = conf->iothread;
157 object_ref(OBJECT(s->iothread));
158 }
159 s->ctx = iothread_get_aio_context(s->iothread);
160 s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
161
162 s->insert_notifier.notify = data_plane_blk_insert_notifier;
163 s->remove_notifier.notify = data_plane_blk_remove_notifier;
164 blk_add_insert_bs_notifier(conf->conf.blk, &s->insert_notifier);
165 blk_add_remove_bs_notifier(conf->conf.blk, &s->remove_notifier);
166
167 data_plane_set_up_op_blockers(s);
168
169 *dataplane = s;
170 }
171
172 /* Context: QEMU global mutex held */
173 void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
174 {
175 if (!s) {
176 return;
177 }
178
179 virtio_blk_data_plane_stop(s);
180 data_plane_remove_op_blockers(s);
181 notifier_remove(&s->insert_notifier);
182 notifier_remove(&s->remove_notifier);
183 qemu_bh_delete(s->bh);
184 object_unref(OBJECT(s->iothread));
185 g_free(s);
186 }
187
188 /* Context: QEMU global mutex held */
189 void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
190 {
191 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
192 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
193 VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
194 int r;
195
196 if (vblk->dataplane_started || s->starting) {
197 return;
198 }
199
200 s->starting = true;
201 s->vq = virtio_get_queue(s->vdev, 0);
202
203 /* Set up guest notifier (irq) */
204 r = k->set_guest_notifiers(qbus->parent, 1, true);
205 if (r != 0) {
206 fprintf(stderr, "virtio-blk failed to set guest notifier (%d), "
207 "ensure -enable-kvm is set\n", r);
208 goto fail_guest_notifiers;
209 }
210 s->guest_notifier = virtio_queue_get_guest_notifier(s->vq);
211
212 /* Set up virtqueue notify */
213 r = k->set_host_notifier(qbus->parent, 0, true);
214 if (r != 0) {
215 fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
216 goto fail_host_notifier;
217 }
218
219 s->starting = false;
220 vblk->dataplane_started = true;
221 trace_virtio_blk_data_plane_start(s);
222
223 blk_set_aio_context(s->conf->conf.blk, s->ctx);
224
225 /* Kick right away to begin processing requests already in vring */
226 event_notifier_set(virtio_queue_get_host_notifier(s->vq));
227
228 /* Get this show started by hooking up our callbacks */
229 aio_context_acquire(s->ctx);
230 virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, true, true);
231 aio_context_release(s->ctx);
232 return;
233
234 fail_host_notifier:
235 k->set_guest_notifiers(qbus->parent, 1, false);
236 fail_guest_notifiers:
237 s->disabled = true;
238 s->starting = false;
239 vblk->dataplane_started = true;
240 }
241
242 /* Context: QEMU global mutex held */
243 void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
244 {
245 BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
246 VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
247 VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
248
249 if (!vblk->dataplane_started || s->stopping) {
250 return;
251 }
252
253 /* Better luck next time. */
254 if (s->disabled) {
255 s->disabled = false;
256 vblk->dataplane_started = false;
257 return;
258 }
259 s->stopping = true;
260 trace_virtio_blk_data_plane_stop(s);
261
262 aio_context_acquire(s->ctx);
263
264 /* Stop notifications for new requests from guest */
265 virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, false, false);
266
267 /* Drain and switch bs back to the QEMU main loop */
268 blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
269
270 aio_context_release(s->ctx);
271
272 k->set_host_notifier(qbus->parent, 0, false);
273
274 /* Clean up guest notifier (irq) */
275 k->set_guest_notifiers(qbus->parent, 1, false);
276
277 vblk->dataplane_started = false;
278 s->stopping = false;
279 }