diff mbox

[01/18] virtio: Return error from virtqueue_map_sg

Message ID 1429257573-7359-2-git-send-email-famz@redhat.com
State New
Headers show

Commit Message

Fam Zheng April 17, 2015, 7:59 a.m. UTC
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(-)
diff mbox

Patch

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 9546fd2..f7d8528 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -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;
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index e336bdb..1e07858 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -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
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 17c1260..179c412 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -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;
 
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index d95f8b6..64c10cf 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -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);