static bool vmsd_can_compress(const VMStateField *field) { if (field->field_exists) { /* Dynamically existing fields mess up compression */ return false; } if (field->flags & VMS_STRUCT) { const VMStateField *sfield = field->vmsd->fields; while (sfield->name) { if (!vmsd_can_compress(sfield)) { /* Child elements can't compress, so can't we */ return false; } sfield++; } if (field->vmsd->subsections) { /* Subsections may come and go, better don't compress */ return false; } } return true; }
static void vmsd_desc_field_start(const VMStateDescription *vmsd, QJSON *vmdesc, const VMStateField *field, int i, int max) { char *name, *old_name; bool is_array = max > 1; bool can_compress = vmsd_can_compress(field); if (!vmdesc) { return; } name = g_strdup(field->name); /* Field name is not unique, need to make it unique */ if (!vmfield_name_is_unique(vmsd->fields, field)) { int num = vmfield_name_num(vmsd->fields, field); old_name = name; name = g_strdup_printf("%s[%d]", name, num); g_free(old_name); } json_start_object(vmdesc, NULL); json_prop_str(vmdesc, "name", name); if (is_array) { if (can_compress) { json_prop_int(vmdesc, "array_len", max); } else { json_prop_int(vmdesc, "index", i); } } json_prop_str(vmdesc, "type", vmfield_get_type_name(field)); if (field->flags & VMS_STRUCT) { json_start_object(vmdesc, "struct"); } g_free(name); }
int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, QJSON *vmdesc, int version_id) { int ret = 0; const VMStateField *field = vmsd->fields; trace_vmstate_save_state_top(vmsd->name); if (vmsd->pre_save) { ret = vmsd->pre_save(opaque); trace_vmstate_save_state_pre_save_res(vmsd->name, ret); if (ret) { error_report("pre-save failed: %s", vmsd->name); return ret; } } if (vmdesc) { json_prop_str(vmdesc, "vmsd_name", vmsd->name); json_prop_int(vmdesc, "version", version_id); json_start_array(vmdesc, "fields"); } while (field->name) { 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); int64_t old_offset, written_bytes; QJSON *vmdesc_loop = vmdesc; trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems); if (field->flags & VMS_POINTER) { first_elem = *(void **)first_elem; assert(first_elem || !n_elems || !size); } 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 (field->flags & VMS_ARRAY_OF_POINTER) { assert(curr_elem); curr_elem = *(void **)curr_elem; } if (!curr_elem && size) { /* if null pointer write placeholder and do not follow */ assert(field->flags & VMS_ARRAY_OF_POINTER); ret = vmstate_info_nullptr.put(f, curr_elem, size, NULL, NULL); } else if (field->flags & VMS_STRUCT) { 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 { 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; vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i); /* Compressed arrays only care about the first element */ if (vmdesc_loop && vmsd_can_compress(field)) { vmdesc_loop = NULL; } } } else { if (field->flags & VMS_MUST_EXIST) { error_report("Output state validation failed: %s/%s", vmsd->name, field->name); assert(!(field->flags & VMS_MUST_EXIST)); } } field++; } if (vmdesc) { json_end_array(vmdesc); } ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc); if (vmsd->post_save) { int ps_ret = vmsd->post_save(opaque); if (!ret) { ret = ps_ret; } } return ret; }
void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, QJSON *vmdesc) { VMStateField *field = vmsd->fields; trace_vmstate_save_state_top(vmsd->name); if (vmsd->pre_save) { vmsd->pre_save(opaque); } if (vmdesc) { json_prop_str(vmdesc, "vmsd_name", vmsd->name); json_prop_int(vmdesc, "version", vmsd->version_id); json_start_array(vmdesc, "fields"); } while (field->name) { if (!field->field_exists || field->field_exists(opaque, vmsd->version_id)) { void *base_addr = vmstate_base_addr(opaque, field, false); int i, n_elems = vmstate_n_elems(opaque, field); int size = vmstate_size(opaque, field); int64_t old_offset, written_bytes; QJSON *vmdesc_loop = vmdesc; trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems); for (i = 0; i < n_elems; i++) { void *addr = base_addr + size * i; vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems); old_offset = qemu_ftell_fast(f); if (field->flags & VMS_ARRAY_OF_POINTER) { addr = *(void **)addr; } if (field->flags & VMS_STRUCT) { vmstate_save_state(f, field->vmsd, addr, vmdesc_loop); } else { field->info->put(f, addr, size, field, vmdesc_loop); } written_bytes = qemu_ftell_fast(f) - old_offset; vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i); /* Compressed arrays only care about the first element */ if (vmdesc_loop && vmsd_can_compress(field)) { vmdesc_loop = NULL; } } } else { if (field->flags & VMS_MUST_EXIST) { error_report("Output state validation failed: %s/%s", vmsd->name, field->name); assert(!(field->flags & VMS_MUST_EXIST)); } } field++; } if (vmdesc) { json_end_array(vmdesc); } vmstate_subsection_save(f, vmsd, opaque, vmdesc); }