mirror of https://github.com/xqemu/xqemu.git
virtio-blk: use generic vectored I/O APIs (Christoph Hellwig)
Use the generic bdrv_aio_readv/bdrv_aio_writev APIs instead of linearizing buffers directly. This enables using the future native preadv/pwritev support. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6903 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
522584a57b
commit
d28a1b6ec6
|
@ -35,8 +35,7 @@ typedef struct VirtIOBlockReq
|
||||||
VirtQueueElement elem;
|
VirtQueueElement elem;
|
||||||
struct virtio_blk_inhdr *in;
|
struct virtio_blk_inhdr *in;
|
||||||
struct virtio_blk_outhdr *out;
|
struct virtio_blk_outhdr *out;
|
||||||
size_t size;
|
QEMUIOVector qiov;
|
||||||
uint8_t *buffer;
|
|
||||||
struct VirtIOBlockReq *next;
|
struct VirtIOBlockReq *next;
|
||||||
} VirtIOBlockReq;
|
} VirtIOBlockReq;
|
||||||
|
|
||||||
|
@ -45,10 +44,9 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, int status)
|
||||||
VirtIOBlock *s = req->dev;
|
VirtIOBlock *s = req->dev;
|
||||||
|
|
||||||
req->in->status = status;
|
req->in->status = status;
|
||||||
virtqueue_push(s->vq, &req->elem, req->size + sizeof(*req->in));
|
virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
|
||||||
virtio_notify(&s->vdev, s->vq);
|
virtio_notify(&s->vdev, s->vq);
|
||||||
|
|
||||||
qemu_free(req->buffer);
|
|
||||||
qemu_free(req);
|
qemu_free(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,24 +74,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
VirtIOBlockReq *req = opaque;
|
VirtIOBlockReq *req = opaque;
|
||||||
|
|
||||||
/* Copy read data to the guest */
|
if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) {
|
||||||
if (!ret && !(req->out->type & VIRTIO_BLK_T_OUT)) {
|
|
||||||
size_t offset = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < req->elem.in_num - 1; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
/* Be pretty defensive wrt malicious guests */
|
|
||||||
len = MIN(req->elem.in_sg[i].iov_len,
|
|
||||||
req->size - offset);
|
|
||||||
|
|
||||||
memcpy(req->elem.in_sg[i].iov_base,
|
|
||||||
req->buffer + offset,
|
|
||||||
len);
|
|
||||||
offset += len;
|
|
||||||
}
|
|
||||||
} else if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) {
|
|
||||||
if (virtio_blk_handle_write_error(req, -ret))
|
if (virtio_blk_handle_write_error(req, -ret))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -122,39 +103,16 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtio_blk_handle_write(VirtIOBlockReq *req)
|
static void virtio_blk_handle_write(VirtIOBlockReq *req)
|
||||||
{
|
{
|
||||||
if (!req->buffer) {
|
bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
|
||||||
size_t offset = 0;
|
req->qiov.size / 512, virtio_blk_rw_complete, req);
|
||||||
int i;
|
}
|
||||||
|
|
||||||
for (i = 1; i < req->elem.out_num; i++)
|
static void virtio_blk_handle_read(VirtIOBlockReq *req)
|
||||||
req->size += req->elem.out_sg[i].iov_len;
|
{
|
||||||
|
bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
|
||||||
req->buffer = qemu_memalign(512, req->size);
|
req->qiov.size / 512, virtio_blk_rw_complete, req);
|
||||||
if (req->buffer == NULL) {
|
|
||||||
qemu_free(req);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We copy the data from the SG list to avoid splitting up the request.
|
|
||||||
This helps performance a lot until we can pass full sg lists as AIO
|
|
||||||
operations */
|
|
||||||
for (i = 1; i < req->elem.out_num; i++) {
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
len = MIN(req->elem.out_sg[i].iov_len,
|
|
||||||
req->size - offset);
|
|
||||||
memcpy(req->buffer + offset,
|
|
||||||
req->elem.out_sg[i].iov_base,
|
|
||||||
len);
|
|
||||||
offset += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bdrv_aio_write(req->dev->bs, req->out->sector, req->buffer, req->size / 512,
|
|
||||||
virtio_blk_rw_complete, req);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
|
@ -163,8 +121,6 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
VirtIOBlockReq *req;
|
VirtIOBlockReq *req;
|
||||||
|
|
||||||
while ((req = virtio_blk_get_request(s))) {
|
while ((req = virtio_blk_get_request(s))) {
|
||||||
int i;
|
|
||||||
|
|
||||||
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
|
if (req->elem.out_num < 1 || req->elem.in_num < 1) {
|
||||||
fprintf(stderr, "virtio-blk missing headers\n");
|
fprintf(stderr, "virtio-blk missing headers\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -187,23 +143,13 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
virtio_notify(vdev, vq);
|
virtio_notify(vdev, vq);
|
||||||
qemu_free(req);
|
qemu_free(req);
|
||||||
} else if (req->out->type & VIRTIO_BLK_T_OUT) {
|
} else if (req->out->type & VIRTIO_BLK_T_OUT) {
|
||||||
if (virtio_blk_handle_write(req) < 0)
|
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
|
||||||
break;
|
req->elem.out_num - 1);
|
||||||
|
virtio_blk_handle_write(req);
|
||||||
} else {
|
} else {
|
||||||
for (i = 0; i < req->elem.in_num - 1; i++)
|
qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
|
||||||
req->size += req->elem.in_sg[i].iov_len;
|
req->elem.in_num - 1);
|
||||||
|
virtio_blk_handle_read(req);
|
||||||
req->buffer = qemu_memalign(512, req->size);
|
|
||||||
if (req->buffer == NULL) {
|
|
||||||
qemu_free(req);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bdrv_aio_read(s->bs, req->out->sector,
|
|
||||||
req->buffer,
|
|
||||||
req->size / 512,
|
|
||||||
virtio_blk_rw_complete,
|
|
||||||
req);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue