@@ -92,11 +92,10 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
next = req->mr_next;
trace_virtio_blk_rw_complete(req, ret);
- if (req->qiov.nalloc != -1) {
- /* If nalloc is != 1 req->qiov is a local copy of the original
- * external iovec. It was allocated in submit_merged_requests
- * to be able to merge requests. */
+ if (req->in == NULL) {
qemu_iovec_destroy(&req->qiov);
+ virtio_blk_free_request(req);
+ continue;
}
if (ret) {
@@ -313,29 +312,33 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
static inline void submit_requests(BlockBackend *blk, MultiReqBuffer *mrb,
int start, int num_reqs, int niov)
{
- QEMUIOVector *qiov = &mrb->reqs[start]->qiov;
+ VirtIOBlockReq *merged_request;
+ QEMUIOVector *qiov;
int64_t sector_num = mrb->reqs[start]->sector_num;
- int nb_sectors = mrb->reqs[start]->qiov.size / BDRV_SECTOR_SIZE;
+ int nb_sectors = 0;
bool is_write = mrb->is_write;
if (num_reqs > 1) {
int i;
- struct iovec *tmp_iov = qiov->iov;
- int tmp_niov = qiov->niov;
- /* mrb->reqs[start]->qiov was initialized from external so we can't
- * modifiy it here. We need to initialize it locally and then add the
- * external iovecs. */
- qemu_iovec_init(qiov, niov)
+ merged_request = virtio_blk_alloc_request(mrb->reqs[start]->dev);
- for (i = 0; i < tmp_niov; i++) {
- qemu_iovec_add(qiov, tmp_iov[i].iov_base, tmp_iov[i].iov_len);
- }
+ /* use the 'in' field to judge whether the request is
+ a merged request */
+ merged_request->in = NULL;
+
+ qiov = &merged_request->qiov;
+ qemu_iovec_init(qiov, niov);
- for (i = start + 1; i < start + num_reqs; i++) {
+ for (i = start; i < start + num_reqs; i++) {
qemu_iovec_concat(qiov, &mrb->reqs[i]->qiov, 0,
mrb->reqs[i]->qiov.size);
- mrb->reqs[i - 1]->mr_next = mrb->reqs[i];
+ if (i > start) {
+ mrb->reqs[i - 1]->mr_next = mrb->reqs[i];
+ } else {
+ merged_request->mr_next = mrb->reqs[i];
+ }
+
nb_sectors += mrb->reqs[i]->qiov.size / BDRV_SECTOR_SIZE;
}
assert(nb_sectors == qiov->size / BDRV_SECTOR_SIZE);
@@ -345,14 +348,18 @@ static inline void submit_requests(BlockBackend *blk,
MultiReqBuffer *mrb,
block_acct_merge_done(blk_get_stats(blk),
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ,
num_reqs - 1);
+ } else {
+ merged_request = mrb->reqs[start];
+ qiov = &mrb->reqs[start]->qiov;
+ nb_sectors = mrb->reqs[start]->qiov.size / BDRV_SECTOR_SIZE;
}
if (is_write) {
blk_aio_writev(blk, sector_num, qiov, nb_sectors,
- virtio_blk_rw_complete, mrb->reqs[start]);
+ virtio_blk_rw_complete, merged_request);
} else {
blk_aio_readv(blk, sector_num, qiov, nb_sectors,
- virtio_blk_rw_complete, mrb->reqs[start]);
+ virtio_blk_rw_complete, merged_request);
}
}