From patchwork Tue Mar 25 20:17:20 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Dr. David Alan Gilbert" X-Patchwork-Id: 333703 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 694A3140092 for ; Wed, 26 Mar 2014 07:32:44 +1100 (EST) Received: from localhost ([::1]:44027 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSXpl-0004ot-KR for incoming@patchwork.ozlabs.org; Tue, 25 Mar 2014 16:20:29 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46163) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSXnN-00023a-0v for qemu-devel@nongnu.org; Tue, 25 Mar 2014 16:18:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WSXnG-0008Hx-Pj for qemu-devel@nongnu.org; Tue, 25 Mar 2014 16:18:00 -0400 Received: from mx1.redhat.com ([209.132.183.28]:45405) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WSXnG-0008Hj-FO for qemu-devel@nongnu.org; Tue, 25 Mar 2014 16:17:54 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s2PKHoLd007170 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 25 Mar 2014 16:17:51 -0400 Received: from dgilbert-t530.home.treblig.org (vpn1-7-106.ams2.redhat.com [10.36.7.106]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s2PKHSSd029837; Tue, 25 Mar 2014 16:17:48 -0400 From: "Dr. David Alan Gilbert (git)" To: qemu-devel@nongnu.org Date: Tue, 25 Mar 2014 20:17:20 +0000 Message-Id: <1395778647-30925-10-git-send-email-dgilbert@redhat.com> In-Reply-To: <1395778647-30925-1-git-send-email-dgilbert@redhat.com> References: <1395778647-30925-1-git-send-email-dgilbert@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: stefanb@linux.vnet.ibm.com, quintela@redhat.com, mdroth@linux.vnet.ibm.com, agraf@suse.de, mst@redhat.com, aliguori@amazon.com, afaerber@suse.de Subject: [Qemu-devel] [RFC PATCH 09/16] Visitor: Load path X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: "Dr. David Alan Gilbert" Hacks in piix4.c, pci.c, spapr_vscsi.c for now Signed-off-by: Dr. David Alan Gilbert --- arch_init.c | 72 ++++++++++++++--------- 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, 251 insertions(+), 102 deletions(-) diff --git a/arch_init.c b/arch_init.c index 02bf78a..145666d 100644 --- a/arch_init.c +++ b/arch_init.c @@ -1004,15 +1004,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; @@ -1021,16 +1018,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; } @@ -1051,6 +1045,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++; @@ -1058,11 +1055,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) { @@ -1071,14 +1075,17 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) ram_addr_t length; ram_addr_t total_ram_bytes = addr; + visit_start_list(v, "blocklist", &local_err); 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))) { @@ -1103,6 +1110,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) total_ram_bytes -= length; } + LOCAL_ERR_REPORT(ret = -EINVAL; goto done;); + visit_end_list(v, &local_err); + LOCAL_ERR_REPORT(ret = -EINVAL; goto done;); } } @@ -1110,24 +1120,25 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) 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); + visit_type_uint8(v, &ch, "pagefill", &local_err); ram_handle_compressed(host, 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); } 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; } @@ -1144,7 +1155,12 @@ 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); + }; + 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 e91f729..2009c0f 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 8e799e2..c50a741 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 51efd4a..7431773 100644 --- a/savevm.c +++ b/savevm.c @@ -436,12 +436,41 @@ 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) { + 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) @@ -827,57 +856,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; } @@ -886,38 +927,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); @@ -936,10 +990,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 46bf7b9..af332b7 100644 --- a/vmstate.c +++ b/vmstate.c @@ -9,7 +9,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) \ @@ -19,11 +19,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; @@ -32,7 +41,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); @@ -69,6 +89,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; @@ -76,30 +101,62 @@ 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) { 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; @@ -208,44 +265,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; }