Add qemu 2.4.0
[kvmfornfv.git] / qemu / 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 "trace.h"
16 #include "qemu/iov.h"
17 #include "qemu/thread.h"
18 #include "qemu/error-report.h"
19 #include "hw/virtio/virtio-access.h"
20 #include "hw/virtio/dataplane/vring.h"
21 #include "hw/virtio/dataplane/vring-accessors.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 started;
31     bool starting;
32     bool stopping;
33     bool disabled;
34
35     VirtIOBlkConf *conf;
36
37     VirtIODevice *vdev;
38     Vring vring;                    /* virtqueue vring */
39     EventNotifier *guest_notifier;  /* irq */
40     QEMUBH *bh;                     /* bh for guest notification */
41
42     /* Note that these EventNotifiers are assigned by value.  This is
43      * fine as long as you do not call event_notifier_cleanup on them
44      * (because you don't own the file descriptor or handle; you just
45      * use it).
46      */
47     IOThread *iothread;
48     IOThread internal_iothread_obj;
49     AioContext *ctx;
50     EventNotifier host_notifier;    /* doorbell */
51
52     /* Operation blocker on BDS */
53     Error *blocker;
54     void (*saved_complete_request)(struct VirtIOBlockReq *req,
55                                    unsigned char status);
56 };
57
58 /* Raise an interrupt to signal guest, if necessary */
59 static void notify_guest(VirtIOBlockDataPlane *s)
60 {
61     if (!vring_should_notify(s->vdev, &s->vring)) {
62         return;
63     }
64
65     event_notifier_set(s->guest_notifier);
66 }
67
68 static void notify_guest_bh(void *opaque)
69 {
70     VirtIOBlockDataPlane *s = opaque;
71
72     notify_guest(s);
73 }
74
75 static void complete_request_vring(VirtIOBlockReq *req, unsigned char status)
76 {
77     VirtIOBlockDataPlane *s = req->dev->dataplane;
78     stb_p(&req->in->status, status);
79
80     vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, req->in_len);
81
82     /* Suppress notification to guest by BH and its scheduled
83      * flag because requests are completed as a batch after io
84      * plug & unplug is introduced, and the BH can still be
85      * executed in dataplane aio context even after it is
86      * stopped, so needn't worry about notification loss with BH.
87      */
88     qemu_bh_schedule(s->bh);
89 }
90
91 static void handle_notify(EventNotifier *e)
92 {
93     VirtIOBlockDataPlane *s = container_of(e, VirtIOBlockDataPlane,
94                                            host_notifier);
95     VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
96
97     event_notifier_test_and_clear(&s->host_notifier);
98     blk_io_plug(s->conf->conf.blk);
99     for (;;) {
100         MultiReqBuffer mrb = {};
101         int ret;
102
103         /* Disable guest->host notifies to avoid unnecessary vmexits */
104         vring_disable_notification(s->vdev, &s->vring);
105
106         for (;;) {
107             VirtIOBlockReq *req = virtio_blk_alloc_request(vblk);
108
109             ret = vring_pop(s->vdev, &s->vring, &req->elem);
110             if (ret < 0) {
111                 virtio_blk_free_request(req);
112                 break; /* no more requests */
113             }
114
115             trace_virtio_blk_data_plane_process_request(s, req->elem.out_num,
116                                                         req->elem.in_num,
117                                                         req->elem.index);
118
119             virtio_blk_handle_request(req, &mrb);
120         }
121
122         if (mrb.num_reqs) {
123             virtio_blk_submit_multireq(s->conf->conf.blk, &mrb);
124         }
125
126         if (likely(ret == -EAGAIN)) { /* vring emptied */
127             /* Re-enable guest->host notifies and stop processing the vring.
128              * But if the guest has snuck in more descriptors, keep processing.
129              */
130             if (vring_enable_notification(s->vdev, &s->vring)) {
131                 break;
132             }
133         } else { /* fatal error */
134             break;
135         }
136     }
137     blk_io_unplug(s->conf->conf.blk);
138 }
139
140 /* Context: QEMU global mutex held */
141 void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
142                                   VirtIOBlockDataPlane **dataplane,
143                                   Error **errp)
144 {
145     VirtIOBlockDataPlane *s;
146     Error *local_err = NULL;
147     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
148     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
149
150     *dataplane = NULL;
151
152     if (!conf->data_plane && !conf->iothread) {
153         return;
154     }
155
156     /* Don't try if transport does not support notifiers. */
157     if (!k->set_guest_notifiers || !k->set_host_notifier) {
158         error_setg(errp,
159                    "device is incompatible with x-data-plane "
160                    "(transport does not support notifiers)");
161         return;
162     }
163
164     /* If dataplane is (re-)enabled while the guest is running there could be
165      * block jobs that can conflict.
166      */
167     if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE,
168                           &local_err)) {
169         error_setg(errp, "cannot start dataplane thread: %s",
170                    error_get_pretty(local_err));
171         error_free(local_err);
172         return;
173     }
174
175     s = g_new0(VirtIOBlockDataPlane, 1);
176     s->vdev = vdev;
177     s->conf = conf;
178
179     if (conf->iothread) {
180         s->iothread = conf->iothread;
181         object_ref(OBJECT(s->iothread));
182     } else {
183         /* Create per-device IOThread if none specified.  This is for
184          * x-data-plane option compatibility.  If x-data-plane is removed we
185          * can drop this.
186          */
187         object_initialize(&s->internal_iothread_obj,
188                           sizeof(s->internal_iothread_obj),
189                           TYPE_IOTHREAD);
190         user_creatable_complete(OBJECT(&s->internal_iothread_obj), &error_abort);
191         s->iothread = &s->internal_iothread_obj;
192     }
193     s->ctx = iothread_get_aio_context(s->iothread);
194     s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
195
196     error_setg(&s->blocker, "block device is in use by data plane");
197     blk_op_block_all(conf->conf.blk, s->blocker);
198     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
199     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
200     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_BACKUP_SOURCE, s->blocker);
201     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_CHANGE, s->blocker);
202     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_SOURCE, s->blocker);
203     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_COMMIT_TARGET, s->blocker);
204     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EJECT, s->blocker);
205     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_EXTERNAL_SNAPSHOT, s->blocker);
206     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT, s->blocker);
207     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_INTERNAL_SNAPSHOT_DELETE,
208                    s->blocker);
209     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_MIRROR, s->blocker);
210     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_STREAM, s->blocker);
211     blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_REPLACE, s->blocker);
212
213     *dataplane = s;
214 }
215
216 /* Context: QEMU global mutex held */
217 void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
218 {
219     if (!s) {
220         return;
221     }
222
223     virtio_blk_data_plane_stop(s);
224     blk_op_unblock_all(s->conf->conf.blk, s->blocker);
225     error_free(s->blocker);
226     qemu_bh_delete(s->bh);
227     object_unref(OBJECT(s->iothread));
228     g_free(s);
229 }
230
231 /* Context: QEMU global mutex held */
232 void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
233 {
234     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
235     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
236     VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
237     VirtQueue *vq;
238     int r;
239
240     if (s->started || s->disabled) {
241         return;
242     }
243
244     if (s->starting) {
245         return;
246     }
247
248     s->starting = true;
249
250     vq = virtio_get_queue(s->vdev, 0);
251     if (!vring_setup(&s->vring, s->vdev, 0)) {
252         goto fail_vring;
253     }
254
255     /* Set up guest notifier (irq) */
256     r = k->set_guest_notifiers(qbus->parent, 1, true);
257     if (r != 0) {
258         fprintf(stderr, "virtio-blk failed to set guest notifier (%d), "
259                 "ensure -enable-kvm is set\n", r);
260         goto fail_guest_notifiers;
261     }
262     s->guest_notifier = virtio_queue_get_guest_notifier(vq);
263
264     /* Set up virtqueue notify */
265     r = k->set_host_notifier(qbus->parent, 0, true);
266     if (r != 0) {
267         fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
268         goto fail_host_notifier;
269     }
270     s->host_notifier = *virtio_queue_get_host_notifier(vq);
271
272     s->saved_complete_request = vblk->complete_request;
273     vblk->complete_request = complete_request_vring;
274
275     s->starting = false;
276     s->started = true;
277     trace_virtio_blk_data_plane_start(s);
278
279     blk_set_aio_context(s->conf->conf.blk, s->ctx);
280
281     /* Kick right away to begin processing requests already in vring */
282     event_notifier_set(virtio_queue_get_host_notifier(vq));
283
284     /* Get this show started by hooking up our callbacks */
285     aio_context_acquire(s->ctx);
286     aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify);
287     aio_context_release(s->ctx);
288     return;
289
290   fail_host_notifier:
291     k->set_guest_notifiers(qbus->parent, 1, false);
292   fail_guest_notifiers:
293     vring_teardown(&s->vring, s->vdev, 0);
294     s->disabled = true;
295   fail_vring:
296     s->starting = false;
297 }
298
299 /* Context: QEMU global mutex held */
300 void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
301 {
302     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
303     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
304     VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
305
306
307     /* Better luck next time. */
308     if (s->disabled) {
309         s->disabled = false;
310         return;
311     }
312     if (!s->started || s->stopping) {
313         return;
314     }
315     s->stopping = true;
316     vblk->complete_request = s->saved_complete_request;
317     trace_virtio_blk_data_plane_stop(s);
318
319     aio_context_acquire(s->ctx);
320
321     /* Stop notifications for new requests from guest */
322     aio_set_event_notifier(s->ctx, &s->host_notifier, NULL);
323
324     /* Drain and switch bs back to the QEMU main loop */
325     blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
326
327     aio_context_release(s->ctx);
328
329     /* Sync vring state back to virtqueue so that non-dataplane request
330      * processing can continue when we disable the host notifier below.
331      */
332     vring_teardown(&s->vring, s->vdev, 0);
333
334     k->set_host_notifier(qbus->parent, 0, false);
335
336     /* Clean up guest notifier (irq) */
337     k->set_guest_notifiers(qbus->parent, 1, false);
338
339     s->started = false;
340     s->stopping = false;
341 }