-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJXcnpMAAoJEJykq7OBq3PIymwIAJDUKUCfGOX0ihe2ZwSHEQLP NfKp4JH4rQE1EoDbq1Z2WOrxjw8KVYBN8dsq6yfOnEiIw88wp4XSaz9w6gSBs0wH Z+6V8b/OMh8BwVZ7Y4zNtXrP0qP7DbD15FzLQLc3Eed32cjDmMDHFFixoB9PlWQM 2G6aOFtP8DzMl+lJ0iUzy3RWwZWSiLdBR9IEpYvLhBn1QRZ4HtWME2Yl42YCzSho TZzyBqSHzKY2pT/aLKIxovONLxTrmkrF9dhX0J6pggr/Nux6oqMQQUTT4DW7V3OF +N8Ekt3Ygu8KYvQXiBxYANCXOvEkMfdKNcQGmFXs2DaNirGEGpt5o9b8lsEhNMw= =Gyiy -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' 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>
This commit is contained in:
commit
12c8720d8f
@ -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,
|
||||
|
@ -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
|
||||
@ -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];
|
||||
|
||||
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 */
|
||||
}
|
||||
}
|
||||
|
||||
event_notifier_set(s->guest_notifier);
|
||||
}
|
||||
|
||||
/* Context: QEMU global mutex held */
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
@ -138,6 +154,8 @@ 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) {
|
||||
@ -145,22 +163,25 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
|
||||
}
|
||||
|
||||
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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,12 +189,12 @@ out:
|
||||
|
||||
#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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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");
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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(),
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ struct VirtIOBlkConf
|
||||
uint32_t scsi;
|
||||
uint32_t config_wce;
|
||||
uint32_t request_merging;
|
||||
uint16_t num_queues;
|
||||
};
|
||||
|
||||
struct VirtIOBlockDataPlane;
|
||||
@ -46,7 +47,6 @@ struct VirtIOBlockReq;
|
||||
typedef struct VirtIOBlock {
|
||||
VirtIODevice parent_obj;
|
||||
BlockBackend *blk;
|
||||
VirtQueue *vq;
|
||||
void *rq;
|
||||
QEMUBH *bh;
|
||||
VirtIOBlkConf conf;
|
||||
@ -62,6 +62,7 @@ typedef struct VirtIOBlockReq {
|
||||
VirtQueueElement elem;
|
||||
int64_t sector_num;
|
||||
VirtIOBlock *dev;
|
||||
VirtQueue *vq;
|
||||
struct virtio_blk_inhdr *in;
|
||||
struct virtio_blk_outhdr out;
|
||||
QEMUIOVector qiov;
|
||||
@ -79,7 +80,8 @@ typedef struct MultiReqBuffer {
|
||||
bool is_write;
|
||||
} MultiReqBuffer;
|
||||
|
||||
void virtio_blk_init_request(VirtIOBlock *s, VirtIOBlockReq *req);
|
||||
void virtio_blk_init_request(VirtIOBlock *s, VirtQueue *vq,
|
||||
VirtIOBlockReq *req);
|
||||
void virtio_blk_free_request(VirtIOBlockReq *req);
|
||||
|
||||
void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb);
|
||||
|
Loading…
Reference in New Issue
Block a user