*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "migration.h"
#include "migration/vmstate.h"
-#include "migration/savevm.h"
+#include "savevm.h"
#include "qemu-file.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "trace.h"
#include "qjson.h"
-static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque, QJSON *vmdesc);
+static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, QJSON *vmdesc);
static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque);
-static int vmstate_n_elems(void *opaque, VMStateField *field)
+static int vmstate_n_elems(void *opaque, const VMStateField *field)
{
int n_elems = 1;
return n_elems;
}
-static int vmstate_size(void *opaque, VMStateField *field)
+static int vmstate_size(void *opaque, const VMStateField *field)
{
int size = field->size;
return size;
}
-static void vmstate_handle_alloc(void *ptr, VMStateField *field, void *opaque)
+static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
+ void *opaque)
{
if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
gsize size = vmstate_size(opaque, field);
int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque, int version_id)
{
- VMStateField *field = vmsd->fields;
+ const VMStateField *field = vmsd->fields;
int ret = 0;
trace_vmstate_load_state(vmsd->name, version_id);
} else if (field->flags & VMS_STRUCT) {
ret = vmstate_load_state(f, field->vmsd, curr_elem,
field->vmsd->version_id);
+ } else if (field->flags & VMS_VSTRUCT) {
+ ret = vmstate_load_state(f, field->vmsd, curr_elem,
+ field->struct_version_id);
} else {
ret = field->info->get(f, curr_elem, size, field);
}
return ret;
}
-static int vmfield_name_num(VMStateField *start, VMStateField *search)
+static int vmfield_name_num(const VMStateField *start,
+ const VMStateField *search)
{
- VMStateField *field;
+ const VMStateField *field;
int found = 0;
for (field = start; field->name; field++) {
return -1;
}
-static bool vmfield_name_is_unique(VMStateField *start, VMStateField *search)
+static bool vmfield_name_is_unique(const VMStateField *start,
+ const VMStateField *search)
{
- VMStateField *field;
+ const VMStateField *field;
int found = 0;
for (field = start; field->name; field++) {
return true;
}
-static const char *vmfield_get_type_name(VMStateField *field)
+static const char *vmfield_get_type_name(const VMStateField *field)
{
const char *type = "unknown";
if (field->flags & VMS_STRUCT) {
type = "struct";
+ } else if (field->flags & VMS_VSTRUCT) {
+ type = "vstruct";
} else if (field->info->name) {
type = field->info->name;
}
return type;
}
-static bool vmsd_can_compress(VMStateField *field)
+static bool vmsd_can_compress(const VMStateField *field)
{
if (field->field_exists) {
/* Dynamically existing fields mess up compression */
}
if (field->flags & VMS_STRUCT) {
- VMStateField *sfield = field->vmsd->fields;
+ const VMStateField *sfield = field->vmsd->fields;
while (sfield->name) {
if (!vmsd_can_compress(sfield)) {
/* Child elements can't compress, so can't we */
}
static void vmsd_desc_field_start(const VMStateDescription *vmsd, QJSON *vmdesc,
- VMStateField *field, int i, int max)
+ const VMStateField *field, int i, int max)
{
char *name, *old_name;
bool is_array = max > 1;
}
static void vmsd_desc_field_end(const VMStateDescription *vmsd, QJSON *vmdesc,
- VMStateField *field, size_t size, int i)
+ const VMStateField *field, size_t size, int i)
{
if (!vmdesc) {
return;
int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque, QJSON *vmdesc)
+ void *opaque, QJSON *vmdesc_id)
+{
+ return vmstate_save_state_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id);
+}
+
+int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, QJSON *vmdesc, int version_id)
{
int ret = 0;
- VMStateField *field = vmsd->fields;
+ const VMStateField *field = vmsd->fields;
trace_vmstate_save_state_top(vmsd->name);
if (vmdesc) {
json_prop_str(vmdesc, "vmsd_name", vmsd->name);
- json_prop_int(vmdesc, "version", vmsd->version_id);
+ json_prop_int(vmdesc, "version", version_id);
json_start_array(vmdesc, "fields");
}
while (field->name) {
- if (!field->field_exists ||
- field->field_exists(opaque, vmsd->version_id)) {
+ if ((field->field_exists &&
+ field->field_exists(opaque, version_id)) ||
+ (!field->field_exists &&
+ field->version_id <= version_id)) {
void *first_elem = opaque + field->offset;
int i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field);
}
for (i = 0; i < n_elems; i++) {
void *curr_elem = first_elem + size * i;
+ ret = 0;
vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
old_offset = qemu_ftell_fast(f);
if (!curr_elem && size) {
/* if null pointer write placeholder and do not follow */
assert(field->flags & VMS_ARRAY_OF_POINTER);
- vmstate_info_nullptr.put(f, curr_elem, size, NULL, NULL);
+ ret = vmstate_info_nullptr.put(f, curr_elem, size, NULL,
+ NULL);
} else if (field->flags & VMS_STRUCT) {
- vmstate_save_state(f, field->vmsd, curr_elem, vmdesc_loop);
+ ret = vmstate_save_state(f, field->vmsd, curr_elem,
+ vmdesc_loop);
+ } else if (field->flags & VMS_VSTRUCT) {
+ ret = vmstate_save_state_v(f, field->vmsd, curr_elem,
+ vmdesc_loop,
+ field->struct_version_id);
} else {
- field->info->put(f, curr_elem, size, field, vmdesc_loop);
+ ret = field->info->put(f, curr_elem, size, field,
+ vmdesc_loop);
+ }
+ if (ret) {
+ error_report("Save of field %s/%s failed",
+ vmsd->name, field->name);
+ if (vmsd->post_save) {
+ vmsd->post_save(opaque);
+ }
+ return ret;
}
written_bytes = qemu_ftell_fast(f) - old_offset;
json_end_array(vmdesc);
}
- vmstate_subsection_save(f, vmsd, opaque, vmdesc);
+ ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc);
- return 0;
+ if (vmsd->post_save) {
+ int ps_ret = vmsd->post_save(opaque);
+ if (!ret) {
+ ret = ps_ret;
+ }
+ }
+ return ret;
}
static const VMStateDescription *
vmstate_get_subsection(const VMStateDescription **sub, char *idstr)
{
- while (sub && *sub && (*sub)->needed) {
+ while (sub && *sub) {
if (strcmp(idstr, (*sub)->name) == 0) {
return *sub;
}
return 0;
}
-static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
- void *opaque, QJSON *vmdesc)
+static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, QJSON *vmdesc)
{
const VMStateDescription **sub = vmsd->subsections;
- bool subsection_found = false;
+ bool vmdesc_has_subsections = false;
+ int ret = 0;
trace_vmstate_subsection_save_top(vmsd->name);
- while (sub && *sub && (*sub)->needed) {
- if ((*sub)->needed(opaque)) {
+ while (sub && *sub) {
+ if (vmstate_save_needed(*sub, opaque)) {
const VMStateDescription *vmsdsub = *sub;
uint8_t len;
trace_vmstate_subsection_save_loop(vmsd->name, vmsdsub->name);
if (vmdesc) {
/* Only create subsection array when we have any */
- if (!subsection_found) {
+ if (!vmdesc_has_subsections) {
json_start_array(vmdesc, "subsections");
- subsection_found = true;
+ vmdesc_has_subsections = true;
}
json_start_object(vmdesc, NULL);
qemu_put_byte(f, len);
qemu_put_buffer(f, (uint8_t *)vmsdsub->name, len);
qemu_put_be32(f, vmsdsub->version_id);
- vmstate_save_state(f, vmsdsub, opaque, vmdesc);
+ ret = vmstate_save_state(f, vmsdsub, opaque, vmdesc);
+ if (ret) {
+ return ret;
+ }
if (vmdesc) {
json_end_object(vmdesc);
sub++;
}
- if (vmdesc && subsection_found) {
+ if (vmdesc_has_subsections) {
json_end_array(vmdesc);
}
+
+ return ret;
}