[RFC 12/22] hw/virtio: move to new migration APIs

Vladimir Sementsov-Ogievskiy posted 22 patches 2 weeks, 2 days ago
[RFC 12/22] hw/virtio: move to new migration APIs
Posted by Vladimir Sementsov-Ogievskiy 2 weeks, 2 days ago
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
 hw/virtio/vhost-user-fs.c      | 65 ++++++++++++++--------------
 hw/virtio/virtio-mmio.c        | 10 +++--
 hw/virtio/virtio-pci.c         | 10 +++--
 hw/virtio/virtio.c             | 78 ++++++++++++++++++++--------------
 include/hw/virtio/virtio-bus.h |  4 +-
 include/hw/virtio/virtio.h     |  2 -
 6 files changed, 94 insertions(+), 75 deletions(-)

diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c
index e77c69eb12..84a7663ea8 100644
--- a/hw/virtio/vhost-user-fs.c
+++ b/hw/virtio/vhost-user-fs.c
@@ -306,9 +306,11 @@ static struct vhost_dev *vuf_get_vhost(VirtIODevice *vdev)
 /**
  * Fetch the internal state from virtiofsd and save it to `f`.
  */
-static int vuf_save_state(QEMUFile *f, void *pv, size_t size,
-                          const VMStateField *field, JSONWriter *vmdesc)
+static bool vuf_save_state(QEMUFile *f, void *pv, size_t size,
+                           const VMStateField *field, JSONWriter *vmdesc,
+                           Error **errp)
 {
+    ERRP_GUARD();
     VirtIODevice *vdev = pv;
     VHostUserFS *fs = VHOST_USER_FS(vdev);
     Error *local_error = NULL;
@@ -316,39 +318,39 @@ static int vuf_save_state(QEMUFile *f, void *pv, size_t size,
 
     ret = vhost_save_backend_state(&fs->vhost_dev, f, &local_error);
     if (ret < 0) {
-        error_reportf_err(local_error,
-                          "Error saving back-end state of %s device %s "
-                          "(tag: \"%s\"): ",
-                          vdev->name, vdev->parent_obj.canonical_path,
-                          fs->conf.tag ?: "<none>");
-        return ret;
+        error_prepend(errp,
+                      "Error saving back-end state of %s device %s "
+                      "(tag: \"%s\"): ",
+                      vdev->name, vdev->parent_obj.canonical_path,
+                      fs->conf.tag ?: "<none>");
+        return false;
     }
 
-    return 0;
+    return true;
 }
 
 /**
  * Load virtiofsd's internal state from `f` and send it over to virtiofsd.
  */
-static int vuf_load_state(QEMUFile *f, void *pv, size_t size,
-                          const VMStateField *field)
+static bool vuf_load_state(QEMUFile *f, void *pv, size_t size,
+                           const VMStateField *field, Error **errp)
 {
+    ERRP_GUARD();
     VirtIODevice *vdev = pv;
     VHostUserFS *fs = VHOST_USER_FS(vdev);
-    Error *local_error = NULL;
     int ret;
 
-    ret = vhost_load_backend_state(&fs->vhost_dev, f, &local_error);
+    ret = vhost_load_backend_state(&fs->vhost_dev, f, errp);
     if (ret < 0) {
-        error_reportf_err(local_error,
-                          "Error loading back-end state of %s device %s "
-                          "(tag: \"%s\"): ",
-                          vdev->name, vdev->parent_obj.canonical_path,
-                          fs->conf.tag ?: "<none>");
-        return ret;
+        error_prepend(errp,
+                      "Error loading back-end state of %s device %s "
+                      "(tag: \"%s\"): ",
+                      vdev->name, vdev->parent_obj.canonical_path,
+                      fs->conf.tag ?: "<none>");
+        return false;
     }
 
-    return 0;
+    return true;
 }
 
 static bool vuf_is_internal_migration(void *opaque)
@@ -357,20 +359,21 @@ static bool vuf_is_internal_migration(void *opaque)
     return true;
 }
 
-static int vuf_check_migration_support(void *opaque)
+static bool vuf_check_migration_support(void *opaque, Error **errp)
 {
     VirtIODevice *vdev = opaque;
     VHostUserFS *fs = VHOST_USER_FS(vdev);
 
     if (!vhost_supports_device_state(&fs->vhost_dev)) {
-        error_report("Back-end of %s device %s (tag: \"%s\") does not support "
-                     "migration through qemu",
-                     vdev->name, vdev->parent_obj.canonical_path,
-                     fs->conf.tag ?: "<none>");
-        return -ENOTSUP;
+        error_setg(errp,
+                   "Back-end of %s device %s (tag: \"%s\") does not support "
+                   "migration through qemu",
+                   vdev->name, vdev->parent_obj.canonical_path,
+                   fs->conf.tag ?: "<none>");
+        return false;
     }
 
-    return 0;
+    return true;
 }
 
 static const VMStateDescription vuf_backend_vmstate;
@@ -392,15 +395,15 @@ static const VMStateDescription vuf_backend_vmstate = {
     .name = "vhost-user-fs-backend",
     .version_id = 0,
     .needed = vuf_is_internal_migration,
-    .pre_load = vuf_check_migration_support,
-    .pre_save = vuf_check_migration_support,
+    .pre_load_errp = vuf_check_migration_support,
+    .pre_save_errp = vuf_check_migration_support,
     .fields = (const VMStateField[]) {
         {
             .name = "back-end",
             .info = &(const VMStateInfo) {
                 .name = "virtio-fs back-end state",
-                .get = vuf_load_state,
-                .put = vuf_save_state,
+                .load = vuf_load_state,
+                .save = vuf_save_state,
             },
         },
         VMSTATE_END_OF_LIST()
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index fb58c36452..9d37ee029b 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -609,18 +609,20 @@ static const VMStateDescription vmstate_virtio_mmio = {
     }
 };
 
-static void virtio_mmio_save_extra_state(DeviceState *opaque, QEMUFile *f)
+static bool virtio_mmio_save_extra_state(DeviceState *opaque, QEMUFile *f,
+                                         Error **errp)
 {
     VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
 
-    vmstate_save_state(f, &vmstate_virtio_mmio, proxy, NULL, &error_fatal);
+    return vmstate_save_vmsd(f, &vmstate_virtio_mmio, proxy, NULL, errp);
 }
 
-static int virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f)
+static bool virtio_mmio_load_extra_state(DeviceState *opaque, QEMUFile *f,
+                                         Error **errp)
 {
     VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque);
 
-    return vmstate_load_state(f, &vmstate_virtio_mmio, proxy, 1, &error_fatal);
+    return vmstate_load_vmsd(f, &vmstate_virtio_mmio, proxy, 1, errp);
 }
 
 static bool virtio_mmio_has_extra_state(DeviceState *opaque)
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 937e22f08a..95faa84a58 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -184,18 +184,20 @@ static bool virtio_pci_has_extra_state(DeviceState *d)
     return true;
 }
 
-static void virtio_pci_save_extra_state(DeviceState *d, QEMUFile *f)
+static bool virtio_pci_save_extra_state(DeviceState *d, QEMUFile *f,
+                                        Error **errp)
 {
     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
 
-    vmstate_save_state(f, &vmstate_virtio_pci, proxy, NULL, &error_fatal);
+    return vmstate_save_vmsd(f, &vmstate_virtio_pci, proxy, NULL, errp);
 }
 
-static int virtio_pci_load_extra_state(DeviceState *d, QEMUFile *f)
+static bool virtio_pci_load_extra_state(DeviceState *d, QEMUFile *f,
+                                        Error **errp)
 {
     VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
 
-    return vmstate_load_state(f, &vmstate_virtio_pci, proxy, 1, &error_fatal);
+    return vmstate_load_vmsd(f, &vmstate_virtio_pci, proxy, 1, errp);
 }
 
 static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 153ee0a0cf..36e0493344 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2873,35 +2873,37 @@ static const VMStateDescription vmstate_virtio_ringsize = {
     }
 };
 
-static int get_extra_state(QEMUFile *f, void *pv, size_t size,
-                           const VMStateField *field)
+static bool load_extra_state(QEMUFile *f, void *pv, size_t size,
+                             const VMStateField *field,
+                             Error **errp)
 {
     VirtIODevice *vdev = pv;
     BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
 
     if (!k->load_extra_state) {
-        return -1;
+        error_setg(errp, "extra state is unsupported");
+        return false;
     } else {
-        return k->load_extra_state(qbus->parent, f);
+        return k->load_extra_state(qbus->parent, f, errp);
     }
 }
 
-static int put_extra_state(QEMUFile *f, void *pv, size_t size,
-                           const VMStateField *field, JSONWriter *vmdesc)
+static bool save_extra_state(QEMUFile *f, void *pv, size_t size,
+                             const VMStateField *field, JSONWriter *vmdesc,
+                             Error **errp)
 {
     VirtIODevice *vdev = pv;
     BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
 
-    k->save_extra_state(qbus->parent, f);
-    return 0;
+    return k->save_extra_state(qbus->parent, f, errp);
 }
 
 static const VMStateInfo vmstate_info_extra_state = {
     .name = "virtqueue_extra_state",
-    .get = get_extra_state,
-    .put = put_extra_state,
+    .load = load_extra_state,
+    .save = save_extra_state,
 };
 
 static const VMStateDescription vmstate_virtio_extra_state = {
@@ -3024,14 +3026,13 @@ static const VMStateDescription vmstate_virtio = {
     }
 };
 
-int virtio_save(VirtIODevice *vdev, QEMUFile *f)
+static bool virtio_save(VirtIODevice *vdev, QEMUFile *f, Error **errp)
 {
     BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
     VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
     uint32_t guest_features_lo = (vdev->guest_features & 0xffffffff);
     int i;
-    Error *local_err = NULL;
 
     if (k->save_config) {
         k->save_config(qbus->parent, f);
@@ -3075,39 +3076,54 @@ int virtio_save(VirtIODevice *vdev, QEMUFile *f)
     }
 
     if (vdc->vmsd) {
-        int ret = vmstate_save_state(f, vdc->vmsd, vdev, NULL, &local_err);
-        if (ret) {
-            error_report_err(local_err);
-            return ret;
+        if (!vmstate_save_vmsd(f, vdc->vmsd, vdev, NULL, errp)) {
+            return false;
         }
     }
 
     /* Subsections */
-    return vmstate_save_state(f, &vmstate_virtio, vdev, NULL, &error_fatal);
+    return vmstate_save_vmsd(f, &vmstate_virtio, vdev, NULL, &error_fatal);
 }
 
 /* A wrapper for use as a VMState .put function */
-static int virtio_device_put(QEMUFile *f, void *opaque, size_t size,
-                              const VMStateField *field, JSONWriter *vmdesc)
+static bool virtio_device_save(QEMUFile *f, void *opaque, size_t size,
+                               const VMStateField *field, JSONWriter *vmdesc,
+                               Error **errp)
 {
-    return virtio_save(VIRTIO_DEVICE(opaque), f);
+    return virtio_save(VIRTIO_DEVICE(opaque), f, errp);
 }
 
 /* A wrapper for use as a VMState .get function */
-static int coroutine_mixed_fn
-virtio_device_get(QEMUFile *f, void *opaque, size_t size,
-                  const VMStateField *field)
+static bool coroutine_mixed_fn
+virtio_device_load(QEMUFile *f, void *opaque, size_t size,
+                   const VMStateField *field, Error **errp)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
     DeviceClass *dc = DEVICE_CLASS(VIRTIO_DEVICE_GET_CLASS(vdev));
 
-    return virtio_load(vdev, f, dc->vmsd->version_id);
+    /* TODO: update virtio_load() to set errp and return bool */
+    int ret = virtio_load(vdev, f, dc->vmsd->version_id);
+
+    if (ret < 0) {
+        /*
+         * Using error_setg_errn or strerror would be incorrect,
+         * because virtio_load may mix simple -1 with -errno
+         * values on different paths.
+         *
+         * TODO: update virtio_load and all related callbacks
+         * to "errp + boolean return value" API.
+         */
+        error_setg(errp, "virtio_load failed: %d", ret);
+        return false;
+    }
+
+    return true;
 }
 
 const VMStateInfo  virtio_vmstate_info = {
     .name = "virtio",
-    .get = virtio_device_get,
-    .put = virtio_device_put,
+    .load = virtio_device_load,
+    .save = virtio_device_save,
 };
 
 static int virtio_set_features_nocheck(VirtIODevice *vdev, const uint64_t *val)
@@ -3387,18 +3403,16 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
     }
 
     if (vdc->vmsd) {
-        ret = vmstate_load_state(f, vdc->vmsd, vdev, version_id, &local_err);
-        if (ret) {
+        if (!vmstate_load_vmsd(f, vdc->vmsd, vdev, version_id, &local_err)) {
             error_report_err(local_err);
-            return ret;
+            return -EINVAL;
         }
     }
 
     /* Subsections */
-    ret = vmstate_load_state(f, &vmstate_virtio, vdev, 1, &local_err);
-    if (ret) {
+    if (!vmstate_load_vmsd(f, &vmstate_virtio, vdev, 1, &local_err)) {
         error_report_err(local_err);
-        return ret;
+        return -EINVAL;
     }
 
     if (vdev->device_endian == VIRTIO_DEVICE_ENDIAN_UNKNOWN) {
diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h
index 7ab8c9dab0..31bf2cd607 100644
--- a/include/hw/virtio/virtio-bus.h
+++ b/include/hw/virtio/virtio-bus.h
@@ -42,11 +42,11 @@ struct VirtioBusClass {
     void (*notify)(DeviceState *d, uint16_t vector);
     void (*save_config)(DeviceState *d, QEMUFile *f);
     void (*save_queue)(DeviceState *d, int n, QEMUFile *f);
-    void (*save_extra_state)(DeviceState *d, QEMUFile *f);
+    bool (*save_extra_state)(DeviceState *d, QEMUFile *f, Error **errp);
     int (*load_config)(DeviceState *d, QEMUFile *f);
     int (*load_queue)(DeviceState *d, int n, QEMUFile *f);
     int (*load_done)(DeviceState *d, QEMUFile *f);
-    int (*load_extra_state)(DeviceState *d, QEMUFile *f);
+    bool (*load_extra_state)(DeviceState *d, QEMUFile *f, Error **errp);
     bool (*has_extra_state)(DeviceState *d);
     bool (*query_guest_notifiers)(DeviceState *d);
     int (*set_guest_notifiers)(DeviceState *d, int nvqs, bool assign);
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index d97529c3f1..d729502eca 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -296,8 +296,6 @@ int virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes,
 
 void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
 
-int virtio_save(VirtIODevice *vdev, QEMUFile *f);
-
 extern const VMStateInfo virtio_vmstate_info;
 
 #define VMSTATE_VIRTIO_DEVICE \
-- 
2.48.1