From 7ac37d34ed427bf0cbe12436f87112982ba990aa Mon Sep 17 00:00:00 2001
From: Greg Kurz <gkurz@linux.vnet.ibm.com>
Date: Tue, 24 Jun 2014 19:15:31 +0200
Subject: [PATCH] virtio: introduce device specific migration calls
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

In order to migrate virtio subsections, they should be streamed after
the device itself. We need the device specific code to be called from
the common migration code to achieve this. This patch introduces load
and save methods for this purpose.

Suggested-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Reviewed-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
(cherry picked from commit 1b5fc0dea469976fcbf6dc2e8f2637a2154af2fb)
Signed-off-by: Alexander Graf <agraf@suse.de>
---
 hw/block/virtio-blk.c       |  2 +-
 hw/char/virtio-serial-bus.c |  2 +-
 hw/net/virtio-net.c         |  2 +-
 hw/scsi/virtio-scsi.c       |  2 +-
 hw/virtio/virtio-balloon.c  |  2 +-
 hw/virtio/virtio-rng.c      |  2 +-
 hw/virtio/virtio.c          | 13 ++++++++++++-
 include/hw/virtio/virtio.h  |  4 +++-
 8 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 8a568e5edb..63d4ccdf2b 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -611,7 +611,7 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
     if (version_id != 2)
         return -EINVAL;
 
-    ret = virtio_load(vdev, f);
+    ret = virtio_load(vdev, f, version_id);
     if (ret) {
         return ret;
     }
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index ee1ba162aa..9f1df84baf 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -677,7 +677,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
     }
 
     /* The virtio device */
-    ret = virtio_load(VIRTIO_DEVICE(s), f);
+    ret = virtio_load(VIRTIO_DEVICE(s), f, version_id);
     if (ret) {
         return ret;
     }
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 2ac6ce5c25..1e9144c70f 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1350,7 +1350,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
     if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
         return -EINVAL;
 
-    ret = virtio_load(vdev, f);
+    ret = virtio_load(vdev, f, version_id);
     if (ret) {
         return ret;
     }
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index d183cd04cf..d0c94186f1 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -487,7 +487,7 @@ static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
     VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
     int ret;
 
-    ret = virtio_load(vdev, f);
+    ret = virtio_load(vdev, f, version_id);
     if (ret) {
         return ret;
     }
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index a470a0b3a6..6d8ec722eb 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -327,7 +327,7 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
     if (version_id != 1)
         return -EINVAL;
 
-    ret = virtio_load(vdev, f);
+    ret = virtio_load(vdev, f, version_id);
     if (ret) {
         return ret;
     }
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index b6ab3610cb..025de81345 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -113,7 +113,7 @@ static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
     if (version_id != 1) {
         return -EINVAL;
     }
-    virtio_load(vdev, f);
+    virtio_load(vdev, f, version_id);
 
     /* We may have an element ready but couldn't process it due to a quota
      * limit.  Make sure to try again after live migration when the quota may
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 3e4b70c50f..4843d6f78d 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -843,6 +843,7 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
 {
     BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
     int i;
 
     if (k->save_config) {
@@ -877,6 +878,10 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f)
             k->save_queue(qbus->parent, i, f);
         }
     }
+
+    if (vdc->save != NULL) {
+        vdc->save(vdev, f);
+    }
 }
 
 int virtio_set_features(VirtIODevice *vdev, uint32_t val)
@@ -895,7 +900,7 @@ int virtio_set_features(VirtIODevice *vdev, uint32_t val)
     return bad ? -1 : 0;
 }
 
-int virtio_load(VirtIODevice *vdev, QEMUFile *f)
+int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
 {
     int i, ret;
     int32_t config_len;
@@ -904,6 +909,7 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
     uint32_t supported_features;
     BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev);
 
     if (k->load_config) {
         ret = k->load_config(qbus->parent, f);
@@ -983,6 +989,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f)
     }
 
     virtio_notify_vector(vdev, VIRTIO_NO_VECTOR);
+
+    if (vdc->load != NULL) {
+        return vdc->load(vdev, f, version_id);
+    }
+
     return 0;
 }
 
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index 3e54e90aad..3505ce511e 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -150,6 +150,8 @@ typedef struct VirtioDeviceClass {
      * must mask in frontend instead.
      */
     void (*guest_notifier_mask)(VirtIODevice *vdev, int n, bool mask);
+    void (*save)(VirtIODevice *vdev, QEMUFile *f);
+    int (*load)(VirtIODevice *vdev, QEMUFile *f, int version_id);
 } VirtioDeviceClass;
 
 void virtio_init(VirtIODevice *vdev, const char *name,
@@ -184,7 +186,7 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq);
 
 void virtio_save(VirtIODevice *vdev, QEMUFile *f);
 
-int virtio_load(VirtIODevice *vdev, QEMUFile *f);
+int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id);
 
 void virtio_notify_config(VirtIODevice *vdev);
 
