diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index 1222a37..aa4ad91 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -96,9 +96,8 @@ static void handle_notify(EventNotifier *e)
event_notifier_test_and_clear(&s->host_notifier);
blk_io_plug(s->conf->conf.blk);
for (;;) {
- MultiReqBuffer mrb = {
- .num_writes = 0,
- };
+ MultiReqBuffer mrb_rd = {};
+ MultiReqBuffer mrb_wr = {.is_write = 1};
int ret;
/* Disable guest->host notifies to avoid unnecessary vmexits */
@@ -117,10 +116,11 @@ static void handle_notify(EventNotifier *e)
req->elem.in_num,
req->elem.index);
- virtio_blk_handle_request(req, &mrb);
+ virtio_blk_handle_request(req, &mrb_wr, &mrb_rd);
}
- virtio_submit_multiwrite(s->conf->conf.blk, &mrb);
+ virtio_submit_multireq(s->conf->conf.blk, &mrb_wr);
+ virtio_submit_multireq(s->conf->conf.blk, &mrb_rd);
if (likely(ret == -EAGAIN)) { /* vring emptied */
/* Re-enable guest->host notifies and stop processing the vring.
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 490f961..f522bfc 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -22,12 +22,15 @@
#include "dataplane/virtio-blk.h"
#include "migration/migration.h"
#include "block/scsi.h"
+#include "block/block_int.h"
#ifdef __linux__
# include <scsi/sg.h>
#endif
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
+/* #define DEBUG_MULTIREQ */
+
VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
{
VirtIOBlockReq *req = g_slice_new(VirtIOBlockReq);
@@ -88,6 +91,11 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
trace_virtio_blk_rw_complete(req, ret);
+#ifdef DEBUG_MULTIREQ
+ printf("virtio_blk_rw_complete p %p ret %d\n",
+ req, ret);
+#endif
+
if (ret) {
int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
bool is_read = !(p & VIRTIO_BLK_T_OUT);
@@ -257,24 +265,63 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
virtio_blk_free_request(req);
}
-void virtio_submit_multiwrite(BlockBackend *blk, MultiReqBuffer *mrb)
+static void virtio_multireq_cb(void *opaque, int ret)
+{
+ MultiReqBuffer *mrb = opaque;
+ int i;
+#ifdef DEBUG_MULTIREQ
+ printf("virtio_multireq_cb: p %p sector_num %ld nb_sectors %d is_write %d
num_reqs %d\n",
+ mrb, mrb->sector_num, mrb->nb_sectors, mrb->is_write,
mrb->num_reqs);
+#endif
+ for (i = 0; i < mrb->num_reqs; i++) {
+ virtio_blk_rw_complete(mrb->reqs[i], ret);
+ }
+
+ qemu_iovec_destroy(&mrb->qiov);
+ g_free(mrb);
+}
+
+void virtio_submit_multireq(BlockBackend *blk, MultiReqBuffer *mrb0)
{
- int i, ret;
+ MultiReqBuffer *mrb = NULL;
- if (!mrb->num_writes) {
+ if (!mrb0->num_reqs) {
return;
}
- ret = blk_aio_multiwrite(blk, mrb->blkreq, mrb->num_writes);
- if (ret != 0) {
- for (i = 0; i < mrb->num_writes; i++) {
- if (mrb->blkreq[i].error) {
- virtio_blk_rw_complete(mrb->blkreq[i].opaque, -EIO);
- }
+ if (mrb0->num_reqs == 1) {
+ if (mrb0->is_write) {
+ blk_aio_writev(blk, mrb0->sector_num, &mrb0->reqs[0]->qiov,
mrb0->nb_sectors,
+ virtio_blk_rw_complete, mrb0->reqs[0]);
+ } else {
+ blk_aio_readv(blk, mrb0->sector_num, &mrb0->reqs[0]->qiov,
mrb0->nb_sectors,
+ virtio_blk_rw_complete, mrb0->reqs[0]);
}
+ qemu_iovec_destroy(&mrb0->qiov);
+ mrb0->num_reqs = 0;
+ return;
+ }
+
+ mrb = g_malloc(sizeof(MultiReqBuffer));
+ memcpy(mrb, mrb0, sizeof(MultiReqBuffer));
+ mrb0->num_reqs = 0;
+
+#ifdef DEBUG_MULTIREQ
+ printf("virtio_submit_multireq: p %p sector_num %ld nb_sectors %d is_write %d
num_reqs %d\n",
+ mrb, mrb->sector_num, mrb->nb_sectors, mrb->is_write,
mrb->num_reqs);
+#endif
+
+ if (mrb->is_write) {
+ blk_aio_writev(blk, mrb->sector_num, &mrb->qiov, mrb->nb_sectors,
+ virtio_multireq_cb, mrb);
+ } else {
+ blk_aio_readv(blk, mrb->sector_num, &mrb->qiov, mrb->nb_sectors,
+ virtio_multireq_cb, mrb);
}
- mrb->num_writes = 0;
+ block_acct_merge_done(blk_get_stats(blk),
+ mrb->is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ,
+ mrb->num_reqs - 1);
}
static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
@@ -283,9 +330,9 @@ static void virtio_blk_handle_flush(VirtIOBlockReq *req,
MultiReqBuffer *mrb)
BLOCK_ACCT_FLUSH);
/*
- * Make sure all outstanding writes are posted to the backing device.
+ * Make sure all outstanding requests are posted to the backing device.
*/
- virtio_submit_multiwrite(req->dev->blk, mrb);
+ virtio_submit_multireq(req->dev->blk, mrb);
blk_aio_flush(req->dev->blk, virtio_blk_flush_complete, req);
}
@@ -308,61 +355,8 @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
return true;
}
-static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
-{
- BlockRequest *blkreq;
- uint64_t sector;
-
- sector = virtio_ldq_p(VIRTIO_DEVICE(req->dev), &req->out.sector);
-
- trace_virtio_blk_handle_write(req, sector, req->qiov.size / 512);
-
- if (!virtio_blk_sect_range_ok(req->dev, sector, req->qiov.size)) {
- virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
- virtio_blk_free_request(req);
- return;
- }
-
- block_acct_start(blk_get_stats(req->dev->blk), &req->acct, req->qiov.size,
- BLOCK_ACCT_WRITE);
-
- if (mrb->num_writes == VIRTIO_BLK_MAX_MERGE_REQS) {
- virtio_submit_multiwrite(req->dev->blk, mrb);
- }
-
- blkreq = &mrb->blkreq[mrb->num_writes];
- blkreq->sector = sector;
- blkreq->nb_sectors = req->qiov.size / BDRV_SECTOR_SIZE;
- blkreq->qiov = &req->qiov;
- blkreq->cb = virtio_blk_rw_complete;
- blkreq->opaque = req;
- blkreq->error = 0;
-
- mrb->num_writes++;
-}
-
-static void virtio_blk_handle_read(VirtIOBlockReq *req)
-{
- uint64_t sector;
-
- sector = virtio_ldq_p(VIRTIO_DEVICE(req->dev), &req->out.sector);
-
- trace_virtio_blk_handle_read(req, sector, req->qiov.size / 512);
-
- if (!virtio_blk_sect_range_ok(req->dev, sector, req->qiov.size)) {
- virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
- virtio_blk_free_request(req);
- return;
- }
-
- block_acct_start(blk_get_stats(req->dev->blk), &req->acct, req->qiov.size,
- BLOCK_ACCT_READ);
- blk_aio_readv(req->dev->blk, sector, &req->qiov,
- req->qiov.size / BDRV_SECTOR_SIZE,
- virtio_blk_rw_complete, req);
-}
-
-void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
+void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb_wr,
+ MultiReqBuffer *mrb_rd)
{
uint32_t type;
struct iovec *in_iov = req->elem.in_sg;
@@ -397,7 +391,7 @@ void virtio_blk_handle_request(VirtIOBlockReq *req,
MultiReqBuffer *mrb)
type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
if (type & VIRTIO_BLK_T_FLUSH) {
- virtio_blk_handle_flush(req, mrb);
+ virtio_blk_handle_flush(req, mrb_wr);
} else if (type & VIRTIO_BLK_T_SCSI_CMD) {
virtio_blk_handle_scsi(req);
} else if (type & VIRTIO_BLK_T_GET_ID) {
@@ -414,13 +408,71 @@ void virtio_blk_handle_request(VirtIOBlockReq *req,
MultiReqBuffer *mrb)
iov_from_buf(in_iov, in_num, 0, serial, size);
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
virtio_blk_free_request(req);
- } else if (type & VIRTIO_BLK_T_OUT) {
- qemu_iovec_init_external(&req->qiov, iov, out_num);
- virtio_blk_handle_write(req, mrb);
- } else if (type == VIRTIO_BLK_T_IN || type == VIRTIO_BLK_T_BARRIER) {
- /* VIRTIO_BLK_T_IN is 0, so we can't just & it. */
- qemu_iovec_init_external(&req->qiov, in_iov, in_num);
- virtio_blk_handle_read(req);
+ } else if (type & VIRTIO_BLK_T_OUT || type == VIRTIO_BLK_T_IN || type ==
VIRTIO_BLK_T_BARRIER) {