From: Alexander Mikhalitsyn <[email protected]> Add VMSTATE_VARRAY_OF_POINTER_TO_STRUCT_ALLOC, which helps to save/restore a dynamic array of pointers to structures.
Signed-off-by: Alexander Mikhalitsyn <[email protected]> --- include/migration/vmstate.h | 21 +++++++++ migration/vmstate-types.c | 88 +++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 89f9f49d20a..bc6495a7f67 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -265,6 +265,7 @@ extern const VMStateInfo vmstate_info_bitmap; extern const VMStateInfo vmstate_info_qtailq; extern const VMStateInfo vmstate_info_gtree; extern const VMStateInfo vmstate_info_qlist; +extern const VMStateInfo vmstate_info_ptrs_array_entry; #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0) /* @@ -537,6 +538,26 @@ extern const VMStateInfo vmstate_info_qlist; .offset = vmstate_offset_array(_s, _f, _type*, _n), \ } +/* + * For migrating a dynamically allocated uint32-indexed array + * of pointers to structures (with NULL entries and with auto memory allocation). + * + * _type: type of structure pointed to + * _vmsd: VMSD for structure + * start: size of structure pointed to (for auto memory allocation) + */ +#define VMSTATE_VARRAY_OF_POINTER_TO_STRUCT_ALLOC(_field, _state, _field_num, _version, _vmsd, _type) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \ + .info = &vmstate_info_ptrs_array_entry, \ + .vmsd = &(_vmsd), \ + .start = sizeof(_type), \ + .size = sizeof(_type *), \ + .flags = VMS_VARRAY_UINT32|VMS_POINTER, \ + .offset = vmstate_offset_pointer(_state, _field, _type *), \ +} + #define VMSTATE_VARRAY_OF_POINTER_UINT32(_field, _state, _field_num, _version, _info, _type) { \ .name = (stringify(_field)), \ .version_id = (_version), \ diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c index 89cb2114721..3335377cd07 100644 --- a/migration/vmstate-types.c +++ b/migration/vmstate-types.c @@ -942,3 +942,91 @@ const VMStateInfo vmstate_info_qlist = { .get = get_qlist, .put = put_qlist, }; + +static int put_ptrs_array_entry(QEMUFile *f, void *ppv, size_t unused_size, + const VMStateField *field, JSONWriter *vmdesc) +{ + const VMStateDescription *vmsd = field->vmsd; + int ret; + Error *local_err = NULL; + void *pv; + + /* + * (ppv) is an address of an i-th element of a dynamic array. + * + * (ppv) can not be NULL unless we have some regression/bug in + * vmstate_save_state_v(), because it is result of pointer arithemic like: + * first_elem + size * i. + */ + if (ppv == NULL) { + error_report("vmstate: put_ptrs_array_entry must be called with ppv != NULL"); + return -EINVAL; + } + + /* get a pointer to a structure */ + pv = *(void **)ppv; + + if (pv == NULL) { + /* write a mark telling that there was a NULL pointer */ + qemu_put_byte(f, false); + return 0; + } + + /* if pointer is not NULL, dump the structure contents with help of vmsd */ + qemu_put_byte(f, true); + ret = vmstate_save_state(f, vmsd, pv, vmdesc, &local_err); + if (ret) { + error_report_err(local_err); + return ret; + } + + return 0; +} + +static int get_ptrs_array_entry(QEMUFile *f, void *ppv, size_t unused_size, + const VMStateField *field) +{ + int ret = 0; + Error *local_err = NULL; + const VMStateDescription *vmsd = field->vmsd; + /* size of structure pointed to by elements of array */ + size_t size = field->start; + + if (ppv == NULL) { + error_report("vmstate: get_ptrs_array_entry must be called with ppv != NULL"); + return -EINVAL; + } + + /* + * We start from a clean array, all elements must be NULL, unless + * something we haven't prepared for has changed in vmstate_save_state_v(). + * Let's check for this just in case. + */ + if (*(void **)ppv != NULL) { + error_report("vmstate: get_ptrs_array_entry must be called with *ppv == NULL"); + return -EINVAL; + } + + if (qemu_get_byte(f)) { + void *pv; + + /* allocate memory for structure */ + pv = g_malloc0(size); + ret = vmstate_load_state(f, vmsd, pv, vmsd->version_id, &local_err); + if (ret) { + error_report_err(local_err); + g_free(pv); + return ret; + } + + *(void **)ppv = pv; + } + + return ret; +} + +const VMStateInfo vmstate_info_ptrs_array_entry = { + .name = "ptrs_array_entry", + .get = get_ptrs_array_entry, + .put = put_ptrs_array_entry, +}; -- 2.47.3
