vmstate: Add a VSTRUCT type
The VMS_STRUCT has no way to specify which version of a structure to use. Add a type and a new field to allow the specific version of a structure to be used. Signed-off-by: Corey Minyard <cminyard@mvista.com> Message-Id: <1524670052-28373-2-git-send-email-minyard@acm.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
8f971cf0c9
commit
2dc6660bd8
@ -143,6 +143,11 @@ enum VMStateFlags {
|
|||||||
* to determine the number of entries in the array. Only valid in
|
* to determine the number of entries in the array. Only valid in
|
||||||
* combination with one of VMS_VARRAY*. */
|
* combination with one of VMS_VARRAY*. */
|
||||||
VMS_MULTIPLY_ELEMENTS = 0x4000,
|
VMS_MULTIPLY_ELEMENTS = 0x4000,
|
||||||
|
|
||||||
|
/* A structure field that is like VMS_STRUCT, but uses
|
||||||
|
* VMStateField.struct_version_id to tell which version of the
|
||||||
|
* structure we are referencing to use. */
|
||||||
|
VMS_VSTRUCT = 0x8000,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -167,6 +172,7 @@ struct VMStateField {
|
|||||||
enum VMStateFlags flags;
|
enum VMStateFlags flags;
|
||||||
const VMStateDescription *vmsd;
|
const VMStateDescription *vmsd;
|
||||||
int version_id;
|
int version_id;
|
||||||
|
int struct_version_id;
|
||||||
bool (*field_exists)(void *opaque, int version_id);
|
bool (*field_exists)(void *opaque, int version_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -248,6 +254,25 @@ extern const VMStateInfo vmstate_info_qtailq;
|
|||||||
vmstate_offset_array(_state, _field, uint8_t, \
|
vmstate_offset_array(_state, _field, uint8_t, \
|
||||||
sizeof(typeof_field(_state, _field)))
|
sizeof(typeof_field(_state, _field)))
|
||||||
|
|
||||||
|
/* In the macros below, if there is a _version, that means the macro's
|
||||||
|
* field will be processed only if the version being received is >=
|
||||||
|
* the _version specified. In general, if you add a new field, you
|
||||||
|
* would increment the structure's version and put that version
|
||||||
|
* number into the new field so it would only be processed with the
|
||||||
|
* new version.
|
||||||
|
*
|
||||||
|
* In particular, for VMSTATE_STRUCT() and friends the _version does
|
||||||
|
* *NOT* pick the version of the sub-structure. It works just as
|
||||||
|
* specified above. The version of the top-level structure received
|
||||||
|
* is passed down to all sub-structures. This means that the
|
||||||
|
* sub-structures must have version that are compatible with all the
|
||||||
|
* structures that use them.
|
||||||
|
*
|
||||||
|
* If you want to specify the version of the sub-structure, use
|
||||||
|
* VMSTATE_VSTRUCT(), which allows the specific sub-structure version
|
||||||
|
* to be directly specified.
|
||||||
|
*/
|
||||||
|
|
||||||
#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \
|
#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \
|
||||||
.name = (stringify(_field)), \
|
.name = (stringify(_field)), \
|
||||||
.version_id = (_version), \
|
.version_id = (_version), \
|
||||||
@ -395,6 +420,17 @@ extern const VMStateInfo vmstate_info_qtailq;
|
|||||||
.offset = offsetof(_state, _field), \
|
.offset = offsetof(_state, _field), \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VMSTATE_VSTRUCT_TEST(_field, _state, _test, _version, _vmsd, _type, _struct_version) { \
|
||||||
|
.name = (stringify(_field)), \
|
||||||
|
.version_id = (_version), \
|
||||||
|
.struct_version_id = (_struct_version), \
|
||||||
|
.field_exists = (_test), \
|
||||||
|
.vmsd = &(_vmsd), \
|
||||||
|
.size = sizeof(_type), \
|
||||||
|
.flags = VMS_VSTRUCT, \
|
||||||
|
.offset = vmstate_offset_value(_state, _field, _type), \
|
||||||
|
}
|
||||||
|
|
||||||
#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \
|
#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \
|
||||||
.name = (stringify(_field)), \
|
.name = (stringify(_field)), \
|
||||||
.version_id = (_version), \
|
.version_id = (_version), \
|
||||||
@ -712,6 +748,13 @@ extern const VMStateInfo vmstate_info_qtailq;
|
|||||||
#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \
|
#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \
|
||||||
VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
|
VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type)
|
||||||
|
|
||||||
|
#define VMSTATE_VSTRUCT(_field, _state, _vmsd, _type, _struct_version)\
|
||||||
|
VMSTATE_VSTRUCT_TEST(_field, _state, NULL, 0, _vmsd, _type, _struct_version)
|
||||||
|
|
||||||
|
#define VMSTATE_VSTRUCT_V(_field, _state, _version, _vmsd, _type, _struct_version) \
|
||||||
|
VMSTATE_VSTRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type, \
|
||||||
|
_struct_version)
|
||||||
|
|
||||||
#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \
|
#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \
|
||||||
VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
|
VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type)
|
||||||
|
|
||||||
@ -1000,6 +1043,8 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
|
|||||||
void *opaque, int version_id);
|
void *opaque, int version_id);
|
||||||
int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
|
int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
|
||||||
void *opaque, QJSON *vmdesc);
|
void *opaque, QJSON *vmdesc);
|
||||||
|
int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
|
||||||
|
void *opaque, QJSON *vmdesc, int version_id);
|
||||||
|
|
||||||
bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque);
|
bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque);
|
||||||
|
|
||||||
|
@ -136,6 +136,9 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
|
|||||||
} else if (field->flags & VMS_STRUCT) {
|
} else if (field->flags & VMS_STRUCT) {
|
||||||
ret = vmstate_load_state(f, field->vmsd, curr_elem,
|
ret = vmstate_load_state(f, field->vmsd, curr_elem,
|
||||||
field->vmsd->version_id);
|
field->vmsd->version_id);
|
||||||
|
} else if (field->flags & VMS_VSTRUCT) {
|
||||||
|
ret = vmstate_load_state(f, field->vmsd, curr_elem,
|
||||||
|
field->struct_version_id);
|
||||||
} else {
|
} else {
|
||||||
ret = field->info->get(f, curr_elem, size, field);
|
ret = field->info->get(f, curr_elem, size, field);
|
||||||
}
|
}
|
||||||
@ -209,6 +212,8 @@ static const char *vmfield_get_type_name(VMStateField *field)
|
|||||||
|
|
||||||
if (field->flags & VMS_STRUCT) {
|
if (field->flags & VMS_STRUCT) {
|
||||||
type = "struct";
|
type = "struct";
|
||||||
|
} else if (field->flags & VMS_VSTRUCT) {
|
||||||
|
type = "vstruct";
|
||||||
} else if (field->info->name) {
|
} else if (field->info->name) {
|
||||||
type = field->info->name;
|
type = field->info->name;
|
||||||
}
|
}
|
||||||
@ -309,7 +314,13 @@ bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque)
|
|||||||
|
|
||||||
|
|
||||||
int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
|
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;
|
int ret = 0;
|
||||||
VMStateField *field = vmsd->fields;
|
VMStateField *field = vmsd->fields;
|
||||||
@ -327,13 +338,15 @@ int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
|
|||||||
|
|
||||||
if (vmdesc) {
|
if (vmdesc) {
|
||||||
json_prop_str(vmdesc, "vmsd_name", vmsd->name);
|
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");
|
json_start_array(vmdesc, "fields");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (field->name) {
|
while (field->name) {
|
||||||
if (!field->field_exists ||
|
if ((field->field_exists &&
|
||||||
field->field_exists(opaque, vmsd->version_id)) {
|
field->field_exists(opaque, version_id)) ||
|
||||||
|
(!field->field_exists &&
|
||||||
|
field->version_id <= version_id)) {
|
||||||
void *first_elem = opaque + field->offset;
|
void *first_elem = opaque + field->offset;
|
||||||
int i, n_elems = vmstate_n_elems(opaque, field);
|
int i, n_elems = vmstate_n_elems(opaque, field);
|
||||||
int size = vmstate_size(opaque, field);
|
int size = vmstate_size(opaque, field);
|
||||||
@ -363,6 +376,10 @@ int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
|
|||||||
} else if (field->flags & VMS_STRUCT) {
|
} else if (field->flags & VMS_STRUCT) {
|
||||||
ret = vmstate_save_state(f, field->vmsd, curr_elem,
|
ret = vmstate_save_state(f, field->vmsd, curr_elem,
|
||||||
vmdesc_loop);
|
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 {
|
} else {
|
||||||
ret = field->info->put(f, curr_elem, size, field,
|
ret = field->info->put(f, curr_elem, size, field,
|
||||||
vmdesc_loop);
|
vmdesc_loop);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user