When VMS_ARRAY_OF_POINTER is specified, it means the vmstate field is an array of pointers.
The size of the element is not relevant to whatever it is stored inside: it is always the host pointer size. Let's reserve the "size" field in this case for future use, update vmstate_size() so as to make it still work for array of pointers properly. When at this, provide rich documentation on how size / size_offset works in vmstate. Signed-off-by: Peter Xu <[email protected]> --- include/migration/vmstate.h | 20 ++++++++++++++++---- migration/savevm.c | 3 +++ migration/vmstate.c | 10 +++++++++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 68fd954411..b4bc69486d 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -183,11 +183,26 @@ typedef enum { struct VMStateField { const char *name; size_t offset; + + /* + * @size or @size_offset specifies the size of the element embeded in + * the field. Only one of them should be present never both. When + * @size_offset is used together with VMS_VBUFFER, it means the size is + * dynamic calculated instead of a constant. + * + * When the field is an array of any type, this stores the size of one + * element of the array. + * + * NOTE: even if VMS_POINTER or VMS_ARRAY_OF_POINTER may be specified, + * this parameter always reflects the real size of the objects that a + * pointer point to. + */ size_t size; + size_t size_offset; + size_t start; int num; size_t num_offset; - size_t size_offset; const VMStateInfo *info; enum VMStateFlags flags; const VMStateDescription *vmsd; @@ -547,7 +562,6 @@ extern const VMStateInfo vmstate_info_qlist; .version_id = (_version), \ .num = (_num), \ .info = &(_info), \ - .size = sizeof(_type *), \ .flags = VMS_ARRAY|VMS_ARRAY_OF_POINTER, \ .offset = vmstate_offset_array(_state, _field, _type*, _num), \ } @@ -557,7 +571,6 @@ extern const VMStateInfo vmstate_info_qlist; .version_id = (_v), \ .num = (_n), \ .vmsd = &(_vmsd), \ - .size = sizeof(_type *), \ .flags = VMS_ARRAY|VMS_STRUCT|VMS_ARRAY_OF_POINTER, \ .offset = vmstate_offset_array(_s, _f, _type*, _n), \ } @@ -567,7 +580,6 @@ extern const VMStateInfo vmstate_info_qlist; .version_id = (_version), \ .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \ .info = &(_info), \ - .size = sizeof(_type *), \ .flags = VMS_VARRAY_UINT32 | VMS_ARRAY_OF_POINTER | VMS_POINTER, \ .offset = vmstate_offset_pointer(_state, _field, _type *), \ } diff --git a/migration/savevm.c b/migration/savevm.c index 8115203b51..f5a6fd0c66 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -868,6 +868,9 @@ static void vmstate_check(const VMStateDescription *vmsd) if (field) { while (field->name) { + if (field->flags & VMS_ARRAY_OF_POINTER) { + assert(field->size == 0); + } if (field->flags & (VMS_STRUCT | VMS_VSTRUCT)) { /* Recurse to sub structures */ vmstate_check(field->vmsd); diff --git a/migration/vmstate.c b/migration/vmstate.c index e98b5f5346..e29a8c3f49 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -110,13 +110,21 @@ static int vmstate_n_elems(void *opaque, const VMStateField *field) static int vmstate_size(void *opaque, const VMStateField *field) { - int size = field->size; + int size; if (field->flags & VMS_VBUFFER) { size = *(int32_t *)(opaque + field->size_offset); if (field->flags & VMS_MULTIPLY) { size *= field->size; } + } else if (field->flags & VMS_ARRAY_OF_POINTER) { + /* + * For an array of pointer, the each element is always size of a + * host pointer. + */ + size = sizeof(void *); + } else { + size = field->size; } return size; -- 2.50.1
