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
>

Reply via email to