[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC PATCH v2 09/16] Visitor: Load path
From: |
Dr. David Alan Gilbert (git) |
Subject: |
[Qemu-devel] [RFC PATCH v2 09/16] Visitor: Load path |
Date: |
Wed, 23 Apr 2014 17:37:42 +0100 |
From: "Dr. David Alan Gilbert" <address@hidden>
Hacks in piix4.c, pci.c, spapr_vscsi.c for now
Signed-off-by: Dr. David Alan Gilbert <address@hidden>
---
arch_init.c | 93 +++++++++++++++---------------
hw/acpi/piix4.c | 5 +-
hw/pci/pci.c | 3 +-
hw/scsi/spapr_vscsi.c | 3 +-
include/migration/vmstate.h | 2 +-
savevm.c | 133 +++++++++++++++++++++++++++++++------------
vmstate.c | 135 +++++++++++++++++++++++++++++++++-----------
7 files changed, 256 insertions(+), 118 deletions(-)
diff --git a/arch_init.c b/arch_init.c
index faf72ff..88023b5 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -960,31 +960,23 @@ static uint64_t ram_save_pending(void *opaque, uint64_t
max_size)
return remaining_size;
}
-static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
+static int load_xbzrle(Visitor *v, ram_addr_t addr, void *host, size_t xh_len)
{
int ret, rc = 0;
- unsigned int xh_len;
- int xh_flags;
+ Error *local_err = NULL;
if (!xbzrle_decoded_buf) {
xbzrle_decoded_buf = g_malloc(TARGET_PAGE_SIZE);
}
- /* extract RLE header */
- xh_flags = qemu_get_byte(f);
- xh_len = qemu_get_be16(f);
-
- if (xh_flags != ENCODING_FLAG_XBZRLE) {
- fprintf(stderr, "Failed to load XBZRLE page - wrong compression!\n");
- return -1;
- }
-
if (xh_len > TARGET_PAGE_SIZE) {
fprintf(stderr, "Failed to load XBZRLE page - len overflow!\n");
return -1;
}
/* load data and decode */
- qemu_get_buffer(f, xbzrle_decoded_buf, xh_len);
+ visit_type_buffer(v, xbzrle_decoded_buf, xh_len, false, "xbzrle",
+ &local_err);
+ LOCAL_ERR_REPORT(return -1;);
/* decode RLE */
ret = xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
@@ -1001,15 +993,12 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr,
void *host)
return rc;
}
-static inline void *host_from_stream_offset(QEMUFile *f,
- ram_addr_t offset,
- int flags)
+static inline void *host_from_stream_offset(ramsecentry_header *rse_hdr)
{
static RAMBlock *block = NULL;
- char id[256];
- uint8_t len;
+ ram_addr_t offset = rse_hdr->addr;
- if (flags & RAM_SAVE_FLAG_CONTINUE) {
+ if (rse_hdr->flags & RAM_SAVE_FLAG_CONTINUE) {
if (!block) {
fprintf(stderr, "Ack, bad migration stream!\n");
return NULL;
@@ -1018,16 +1007,13 @@ static inline void *host_from_stream_offset(QEMUFile *f,
return memory_region_get_ram_ptr(block->mr) + offset;
}
- len = qemu_get_byte(f);
- qemu_get_buffer(f, (uint8_t *)id, len);
- id[len] = 0;
-
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
- if (!strncmp(id, block->idstr, sizeof(id)))
+ if (!strncmp(rse_hdr->idstr, block->idstr, sizeof(rse_hdr->idstr))) {
return memory_region_get_ram_ptr(block->mr) + offset;
+ }
}
- fprintf(stderr, "Can't find block %s!\n", id);
+ fprintf(stderr, "Can't find block %s!\n", rse_hdr->idstr);
return NULL;
}
@@ -1048,6 +1034,9 @@ static int ram_load(QEMUFile *f, void *opaque, int
version_id)
int flags, ret = 0;
int error;
static uint64_t seq_iter;
+ Error *local_err = NULL;
+ ramsecentry_header rse_hdr;
+ Visitor *v = qemu_file_get_tmp_visitor(f); // TODO
seq_iter++;
@@ -1055,11 +1044,18 @@ static int ram_load(QEMUFile *f, void *opaque, int
version_id)
return -EINVAL;
}
- do {
- addr = qemu_get_be64(f);
-
- flags = addr & ~TARGET_PAGE_MASK;
- addr &= TARGET_PAGE_MASK;
+ visit_start_sequence_compat(v, "ramseclist", VISIT_SEQ_COMPAT_RAMSECLIST,
+ NULL, &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
+ while (visit_get_next_type(v, &flags, NULL, "ramseclist", &local_err),
+ (!local_err && !(flags & RAM_SAVE_FLAG_EOS))) {
+ LOCAL_ERR_REPORT(return -EINVAL;);
+ visit_start_sequence_compat(v, "ramsecentry",
+ VISIT_SEQ_COMPAT_RAMSECENTRY, &rse_hdr,
+ &local_err);
+ addr = rse_hdr.addr;
+ flags = rse_hdr.flags;
+ LOCAL_ERR_REPORT(return -EINVAL;);
if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
if (version_id == 4) {
@@ -1070,12 +1066,14 @@ static int ram_load(QEMUFile *f, void *opaque, int
version_id)
while (total_ram_bytes) {
RAMBlock *block;
- uint8_t len;
+ visit_start_struct(v, NULL, "blockid", "blockid", 0,
+ &local_err);
+ visit_type_str256(v, id, "blockname", &local_err);
+ visit_type_uint64(v, &length, "blocklen", &local_err);
+ LOCAL_ERR_REPORT(ret = -EINVAL; goto done;);
+ visit_end_struct(v, &local_err);
+ LOCAL_ERR_REPORT(ret = -EINVAL; goto done;);
- len = qemu_get_byte(f);
- qemu_get_buffer(f, (uint8_t *)id, len);
- id[len] = 0;
- length = qemu_get_be64(f);
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
if (!strncmp(id, block->idstr, sizeof(id))) {
@@ -1100,36 +1098,37 @@ static int ram_load(QEMUFile *f, void *opaque, int
version_id)
total_ram_bytes -= length;
}
+ LOCAL_ERR_REPORT(ret = -EINVAL; goto done;);
}
}
if (flags & RAM_SAVE_FLAG_COMPRESS) {
void *host;
- uint8_t ch;
- host = host_from_stream_offset(f, addr, flags);
+ host = host_from_stream_offset(&rse_hdr);
if (!host) {
return -EINVAL;
}
- ch = qemu_get_byte(f);
- ram_handle_compressed(host, ch, TARGET_PAGE_SIZE);
+ ram_handle_compressed(host, rse_hdr.ch, TARGET_PAGE_SIZE);
} else if (flags & RAM_SAVE_FLAG_PAGE) {
void *host;
- host = host_from_stream_offset(f, addr, flags);
+ host = host_from_stream_offset(&rse_hdr);
if (!host) {
return -EINVAL;
}
- qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
+ visit_type_buffer(v, host, TARGET_PAGE_SIZE, false, "page",
+ &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
- void *host = host_from_stream_offset(f, addr, flags);
+ void *host = host_from_stream_offset(&rse_hdr);
if (!host) {
return -EINVAL;
}
- if (load_xbzrle(f, addr, host) < 0) {
+ if (load_xbzrle(v, addr, host, rse_hdr.len) < 0) {
ret = -EINVAL;
goto done;
}
@@ -1141,7 +1140,13 @@ static int ram_load(QEMUFile *f, void *opaque, int
version_id)
ret = error;
goto done;
}
- } while (!(flags & RAM_SAVE_FLAG_EOS));
+ visit_end_sequence_compat(v, "ramsecentry",
+ VISIT_SEQ_COMPAT_RAMSECENTRY, &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
+ };
+ visit_end_sequence_compat(v, "ramseclist", VISIT_SEQ_COMPAT_RAMSECLIST,
+ &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
done:
DPRINTF("Completed load of VM with exit code %d seq iteration "
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 67dc075..a44f4b8 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -211,7 +211,8 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int
version_id)
qemu_get_be16s(f, &s->ar.pm1.evt.en);
qemu_get_be16s(f, &s->ar.pm1.cnt.cnt);
- ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1);
+ ret = vmstate_load_state(qemu_file_get_tmp_visitor(f), &vmstate_apm,
+ &s->apm, 1);
if (ret) {
return ret;
}
@@ -229,7 +230,7 @@ static int acpi_load_old(QEMUFile *f, void *opaque, int
version_id)
qemu_get_be16s(f, &temp);
}
- ret = vmstate_load_state(f, &vmstate_pci_status,
+ ret = vmstate_load_state(qemu_file_get_tmp_visitor(f), &vmstate_pci_status,
&s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT],
1);
return ret;
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index f8b164d..7e8d735 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -523,7 +523,8 @@ void pci_device_save(PCIDevice *s, QEMUFile *f)
int pci_device_load(PCIDevice *s, QEMUFile *f)
{
int ret;
- ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id);
+ ret = vmstate_load_state(qemu_file_get_tmp_visitor(f),
+ pci_get_vmstate(s), s, s->version_id);
/* Restore the interrupt status bit. */
pci_update_irq_status(s);
return ret;
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index e99ebfd..076b558 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -643,7 +643,8 @@ static void *vscsi_load_request(QEMUFile *f, SCSIRequest
*sreq)
assert(!req->active);
memset(req, 0, sizeof(*req));
- rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1);
+ rc = vmstate_load_state(qemu_file_get_tmp_visitor(f),
+ &vmstate_spapr_vscsi_req, req, 1);
if (rc) {
fprintf(stderr, "VSCSI: failed loading request tag#%u\n", sreq->tag);
return NULL;
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index b66342b..d22c4e3 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -759,7 +759,7 @@ extern const VMStateInfo vmstate_info_bitmap;
#define VMSTATE_END_OF_LIST() \
{}
-int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+int vmstate_load_state(Visitor *v, const VMStateDescription *vmsd,
void *opaque, int version_id);
void vmstate_save_state(Visitor *v, const VMStateDescription *vmsd,
void *opaque);
diff --git a/savevm.c b/savevm.c
index 56e6f83..515dd77 100644
--- a/savevm.c
+++ b/savevm.c
@@ -437,13 +437,42 @@ void vmstate_unregister(DeviceState *dev, const
VMStateDescription *vmsd,
}
}
-static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
+static int vmstate_load(Visitor *v, SaveStateEntry *se, int version_id)
{
trace_vmstate_load(se->idstr, se->vmsd ? se->vmsd->name : "(old)");
+ int ret;
+ Error *local_err = NULL;
+
if (!se->vmsd) { /* Old style */
- return se->ops->load_state(f, se->opaque, version_id);
+ QEMUFile *wrapperf;
+ bool is_iterative = se->ops->save_live_iterate != NULL;
+
+ /* Some visitors put old format things down separate QEMUFile's -
+ * but not the iterators which must use the visitors now -
+ * but TODO they need their interface changing
+ */
+
+ if (!is_iterative) {
+ visit_start_sequence_compat(v, "oldstate",
+ VISIT_SEQ_COMPAT_BLOB, &wrapperf, &local_err);
+ }
+ LOCAL_ERR_REPORT(return -EINVAL;);
+
+ ret = se->ops->load_state(is_iterative ? visitor_get_qemufile(v) :
+ wrapperf,
+ se->opaque, version_id);
+ if (!is_iterative) {
+ visit_end_sequence_compat(v, "oldstate", VISIT_SEQ_COMPAT_BLOB,
+ &local_err);
+ }
+
+ LOCAL_ERR_REPORT(return -EINVAL;);
+
+ return ret;
}
- return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
+ ret = vmstate_load_state(v, se->vmsd, se->opaque, version_id);
+
+ return ret;
}
static int vmstate_save(Visitor *v, SaveStateEntry *se, int version_id)
@@ -837,57 +866,69 @@ int qemu_loadvm_state(QEMUFile *f)
QLIST_HEAD(, LoadStateEntry) loadvm_handlers =
QLIST_HEAD_INITIALIZER(loadvm_handlers);
LoadStateEntry *le, *new_le;
- uint8_t section_type;
- unsigned int v;
+ Error *local_err = NULL;
+ int32_t section_type;
+ unsigned int tmp;
int ret;
if (qemu_savevm_state_blocked(NULL)) {
return -EINVAL;
}
- v = qemu_get_be32(f);
- if (v != QEMU_VM_FILE_MAGIC) {
+ tmp = qemu_get_be32(f);
+ if (tmp != QEMU_VM_FILE_MAGIC) {
return -EINVAL;
}
- v = qemu_get_be32(f);
- if (v == QEMU_VM_FILE_VERSION_COMPAT) {
- fprintf(stderr, "SaveVM v2 format is obsolete and don't work
anymore\n");
+ tmp = qemu_get_be32(f);
+ if (tmp == QEMU_VM_FILE_VERSION_COMPAT) {
+ error_report("SaveVM v2 format is obsolete and don't work anymore");
return -ENOTSUP;
}
- if (v != QEMU_VM_FILE_VERSION) {
+ if (tmp != QEMU_VM_FILE_VERSION) {
return -ENOTSUP;
}
- while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
- uint32_t instance_id, version_id, section_id;
+ /* TODO: Here we should be able to figure out if it's a binary file
+ * or what and open the right type of visitor
+ */
+ QemuFileBinInputVisitor *qfbiv = qemu_file_bin_input_visitor_new(f);
+ Visitor *v = qemu_file_bin_input_get_visitor(qfbiv);
+ qemu_file_set_tmp_visitor(f, v);
+
+ visit_start_sequence_compat(v, "top", VISIT_SEQ_COMPAT_BYTE0TERM,
+ NULL, &local_err);
+ while (visit_get_next_type(v, §ion_type, NULL, "section", &local_err),
+ (!local_err && section_type != QEMU_VM_EOF)) {
SaveStateEntry *se;
- char idstr[257];
- int len;
+ SectionHeader sh;
switch (section_type) {
case QEMU_VM_SECTION_START:
case QEMU_VM_SECTION_FULL:
/* Read section start */
- section_id = qemu_get_be32(f);
- len = qemu_get_byte(f);
- qemu_get_buffer(f, (uint8_t *)idstr, len);
- idstr[len] = 0;
- instance_id = qemu_get_be32(f);
- version_id = qemu_get_be32(f);
+ visit_start_sequence_compat(v,
+ (section_type == QEMU_VM_SECTION_START) ?
+ "secstart" : "secfull",
+ VISIT_SEQ_COMPAT_SECTION_HEADER, &sh, &local_err);
+ if (local_err) {
+ ret = -EINVAL;
+ goto out;
+ }
/* Find savevm section */
- se = find_se(idstr, instance_id);
+ se = find_se(sh.idstr, sh.instance_id);
if (se == NULL) {
- fprintf(stderr, "Unknown savevm section or instance '%s'
%d\n", idstr, instance_id);
+ error_report("Unknown savevm section or instance '%s' %d",
+ sh.idstr, sh.instance_id);
ret = -EINVAL;
goto out;
}
/* Validate version */
- if (version_id > se->version_id) {
+ if (sh.version_id > se->version_id) {
fprintf(stderr, "savevm: unsupported version %d for '%s'
v%d\n",
- version_id, idstr, se->version_id);
+ sh.version_id, sh.idstr, se->version_id);
ret = -EINVAL;
goto out;
}
@@ -896,38 +937,51 @@ int qemu_loadvm_state(QEMUFile *f)
le = g_malloc0(sizeof(*le));
le->se = se;
- le->section_id = section_id;
- le->version_id = version_id;
+ le->section_id = sh.section_id;
+ le->version_id = sh.version_id;
QLIST_INSERT_HEAD(&loadvm_handlers, le, entry);
- ret = vmstate_load(f, le->se, le->version_id);
+ ret = vmstate_load(v, le->se, le->version_id);
if (ret < 0) {
- fprintf(stderr, "qemu: warning: error while loading state for
instance 0x%x of device '%s'\n",
- instance_id, idstr);
+ error_report("warning: error while loading state for instance "
+ "0x%x of device '%s'", sh.instance_id, sh.idstr);
goto out;
}
+ visit_end_sequence_compat(v,
+ (section_type == QEMU_VM_SECTION_START) ?
+ "secstart" : "secfull",
+ VISIT_SEQ_COMPAT_SECTION_HEADER, &local_err);
break;
case QEMU_VM_SECTION_PART:
case QEMU_VM_SECTION_END:
- section_id = qemu_get_be32(f);
+ visit_start_sequence_compat(v,
+ (section_type == QEMU_VM_SECTION_PART) ? "secpart" :
"secend",
+ VISIT_SEQ_COMPAT_SECTION_MIN, &sh, &local_err);
+ if (local_err) {
+ ret = -EINVAL;
+ goto out;
+ }
QLIST_FOREACH(le, &loadvm_handlers, entry) {
- if (le->section_id == section_id) {
+ if (le->section_id == sh.section_id) {
break;
}
}
if (le == NULL) {
- fprintf(stderr, "Unknown savevm section %d\n", section_id);
+ error_report("Unknown savevm section %d", sh.section_id);
ret = -EINVAL;
goto out;
}
- ret = vmstate_load(f, le->se, le->version_id);
+ ret = vmstate_load(v, le->se, le->version_id);
if (ret < 0) {
- fprintf(stderr, "qemu: warning: error while loading state
section id %d\n",
- section_id);
+ error_report("warning: error while loading state section id
%d",
+ sh.section_id);
goto out;
}
+ visit_end_sequence_compat(v,
+ (section_type == QEMU_VM_SECTION_PART) ? "secpart" :
"secend",
+ VISIT_SEQ_COMPAT_SECTION_MIN, &local_err);
break;
default:
fprintf(stderr, "Unknown savevm section type %d\n", section_type);
@@ -946,10 +1000,17 @@ out:
g_free(le);
}
+ visit_end_sequence_compat(v, "top", VISIT_SEQ_COMPAT_BYTE0TERM,
&local_err);
+ if (local_err) {
+ error_report("%s", error_get_pretty(local_err));
+ ret = -EINVAL;
+ }
+
if (ret == 0) {
ret = qemu_file_get_error(f);
}
+ qemu_file_bin_input_visitor_cleanup(qfbiv);
return ret;
}
diff --git a/vmstate.c b/vmstate.c
index 013e6b9..6b8855a 100644
--- a/vmstate.c
+++ b/vmstate.c
@@ -10,7 +10,7 @@
static void vmstate_subsection_save(Visitor *v, const VMStateDescription *vmsd,
void *opaque);
-static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+static int vmstate_subsection_load(Visitor *v, const VMStateDescription *vmsd,
void *opaque);
#define LOCAL_ERR_REPORT(fallout) \
@@ -20,11 +20,20 @@ static int vmstate_subsection_load(QEMUFile *f, const
VMStateDescription *vmsd,
fallout \
}
-int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+int vmstate_load_state(Visitor *v, const VMStateDescription *vmsd,
void *opaque, int version_id)
{
VMStateField *field = vmsd->fields;
int ret;
+ Error *local_err = NULL;
+ QEMUFile *wrapperf;
+ uint32_t tmp32;
+
+ /* BER type comes from the vmsd if it's set */
+ tmp32 = vmsd->ber_tag;
+ visit_start_sequence_compat(v, vmsd->name, VISIT_SEQ_COMPAT_VMSTATE,
+ &tmp32, &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
if (version_id > vmsd->version_id) {
return -EINVAL;
@@ -33,7 +42,18 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription
*vmsd,
return -EINVAL;
}
if (version_id < vmsd->minimum_version_id) {
- return vmsd->load_state_old(f, opaque, version_id);
+ /* Some visitors put old format things down separate QEMUFile's */
+ visit_start_sequence_compat(v, vmsd->name, VISIT_SEQ_COMPAT_BLOB,
+ &wrapperf, &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
+
+ ret = vmsd->load_state_old(visitor_get_qemufile(v), opaque,
version_id);
+
+ visit_end_sequence_compat(v, vmsd->name, VISIT_SEQ_COMPAT_BLOB,
+ &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
+
+ return ret;
}
if (vmsd->pre_load) {
int ret = vmsd->pre_load(opaque);
@@ -70,6 +90,11 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription
*vmsd,
if (field->flags & VMS_POINTER) {
base_addr = *(void **)base_addr + field->start;
}
+
+ if (n_elems > 1) {
+ visit_start_array(v, NULL, field->name, n_elems, 0,
&local_err);
+ }
+
for (i = 0; i < n_elems; i++) {
void *addr = base_addr + size * i;
@@ -77,31 +102,63 @@ int vmstate_load_state(QEMUFile *f, const
VMStateDescription *vmsd,
addr = *(void **)addr;
}
if (field->flags & VMS_STRUCT) {
- ret = vmstate_load_state(f, field->vmsd, addr,
+ ret = vmstate_load_state(v, field->vmsd, addr,
field->vmsd->version_id);
} else {
- ret = field->info->get(f, addr, size);
+ if (field->info->visit) {
+ ret = field->info->visit(v, addr, field->name, size,
+ &local_err);
+ } else {
+ /*
+ * Some visitors put old format things down separate
+ * QEMUFile's
+ */
+ visit_start_sequence_compat(v, field->name,
+ VISIT_SEQ_COMPAT_BLOB,
+ &wrapperf, &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
+ ret = field->info->get(wrapperf, addr, size);
+
+ visit_end_sequence_compat(v, field->name,
+ VISIT_SEQ_COMPAT_BLOB,
+ &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
+ }
}
if (ret < 0) {
trace_vmstate_load_field_error(field->name, ret);
return ret;
}
+
+ if ((i+1) != n_elems) {
+ visit_next_array(v, &local_err);
+ }
+ }
+
+ if (n_elems > 1) {
+ visit_end_array(v, &local_err);
}
+
}
field++;
}
- ret = vmstate_subsection_load(f, vmsd, opaque);
+ ret = vmstate_subsection_load(v, vmsd, opaque);
if (ret != 0) {
return ret;
}
if (vmsd->post_load) {
- return vmsd->post_load(opaque, version_id);
+ ret = vmsd->post_load(opaque, version_id);
}
- return 0;
+
+ visit_end_sequence_compat(v, vmsd->name, VISIT_SEQ_COMPAT_VMSTATE,
+ &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
+
+ return ret;
}
-void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+void vmstate_save_state(Visitor *v, const VMStateDescription *vmsd,
void *opaque)
{
VMStateField *field = vmsd->fields;
@@ -210,44 +267,56 @@ static const VMStateDescription *
return NULL;
}
-static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
+static int vmstate_subsection_load(Visitor *v, const VMStateDescription *vmsd,
void *opaque)
{
- while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
- char idstr[256];
+ Error *local_err = NULL;
+ int32_t section_type;
+
+ if (!vmsd->subsections) {
+ /*
+ * If the type has no subsection defined at all then skip completely
+ * Note that this means if we have conditional subsections we will
+ * expect a subseclist, even if it's empty because the conditions are
+ * all false.
+ */
+ return 0;
+ }
+
+ visit_start_sequence_compat(v, "subseclist", VISIT_SEQ_COMPAT_SUBSECLIST,
+ (char *)vmsd->name, &local_err);
+ while (visit_get_next_type(v, §ion_type, NULL, "subsec", &local_err),
+ ((local_err == NULL) && (section_type == QEMU_VM_SUBSECTION))) {
int ret;
- uint8_t version_id, len, size;
const VMStateDescription *sub_vmsd;
+ SectionHeader sh;
- len = qemu_peek_byte(f, 1);
- if (len < strlen(vmsd->name) + 1) {
- /* subsection name has be be "section_name/a" */
- return 0;
- }
- size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
- if (size != len) {
- return 0;
- }
- idstr[size] = 0;
+ visit_start_sequence_compat(v, "subsection",
+ VISIT_SEQ_COMPAT_SUBSECTION, &sh,
+ &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
- if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
- /* it don't have a valid subsection name */
- return 0;
- }
- sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
+ sub_vmsd = vmstate_subsection_name_lookup(vmsd->subsections, sh.idstr);
if (sub_vmsd == NULL) {
+ error_report("vmstate_subsection_load: failed to find subsection "
+ "%s in %s", sh.idstr, vmsd->name);
return -ENOENT;
}
- qemu_file_skip(f, 1); /* subsection */
- qemu_file_skip(f, 1); /* len */
- qemu_file_skip(f, len); /* idstr */
- version_id = qemu_get_be32(f);
- ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
+ ret = vmstate_load_state(v, sub_vmsd, opaque, sh.version_id);
if (ret) {
+ error_report("vmstate_subsection_load: load_state for %s failed "
+ "in %s", sh.idstr, vmsd->name);
return ret;
}
+ visit_end_sequence_compat(v, "subsection", VISIT_SEQ_COMPAT_SUBSECTION,
+ &local_err);
}
+ LOCAL_ERR_REPORT(return -EINVAL;);
+ visit_end_sequence_compat(v, "subseclist", VISIT_SEQ_COMPAT_SUBSECLIST,
+ &local_err);
+ LOCAL_ERR_REPORT(return -EINVAL;);
+
return 0;
}
--
1.9.0
- [Qemu-devel] [RFC PATCH v2 00/16] visitor+BER migration format, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 01/16] Visitor: Add methods for migration format use, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 02/16] QEMUSizedBuffer/QEMUFile, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 06/16] Visitor: Binary compatible output visitor, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 03/16] QEMUFilePart: A shim to read part of a file, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 05/16] Header/constant/types fixes for visitors, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 07/16] Visitor: Binary compatible input visitor, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 09/16] Visitor: Load path,
Dr. David Alan Gilbert (git) <=
- [Qemu-devel] [RFC PATCH v2 10/16] Visitor: Common types to use visitors, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 11/16] BER Visitor: Create output visitor, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 14/16] ASN.1 schema for new migration format, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 13/16] Start some BER format docs, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 16/16] Add vmstate_cpu_common BER type code and wire it in., Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 04/16] qemu-file: Add set/get tmp_visitor, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 08/16] Visitor: Output path, Dr. David Alan Gilbert (git), 2014/04/23
- [Qemu-devel] [RFC PATCH v2 12/16] BER Visitor: Create input visitor, Dr. David Alan Gilbert (git), 2014/04/23
- Re: [Qemu-devel] [RFC PATCH v2 00/16] visitor+BER migration format, Eric Blake, 2014/04/23