Am Mi., 18. März 2026 um 00:23 Uhr schrieb Peter Xu <[email protected]>: > > 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]>
Reviewed-by: Alexander Mikhalitsyn <[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 >
