Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-reques…
Browse files Browse the repository at this point in the history
…t' into staging

# gpg: Signature made Tue 28 Jun 2016 14:23:24 BST
# gpg:                using RSA key 0x9CA4ABB381AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg:                 aka "Stefan Hajnoczi <stefanha@gmail.com>"
# Primary key fingerprint: 8695 A8BF D3F9 7CDA AC35  775A 9CA4 ABB3 81AB 73C8

* remotes/stefanha/tags/block-pull-request:
  virtio-blk: add num-queues device property
  virtio-blk: dataplane multiqueue support
  virtio-blk: live migrate s->rq with multiqueue
  virtio-blk: associate request with a virtqueue
  virtio-blk: tell dataplane which vq to notify
  virtio-blk: multiqueue batch notify
  virtio-blk: add VirtIOBlockConf->num_queues
  dma-helpers: dma_blk_io() cancel support
  Revert "virtio: sync the dataplane vring state to the virtqueue before virtio_save"

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
pm215 committed Jun 28, 2016
2 parents 40428fe + 2f27059 commit 12c8720
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 46 deletions.
7 changes: 7 additions & 0 deletions dma-helpers.c
Expand Up @@ -185,10 +185,17 @@ static void dma_aio_cancel(BlockAIOCB *acb)
}
}

static AioContext *dma_get_aio_context(BlockAIOCB *acb)
{
DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);

return dbs->ctx;
}

static const AIOCBInfo dma_aiocb_info = {
.aiocb_size = sizeof(DMAAIOCB),
.cancel_async = dma_aio_cancel,
.get_aio_context = dma_get_aio_context,
};

BlockAIOCB *dma_blk_io(AioContext *ctx,
Expand Down
81 changes: 58 additions & 23 deletions hw/block/dataplane/virtio-blk.c
Expand Up @@ -31,11 +31,9 @@ struct VirtIOBlockDataPlane {
bool stopping;

VirtIOBlkConf *conf;

VirtIODevice *vdev;
VirtQueue *vq; /* virtqueue vring */
EventNotifier *guest_notifier; /* irq */
QEMUBH *bh; /* bh for guest notification */
unsigned long *batch_notify_vqs;

/* Note that these EventNotifiers are assigned by value. This is
* fine as long as you do not call event_notifier_cleanup on them
Expand All @@ -47,20 +45,36 @@ struct VirtIOBlockDataPlane {
};

/* Raise an interrupt to signal guest, if necessary */
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s)
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq)
{
set_bit(virtio_get_queue_index(vq), s->batch_notify_vqs);
qemu_bh_schedule(s->bh);
}

static void notify_guest_bh(void *opaque)
{
VirtIOBlockDataPlane *s = opaque;
unsigned nvqs = s->conf->num_queues;
unsigned long bitmap[BITS_TO_LONGS(nvqs)];
unsigned j;

if (!virtio_should_notify(s->vdev, s->vq)) {
return;
}
memcpy(bitmap, s->batch_notify_vqs, sizeof(bitmap));
memset(s->batch_notify_vqs, 0, sizeof(bitmap));

for (j = 0; j < nvqs; j += BITS_PER_LONG) {
unsigned long bits = bitmap[j];

event_notifier_set(s->guest_notifier);
while (bits != 0) {
unsigned i = j + ctzl(bits);
VirtQueue *vq = virtio_get_queue(s->vdev, i);

if (virtio_should_notify(s->vdev, vq)) {
event_notifier_set(virtio_queue_get_guest_notifier(vq));
}

bits &= bits - 1; /* clear right-most bit */
}
}
}

/* Context: QEMU global mutex held */
Expand Down Expand Up @@ -104,6 +118,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
}
s->ctx = iothread_get_aio_context(s->iothread);
s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
s->batch_notify_vqs = bitmap_new(conf->num_queues);

*dataplane = s;
}
Expand All @@ -116,6 +131,7 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
}

virtio_blk_data_plane_stop(s);
g_free(s->batch_notify_vqs);
qemu_bh_delete(s->bh);
object_unref(OBJECT(s->iothread));
g_free(s);
Expand All @@ -138,29 +154,34 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
unsigned i;
unsigned nvqs = s->conf->num_queues;
int r;

if (vblk->dataplane_started || s->starting) {
return;
}

s->starting = true;
s->vq = virtio_get_queue(s->vdev, 0);

/* Set up guest notifier (irq) */
r = k->set_guest_notifiers(qbus->parent, 1, true);
r = k->set_guest_notifiers(qbus->parent, nvqs, true);
if (r != 0) {
fprintf(stderr, "virtio-blk failed to set guest notifier (%d), "
"ensure -enable-kvm is set\n", r);
goto fail_guest_notifiers;
}
s->guest_notifier = virtio_queue_get_guest_notifier(s->vq);

/* Set up virtqueue notify */
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 0, true);
if (r != 0) {
fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
goto fail_host_notifier;
for (i = 0; i < nvqs; i++) {
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, true);
if (r != 0) {
fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
while (i--) {
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
}
goto fail_guest_notifiers;
}
}

s->starting = false;
Expand All @@ -170,17 +191,23 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
blk_set_aio_context(s->conf->conf.blk, s->ctx);

/* Kick right away to begin processing requests already in vring */
event_notifier_set(virtio_queue_get_host_notifier(s->vq));
for (i = 0; i < nvqs; i++) {
VirtQueue *vq = virtio_get_queue(s->vdev, i);

event_notifier_set(virtio_queue_get_host_notifier(vq));
}

/* Get this show started by hooking up our callbacks */
aio_context_acquire(s->ctx);
virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx,
virtio_blk_data_plane_handle_output);
for (i = 0; i < nvqs; i++) {
VirtQueue *vq = virtio_get_queue(s->vdev, i);

virtio_queue_aio_set_host_notifier_handler(vq, s->ctx,
virtio_blk_data_plane_handle_output);
}
aio_context_release(s->ctx);
return;

fail_host_notifier:
k->set_guest_notifiers(qbus->parent, 1, false);
fail_guest_notifiers:
vblk->dataplane_disabled = true;
s->starting = false;
Expand All @@ -193,6 +220,8 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
unsigned i;
unsigned nvqs = s->conf->num_queues;

if (!vblk->dataplane_started || s->stopping) {
return;
Expand All @@ -210,17 +239,23 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
aio_context_acquire(s->ctx);

/* Stop notifications for new requests from guest */
virtio_queue_aio_set_host_notifier_handler(s->vq, s->ctx, NULL);
for (i = 0; i < nvqs; i++) {
VirtQueue *vq = virtio_get_queue(s->vdev, i);

virtio_queue_aio_set_host_notifier_handler(vq, s->ctx, NULL);
}

/* Drain and switch bs back to the QEMU main loop */
blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());

aio_context_release(s->ctx);

virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), 0, false);
for (i = 0; i < nvqs; i++) {
virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), i, false);
}

/* Clean up guest notifier (irq) */
k->set_guest_notifiers(qbus->parent, 1, false);
k->set_guest_notifiers(qbus->parent, nvqs, false);

vblk->dataplane_started = false;
s->stopping = false;
Expand Down
2 changes: 1 addition & 1 deletion hw/block/dataplane/virtio-blk.h
Expand Up @@ -26,6 +26,6 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);
void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s);
void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s);
void virtio_blk_data_plane_drain(VirtIOBlockDataPlane *s);
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s);
void virtio_blk_data_plane_notify(VirtIOBlockDataPlane *s, VirtQueue *vq);

#endif /* HW_DATAPLANE_VIRTIO_BLK_H */
57 changes: 42 additions & 15 deletions hw/block/virtio-blk.c
Expand Up @@ -29,9 +29,11 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"

void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req)
void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
VirtIOBlockReq *req)
{
req->dev = s;
req->vq = vq;
req->qiov.size = 0;
req->in_len = 0;
req->next = NULL;
Expand All @@ -53,11 +55,11 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
trace_virtio_blk_req_complete(req, status);

stb_p(&req->in->status, status);
virtqueue_push(s->vq, &req->elem, req->in_len);
virtqueue_push(req->vq, &req->elem, req->in_len);
if (s->dataplane_started && !s->dataplane_disabled) {
virtio_blk_data_plane_notify(s->dataplane);
virtio_blk_data_plane_notify(s->dataplane, req->vq);
} else {
virtio_notify(vdev, s->vq);
virtio_notify(vdev, req->vq);
}
}

Expand Down Expand Up @@ -187,12 +189,12 @@ static void virtio_blk_ioctl_complete(void *opaque, int status)

#endif

static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s, VirtQueue *vq)
{
VirtIOBlockReq *req = virtqueue_pop(s->vq, sizeof(VirtIOBlockReq));
VirtIOBlockReq *req = virtqueue_pop(vq, sizeof(VirtIOBlockReq));

if (req) {
virtio_blk_init_request(s, req);
virtio_blk_init_request(s, vq, req);
}
return req;
}
Expand Down Expand Up @@ -583,7 +585,7 @@ void virtio_blk_handle_vq(VirtIOBlock *s, VirtQueue *vq)

blk_io_plug(s->blk);

while ((req = virtio_blk_get_request(s))) {
while ((req = virtio_blk_get_request(s, vq))) {
virtio_blk_handle_request(req, &mrb);
}

Expand Down Expand Up @@ -708,6 +710,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
blkcfg.physical_block_exp = get_physical_block_exp(conf);
blkcfg.alignment_offset = 0;
blkcfg.wce = blk_enable_write_cache(s->blk);
virtio_stw_p(vdev, &blkcfg.num_queues, s->conf.num_queues);
memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
}

Expand Down Expand Up @@ -751,6 +754,9 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
if (blk_is_read_only(s->blk)) {
virtio_add_feature(&features, VIRTIO_BLK_F_RO);
}
if (s->conf.num_queues > 1) {
virtio_add_feature(&features, VIRTIO_BLK_F_MQ);
}

return features;
}
Expand Down Expand Up @@ -795,11 +801,6 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
static void virtio_blk_save(QEMUFile *f, void *opaque)
{
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
VirtIOBlock *s = VIRTIO_BLK(vdev);

if (s->dataplane) {
virtio_blk_data_plane_stop(s->dataplane);
}

virtio_save(vdev, f);
}
Expand All @@ -811,6 +812,11 @@ static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f)

while (req) {
qemu_put_sbyte(f, 1);

if (s->conf.num_queues > 1) {
qemu_put_be32(f, virtio_get_queue_index(req->vq));
}

qemu_put_virtqueue_element(f, &req->elem);
req = req->next;
}
Expand All @@ -834,9 +840,22 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
VirtIOBlock *s = VIRTIO_BLK(vdev);

while (qemu_get_sbyte(f)) {
unsigned nvqs = s->conf.num_queues;
unsigned vq_idx = 0;
VirtIOBlockReq *req;

if (nvqs > 1) {
vq_idx = qemu_get_be32(f);

if (vq_idx >= nvqs) {
error_report("Invalid virtqueue index in request list: %#x",
vq_idx);
return -EINVAL;
}
}

req = qemu_get_virtqueue_element(f, sizeof(VirtIOBlockReq));
virtio_blk_init_request(s, req);
virtio_blk_init_request(s, virtio_get_queue(vdev, vq_idx), req);
req->next = s->rq;
s->rq = req;
}
Expand All @@ -862,6 +881,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
VirtIOBlkConf *conf = &s->conf;
Error *err = NULL;
static int virtio_blk_id;
unsigned i;

if (!conf->conf.blk) {
error_setg(errp, "drive property not set");
Expand All @@ -871,6 +891,10 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
error_setg(errp, "Device needs media, but drive is empty");
return;
}
if (!conf->num_queues) {
error_setg(errp, "num-queues property must be larger than 0");
return;
}

blkconf_serial(&conf->conf, &conf->serial);
s->original_wce = blk_enable_write_cache(conf->conf.blk);
Expand All @@ -888,7 +912,9 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
s->rq = NULL;
s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1;

s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
for (i = 0; i < conf->num_queues; i++) {
virtio_add_queue(vdev, 128, virtio_blk_handle_output);
}
virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err);
if (err != NULL) {
error_propagate(errp, err);
Expand Down Expand Up @@ -941,6 +967,7 @@ static Property virtio_blk_properties[] = {
#endif
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
true),
DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
DEFINE_PROP_END_OF_LIST(),
};

Expand Down
5 changes: 0 additions & 5 deletions hw/scsi/virtio-scsi.c
Expand Up @@ -666,11 +666,6 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
static void virtio_scsi_save(QEMUFile *f, void *opaque)
{
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
VirtIOSCSI *s = VIRTIO_SCSI(vdev);

if (s->dataplane_started) {
virtio_scsi_dataplane_stop(s);
}
virtio_save(vdev, f);
}

Expand Down

0 comments on commit 12c8720

Please sign in to comment.