@@ -822,9 +822,9 @@ static int virtio_blk_load_device(VirtIODevice *vdev, QEMUFile *f,
s->rq = req;
virtqueue_map_sg(req->elem.in_sg, req->elem.in_addr,
- req->elem.in_num, 1);
+ req->elem.in_num, 1, &error_abort);
virtqueue_map_sg(req->elem.out_sg, req->elem.out_addr,
- req->elem.out_num, 0);
+ req->elem.out_num, 0, &error_abort);
}
return 0;
@@ -703,9 +703,9 @@ static int fetch_active_ports_list(QEMUFile *f, int version_id,
qemu_get_buffer(f, (unsigned char *)&port->elem,
sizeof(port->elem));
virtqueue_map_sg(port->elem.in_sg, port->elem.in_addr,
- port->elem.in_num, 1);
+ port->elem.in_num, 1, &error_abort);
virtqueue_map_sg(port->elem.out_sg, port->elem.out_addr,
- port->elem.out_num, 1);
+ port->elem.out_num, 1, &error_abort);
/*
* Port was throttled on source machine. Let's
@@ -432,25 +432,32 @@ int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
}
void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
- size_t num_sg, int is_write)
+ size_t num_sg, int is_write,
+ Error **errp)
{
- unsigned int i;
+ int i;
hwaddr len;
if (num_sg > VIRTQUEUE_MAX_SIZE) {
- error_report("virtio: map attempt out of bounds: %zd > %d",
- num_sg, VIRTQUEUE_MAX_SIZE);
- exit(1);
+ error_setg(errp, "virtio: map attempt out of bounds: %zd > %d",
+ num_sg, VIRTQUEUE_MAX_SIZE);
+ return;
}
for (i = 0; i < num_sg; i++) {
len = sg[i].iov_len;
sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
if (sg[i].iov_base == NULL || len != sg[i].iov_len) {
- error_report("virtio: error trying to map MMIO memory");
- exit(1);
+ goto fail;
}
}
+ return;
+fail:
+ for ( ; i >= 0; i--) {
+ cpu_physical_memory_unmap(sg[i].iov_base, sg[i].iov_len,
+ is_write, 0);
+ }
+ error_setg(errp, "virtio: error trying to map MMIO memory");
}
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
@@ -514,8 +521,10 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
} while ((i = virtqueue_next_desc(vdev, desc_pa, i, max)) != max);
/* Now map what we have collected */
- virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1);
- virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0);
+ virtqueue_map_sg(elem->in_sg, elem->in_addr, elem->in_num, 1,
+ &error_abort);
+ virtqueue_map_sg(elem->out_sg, elem->out_addr, elem->out_num, 0,
+ &error_abort);
elem->index = head;
@@ -140,7 +140,8 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
unsigned int len, unsigned int idx);
void virtqueue_map_sg(struct iovec *sg, hwaddr *addr,
- size_t num_sg, int is_write);
+ size_t num_sg, int is_write,
+ Error **errp);
int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem);
int virtqueue_avail_bytes(VirtQueue *vq, unsigned int in_bytes,
unsigned int out_bytes);
virtqueue_map_sg calls error_report() and exit() when parameter is invalid, or when mapping failed. Lift the error check to caller, by adding errp. Also, when one of the mapping failed, previous maps are reverted for cleanness. All existing callers pass in error_abort for now. Signed-off-by: Fam Zheng <famz@redhat.com> --- hw/block/virtio-blk.c | 4 ++-- hw/char/virtio-serial-bus.c | 4 ++-- hw/virtio/virtio.c | 27 ++++++++++++++++++--------- include/hw/virtio/virtio.h | 3 ++- 4 files changed, 24 insertions(+), 14 deletions(-)