The vmstate infrastructure includes a VMS_MULTIPY flag, and associated VMSTATE_VBUFFER_MULTIPLY helper macro. These can be used to save a variably sized buffer where the size in bytes of the buffer isn't directly accessible as a structure field, but an element count from which the size can be derived is.
This patch adds an analogous VMS_DIVIDE option, which handles a variably sized buffer whose size is a submultiple of a field, rather than a multiple. For example a buffer containing per-page structures whose size is derived from a field storing the total address space described by the structures could use this construct. Signed-off-by: David Gibson <da...@gibson.dropbear.id.au> --- savevm.c | 8 ++++++++ vmstate.h | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/savevm.c b/savevm.c index 02e9da0..d830837 100644 --- a/savevm.c +++ b/savevm.c @@ -1460,6 +1460,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, if (field->flags & VMS_MULTIPLY) { size *= field->size; } + if (field->flags & VMS_DIVIDE) { + assert((size % field->size) == 0); + size /= field->size; + } } if (field->flags & VMS_ARRAY) { n_elems = field->num; @@ -1524,6 +1528,10 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, if (field->flags & VMS_MULTIPLY) { size *= field->size; } + if (field->flags & VMS_DIVIDE) { + assert((size % field->size) == 0); + size /= field->size; + } } if (field->flags & VMS_ARRAY) { n_elems = field->num; diff --git a/vmstate.h b/vmstate.h index 6bfdb6a..634dbde 100644 --- a/vmstate.h +++ b/vmstate.h @@ -82,6 +82,7 @@ enum VMStateFlags { VMS_MULTIPLY = 0x200, /* multiply "size" field by field_size */ VMS_VARRAY_UINT8 = 0x400, /* Array with size in uint8_t field*/ VMS_VARRAY_UINT32 = 0x800, /* Array with size in uint32_t field*/ + VMS_DIVIDE = 0x1000, /* divide "size" field by field_size */ }; typedef struct { @@ -384,6 +385,18 @@ extern const VMStateInfo vmstate_info_unused_buffer; .start = (_start), \ } +#define VMSTATE_VBUFFER_DIVIDE(_field, _state, _version, _test, _start, _field_size, _divide) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .field_exists = (_test), \ + .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\ + .size = (_divide), \ + .info = &vmstate_info_buffer, \ + .flags = VMS_VBUFFER|VMS_POINTER|VMS_DIVIDE, \ + .offset = offsetof(_state, _field), \ + .start = (_start), \ +} + #define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \ .name = (stringify(_field)), \ .version_id = (_version), \ -- 1.7.10.4