From 503dae393a0fa02439d0fbf169f9aa9fd12b251e Mon Sep 17 00:00:00 2001
From: Juan Quintela <quintela@redhat.com>
Date: Wed, 7 Jul 2010 12:48:29 -0300
Subject: [PATCH 2/6] vmstate: add subsections code

RH-Author: Juan Quintela <quintela@redhat.com>
Message-id: <c72243c10ec6c495684d8a6ad1cfe200faab0407.1278506570.git.quintela@redhat.com>
Patchwork-id: 10525
O-Subject: [PATCH 2/5] vmstate: add subsections code
Bugzilla: 612481
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com>
RH-Acked-by: Jes Sorensen <Jes.Sorensen@redhat.com>

This commit adds subsections for each device section.
Subsections is the way to handle information that don't need to be sent
to de destination of a migration because its values are not needed.  It is
the way to handle optional information.  Notice that only the source can
decide if the information is optional or not.  The destination needs to
understand all subsections that it receives to have a sucessful load.

Signed-off-by: Juan Quintela <quintela@redhat.com>
---
 hw/hw.h  |    6 ++++
 savevm.c |   86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 91 insertions(+), 1 deletions(-)

Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
 hw/hw.h  |    6 ++++
 savevm.c |   86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 91 insertions(+), 1 deletions(-)

diff --git a/hw/hw.h b/hw/hw.h
index 37f8545..82fbcaf 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -314,6 +314,11 @@ typedef struct {
     bool (*field_exists)(void *opaque, int version_id);
 } VMStateField;
 
+typedef struct VMStateSubsection {
+    const VMStateDescription *vmsd;
+    bool (*needed)(void *opaque);
+} VMStateSubsection;
+
 struct VMStateDescription {
     const char *name;
     int version_id;
@@ -325,6 +330,7 @@ struct VMStateDescription {
     void (*pre_save)(void *opaque);
     void (*post_save)(void *opaque);
     VMStateField *fields;
+    const VMStateSubsection *subsections;
 };
 
 extern const VMStateInfo vmstate_info_int8;
diff --git a/savevm.c b/savevm.c
index 98e5c77..e86561f 100644
--- a/savevm.c
+++ b/savevm.c
@@ -552,6 +552,19 @@ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)
     return size1 - size;
 }
 
+static int qemu_peek_byte(QEMUFile *f)
+{
+    if (f->is_write)
+        abort();
+
+    if (f->buf_index >= f->buf_size) {
+        qemu_fill_buffer(f);
+        if (f->buf_index >= f->buf_size)
+            return 0;
+    }
+    return f->buf[f->buf_index];
+}
+
 int qemu_get_byte(QEMUFile *f)
 {
     if (f->is_write)
@@ -1139,10 +1152,16 @@ void vmstate_unregister(const VMStateDescription *vmsd, void *opaque)
     }
 }
 
+static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+                                    void *opaque);
+static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+                                   void *opaque);
+
 int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
                        void *opaque, int version_id)
 {
     VMStateField *field = vmsd->fields;
+    int ret;
 
     if (version_id > vmsd->version_id) {
         return -EINVAL;
@@ -1164,7 +1183,7 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
             (!field->field_exists &&
              field->version_id <= version_id)) {
             void *base_addr = opaque + field->offset;
-            int ret, i, n_elems = 1;
+            int i, n_elems = 1;
             int size = field->size;
 
             if (field->flags & VMS_VBUFFER) {
@@ -1202,6 +1221,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
         }
         field++;
     }
+    ret = vmstate_subsection_load(f, vmsd, opaque);
+    if (ret != 0) {
+        return ret;
+    }
     if (vmsd->post_load) {
         return vmsd->post_load(opaque, version_id);
     }
@@ -1254,6 +1277,7 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
         }
         field++;
     }
+    vmstate_subsection_save(f, vmsd, opaque);
     if (vmsd->post_save) {
         vmsd->post_save(opaque);
     }
@@ -1285,6 +1309,7 @@ static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
 #define QEMU_VM_SECTION_PART         0x02
 #define QEMU_VM_SECTION_END          0x03
 #define QEMU_VM_SECTION_FULL         0x04
+#define QEMU_VM_SUBSECTION           0x05
 
 int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable,
                             int shared)
@@ -1463,6 +1488,65 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id)
     return NULL;
 }
 
+static const VMStateDescription *vmstate_get_subsection(const VMStateSubsection *sub, char *idstr)
+{
+    while(sub && sub->needed) {
+        if (strcmp(idstr, sub->vmsd->name) == 0) {
+            return sub->vmsd;
+        }
+        sub++;
+    }
+    return NULL;
+}
+
+static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+                                   void *opaque)
+{
+    while (qemu_peek_byte(f) == QEMU_VM_SUBSECTION) {
+        char idstr[256];
+        int ret;
+        uint8_t version_id, subsection, len;
+        const VMStateDescription *sub_vmsd;
+
+        subsection = qemu_get_byte(f);
+        len = qemu_get_byte(f);
+        qemu_get_buffer(f, (uint8_t *)idstr, len);
+        idstr[len] = 0;
+        version_id = qemu_get_be32(f);
+
+        sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
+        if (sub_vmsd == NULL) {
+            return -ENOENT;
+        }
+        ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
+        if (ret) {
+            return ret;
+        }
+    }
+    return 0;
+}
+
+static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+                                    void *opaque)
+{
+    const VMStateSubsection *sub = vmsd->subsections;
+
+    while (sub && sub->needed) {
+        if (sub->needed(opaque)) {
+            const VMStateDescription *vmsd = sub->vmsd;
+            uint8_t len;
+
+            qemu_put_byte(f, QEMU_VM_SUBSECTION);
+            len = strlen(vmsd->name);
+            qemu_put_byte(f, len);
+            qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
+            qemu_put_be32(f, vmsd->version_id);
+            vmstate_save_state(f, vmsd, opaque);
+        }
+        sub++;
+    }
+}
+
 typedef struct LoadStateEntry {
     QLIST_ENTRY(LoadStateEntry) entry;
     SaveStateEntry *se;
-- 
1.7.0.3

