* [PATCH v2 1/8] migration: Remove unused vmstate macros
2026-08-18 18:24 [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Fabiano Rosas
@ 2026-08-18 18:24 ` Fabiano Rosas
2026-08-18 18:24 ` [PATCH v2 2/8] migration: Introduce VMStateStructMember Fabiano Rosas
` (7 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Fabiano Rosas @ 2026-08-18 18:24 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin
Remove the several vmstate macros that don't have any users.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
include/migration/vmstate.h | 45 -------------------------------------
1 file changed, 45 deletions(-)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 1b7f295417e..214a2131350 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -451,15 +451,6 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = vmstate_offset_sub_array(_state, _field, _type, _start), \
}
-#define VMSTATE_ARRAY_INT32_UNSAFE(_field, _state, _field_num, _info, _type) {\
- .name = (stringify(_field)), \
- .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
- .info = &(_info), \
- .size = sizeof(_type), \
- .flags = VMS_VARRAY_INT32, \
- .offset = vmstate_offset_varray(_state, _field, _type), \
-}
-
#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
.name = (stringify(_field)), \
.version_id = (_version), \
@@ -710,16 +701,6 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
-#define VMSTATE_STRUCT_VARRAY_INT32(_field, _state, _field_num, _version, _vmsd, _type) { \
- .name = (stringify(_field)), \
- .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
- .version_id = (_version), \
- .vmsd = &(_vmsd), \
- .size = sizeof(_type), \
- .flags = VMS_STRUCT|VMS_VARRAY_INT32, \
- .offset = vmstate_offset_varray(_state, _field, _type), \
-}
-
#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
.num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
@@ -1069,8 +1050,6 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#ifdef CONFIG_LINUX
-#define VMSTATE_U8(_f, _s) \
- VMSTATE_U8_V(_f, _s, 0)
#define VMSTATE_U16(_f, _s) \
VMSTATE_U16_V(_f, _s, 0)
#define VMSTATE_U32(_f, _s) \
@@ -1116,15 +1095,6 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_BOOL_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_bool, bool)
-#define VMSTATE_INT8_TEST(_f, _s, _t) \
- VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int8, int8_t)
-
-#define VMSTATE_INT16_TEST(_f, _s, _t) \
- VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int16, int16_t)
-
-#define VMSTATE_INT32_TEST(_f, _s, _t) \
- VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int32, int32_t)
-
#define VMSTATE_INT64_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_int64, int64_t)
@@ -1140,12 +1110,6 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_UINT64_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint64, uint64_t)
-#define VMSTATE_FD_TEST(_f, _s, _t) \
- VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_fd, int32_t)
-
-#define VMSTATE_TIMER_PTR_TEST(_f, _s, _test) \
- VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
-
#define VMSTATE_TIMER_PTR_V(_f, _s, _v) \
VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *)
@@ -1155,9 +1119,6 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_TIMER_PTR_ARRAY(_f, _s, _n) \
VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer)
-#define VMSTATE_TIMER_TEST(_f, _s, _test) \
- VMSTATE_SINGLE_TEST(_f, _s, _test, 0, vmstate_info_timer, QEMUTimer)
-
#define VMSTATE_TIMER_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, vmstate_info_timer, QEMUTimer)
@@ -1275,12 +1236,6 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \
VMSTATE_BUFFER_START_MIDDLE_V(_f, _s, _start, 0)
-#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \
- VMSTATE_VBUFFER(_f, _s, 0, NULL, _size)
-
-#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size) \
- VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, _size)
-
#define VMSTATE_BUFFER_TEST(_f, _s, _test) \
VMSTATE_STATIC_BUFFER(_f, _s, 0, _test, 0, sizeof(typeof_field(_s, _f)))
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 2/8] migration: Introduce VMStateStructMember
2026-08-18 18:24 [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Fabiano Rosas
2026-08-18 18:24 ` [PATCH v2 1/8] migration: Remove unused " Fabiano Rosas
@ 2026-08-18 18:24 ` Fabiano Rosas
2026-08-18 19:12 ` Peter Xu
2026-08-18 18:24 ` [PATCH v2 3/8] migration: Remove redundant flags Fabiano Rosas
` (6 subsequent siblings)
8 siblings, 1 reply; 11+ messages in thread
From: Fabiano Rosas @ 2026-08-18 18:24 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin, Seungjung Kim, Manos Pitsidianakis
When migrating a buffer or array, the vmstate code needs to know the
size of the buffer and the number of elements of the array. Today a
vmstate writer can choose from a number of macros that take as last
input the name of a struct member from where the size/num will be
read.
At load time, the code will access those values via an opaque pointer
to the migrated data and therefore it needs to also know the size of
the struct member at that offset.
Currently that information is communicated by means of the
VMS_VARRAY_* and VMS_VBUFFER_* flags, where each possible type is
represented by a flag.
So far, that's all fine, but since the vmstate code makes heavy use of
macros, handling several types individually (i.e. by name: int,
int32_t, etc) requires several versions of a same macro, one for each
type. E.g: VMSTATE_VBUFFER_ALLOC_UINT32
^
This creates a pattern where the vmstate writer has to match the macro
name to the data type and has resulted in the code having a tendency
of having one macro version for each type, for each type of vmstate.
There is also some cognitive load to deal with, e.g.
VMSTATE_VARRAY_INT32 doesn't hold an array of int32, it holds an array
of something else and the number of elements for the array is stored
in a variable of type int32.
We're now dealing with the scenario where the code has been expecting
int32_t at some places, but a uint64_t macro variant has been added
without the code being updated.
To address all these situations, introduce a new struct that will hold
the offset of the struct members, but also their size, so the various
extra macros can all be removed and the person writing the vmstate
doesn't need to care about type-checking. Still, keep a minimum check
that those fields are at least integers and fit into 64 bits.
What changes:
1) type checking changes from individual types to a single check for
all integers;
2) there are new ways to access the offsets;
num_offset -> num_indirect.offset
size_offset -> size_indirect.offset
[new] num_indirect.size
[new] size_indirect.size
2) reading the offsets goes from checking the VMS_VARRAY_* flags in an
if/elseif block to comparing offset.size against the hardcoded
sizes in bytes;
3) the VMS_VARRAY_* and VMS_VBUFFER_* flags become obsolete. Removed
in the next patch;
4) memory usage increases +1 byte per vmstate;
Reported-by: Seungjung Kim <seungjung0711@gmail.com>
Fixes: CVE-2026-6426
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
include/migration/vmstate.h | 163 +++++++++++++++++++++--------
migration/savevm.c | 4 +-
migration/vmstate.c | 50 +++++----
rust/bindings/migration-sys/lib.rs | 10 ++
rust/migration/src/vmstate.rs | 24 ++++-
rust/tests/tests/vmstate_tests.rs | 26 ++---
6 files changed, 197 insertions(+), 80 deletions(-)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 214a2131350..12bfa64fb92 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -31,6 +31,7 @@
typedef struct VMStateInfo VMStateInfo;
typedef struct VMStateField VMStateField;
+typedef struct VMStateStructMember VMStateStructMember;
/*
* VMStateInfo allows customized migration of objects that don't fit in
@@ -67,15 +68,15 @@ enum VMStateFlags {
* to the actual field (e.g. struct a { uint8_t *b;
* }). Dereference the pointer before using it as basis for
* further pointer arithmetic (see e.g. VMS_ARRAY). Does not
- * affect the meaning of VMStateField.num_offset or
- * VMStateField.size_offset; see VMS_VARRAY* and VMS_VBUFFER for
+ * affect the meaning of VMStateField.num_indirect or
+ * VMStateField.size_indirect; see VMS_VARRAY* and VMS_VBUFFER for
* those. */
VMS_POINTER = 0x002,
/* The field is an array of fixed size. VMStateField.num contains
* the number of entries in the array. The size of each entry is
* given by VMStateField.size and / or opaque +
- * VMStateField.size_offset; see VMS_VBUFFER and
+ * VMStateField.size_indirect; see VMS_VBUFFER and
* VMS_MULTIPLY. Each array entry will be processed individually
* (VMStateField.info.get()/put() if VMS_STRUCT is not set,
* recursion into VMStateField.vmsd if VMS_STRUCT is set). May not
@@ -88,8 +89,9 @@ enum VMStateFlags {
* array entry. */
VMS_STRUCT = 0x008,
- /* The field is an array of variable size. The int32_t at opaque +
- * VMStateField.num_offset contains the number of entries in the
+ /*
+ * The field is an array of variable size. The integer at opaque +
+ * VMStateField.num_indirect contains the number of entries in the
* array. See the VMS_ARRAY description regarding array handling
* in general. May not be combined with VMS_ARRAY or any other
* VMS_VARRAY*. */
@@ -105,7 +107,7 @@ enum VMStateFlags {
VMS_ARRAY_OF_POINTER = 0x040,
/* The field is an array of variable size. The uint16_t at opaque
- * + VMStateField.num_offset
+ * + VMStateField.num_indirect
* contains the number of entries in the array. See the VMS_ARRAY
* description regarding array handling in general. May not be
* combined with VMS_ARRAY or any other VMS_VARRAY*. */
@@ -114,26 +116,27 @@ enum VMStateFlags {
/* The size of the individual entries (a single array entry if
* VMS_ARRAY or any of VMS_VARRAY* are set, or the field itself if
* neither is set) is variable (i.e. not known at compile-time),
- * but the same for all entries. Use the int32_t at opaque +
- * VMStateField.size_offset (subject to VMS_MULTIPLY) to determine
+ * but the same for all entries. Use the integer at opaque +
+ * VMStateField.size_indirect (subject to VMS_MULTIPLY) to determine
* the size of each (and every) entry. */
VMS_VBUFFER = 0x100,
- /* Multiply the entry size given by the int32_t at opaque +
- * VMStateField.size_offset (see VMS_VBUFFER description) with
+ /*
+ * Multiply the entry size given by the integer at opaque +
+ * VMStateField.size_indirect (see VMS_VBUFFER description) with
* VMStateField.size to determine the number of bytes to be
* allocated. Only valid in combination with VMS_VBUFFER. */
VMS_MULTIPLY = 0x200,
/* The field is an array of variable size. The uint8_t at opaque +
- * VMStateField.num_offset
+ * VMStateField.num_indirect
* contains the number of entries in the array. See the VMS_ARRAY
* description regarding array handling in general. May not be
* combined with VMS_ARRAY or any other VMS_VARRAY*. */
VMS_VARRAY_UINT8 = 0x400,
/* The field is an array of variable size. The uint32_t at opaque
- * + VMStateField.num_offset
+ * + VMStateField.num_indirect
* contains the number of entries in the array. See the VMS_ARRAY
* description regarding array handling in general. May not be
* combined with VMS_ARRAY or any other VMS_VARRAY*. */
@@ -187,29 +190,88 @@ typedef enum {
MIG_PRI_MAX,
} MigrationPriority;
+
+/*
+ * VMStateStructMember: Metadata about a single member of the struct
+ * being migrated by the vmstate. This is kept separate from
+ * VMStateField because a single VMStateField can reference other
+ * members of the struct aside from the main struct member that's
+ * being migrated.
+ *
+ * One situation where extra fields are referenced is the common case
+ * of a struct containing an array or buffer, the size of which is
+ * stored in another member of the same struct.
+ *
+ * Example 1:
+ * struct IDEState {
+ * ...
+ * uint8_t *io_buffer;
+ * int32_t io_buffer_total_len;
+ * ...
+ * }
+ * VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
+ * vmstate_info_uint8, uint8_t)
+ *
+ * In the above, io_buffer is the main field being migrated by the
+ * VMSTATE_VARRAY while io_buffer_total_len is the meta field that
+ * provides the size of the io_buffer. In this particular case,
+ * io_buffer_total_len is never migrated.
+ *
+ * Example 2:
+ * struct SpaprMachineState {
+ * ...
+ * uint32_t fdt_size;
+ * void *fdt_blob;
+ * ...
+ * }
+ * VMSTATE_UINT32(fdt_size, SpaprMachineState),
+ * VMSTATE_VBUFFER_ALLOC_UINT32(fdt_blob, SpaprMachineState, 0, NULL, fdt_size),
+ *
+ * Here, fdt_blob is the field being migrated by VMSTATE_VBUFFER_ALLOC
+ * and fdt_size is the meta field providing the size. In this case,
+ * the extra field is also independently migrated by the
+ * VMSTATE_UINT32 above.
+ */
+struct VMStateStructMember {
+ /* offsetof the field inside the migrated struct */
+ uint32_t offset;
+ /* size of field itself */
+ uint8_t size;
+};
+
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.
+ * @size directly specifies the size of the element being
+ * migrated.
*
- * When the field is an array of any type, this stores the size of one
- * element of the array.
+ * @size_indirect specifies the offset inside a struct where the
+ * size of the element is stored.
*
- * 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.
+ * Only one of the above should be present (except for
+ * VMSTATE_MULTIPLY which uses .size as a multiplier). When
+ * @size_indirect 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, these refer to the size
+ * of one element of the array.
+ *
+ * NOTE: even if VMS_POINTER or VMS_ARRAY_OF_POINTER may be
+ * specified, these parameters always reflect the real size of the
+ * objects that a pointer point to.
+ *
+ * @num_indirect specifies the offset inside a struct where the
+ * number of elements of an array is stored.
*/
size_t size;
- size_t size_offset;
+ VMStateStructMember size_indirect;
+ VMStateStructMember num_indirect;
size_t start;
int num;
- size_t num_offset;
+
const VMStateInfo *info;
enum VMStateFlags flags;
const VMStateDescription *vmsd;
@@ -328,6 +390,17 @@ extern const VMStateInfo vmstate_info_g_byte_array;
(type_check(t1, typeof_elt_of_field(t2, f)) \
+ QEMU_BUILD_BUG_ON_ZERO(!QEMU_IS_ARRAY(((t2 *)0)->f)))
+#define type_check_int64(t) \
+ (~((t)0) * sizeof(struct { \
+ QEMU_BUILD_BUG_ON(sizeof(t) > sizeof(uint64_t)); \
+ }))
+
+#define vmstate_field_offset(_state, _field) { \
+ .offset = (offsetof(_state, _field) + \
+ type_check_int64(typeof_field(_state, _field))), \
+ .size = sizeof(typeof_field(_state, _field)), \
+}
+
#define vmstate_offset_value(_state, _field, _type) \
(offsetof(_state, _field) + \
type_check(_type, typeof_field(_state, _field)))
@@ -454,7 +527,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
.name = (stringify(_field)), \
.version_id = (_version), \
- .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_INT32|VMS_POINTER, \
@@ -464,7 +537,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_VARRAY_UINT32(_field, _state, _field_num, _version, _info, _type) {\
.name = (stringify(_field)), \
.version_id = (_version), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_UINT32|VMS_POINTER, \
@@ -474,7 +547,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_VARRAY_INT32_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
.name = (stringify(_field)), \
.version_id = (_version), \
- .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_INT32 | VMS_POINTER | VMS_ALLOC, \
@@ -484,7 +557,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_VARRAY_UINT32_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
.name = (stringify(_field)), \
.version_id = (_version), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_UINT32|VMS_POINTER|VMS_ALLOC, \
@@ -494,7 +567,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_VARRAY_UINT16_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
.name = (stringify(_field)), \
.version_id = (_version), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_UINT16 | VMS_POINTER | VMS_ALLOC, \
@@ -504,7 +577,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
.name = (stringify(_field)), \
.version_id = (_version), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
.flags = VMS_VARRAY_UINT16, \
@@ -583,7 +656,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
_field, _state, _field_num, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
.flags = VMS_POINTER | VMS_VARRAY_UINT8 | \
@@ -596,7 +669,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
_field, _state, _field_num, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
.flags = VMS_POINTER | VMS_VARRAY_UINT32 | \
@@ -608,7 +681,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_VARRAY_OF_POINTER_UINT32(_field, _state, _field_num, _version, _info, _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.flags = VMS_VARRAY_UINT32 | VMS_ARRAY_OF_POINTER | VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, _type *), \
@@ -650,7 +723,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.version_id = (_version), \
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
@@ -674,7 +747,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_STRUCT_VARRAY_POINTER_INT32(_field, _state, _field_num, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = 0, \
- .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.size = sizeof(_type), \
.vmsd = &(_vmsd), \
.flags = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT, \
@@ -684,7 +757,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_STRUCT_VARRAY_POINTER_UINT32(_field, _state, _field_num, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = 0, \
- .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.size = sizeof(_type), \
.vmsd = &(_vmsd), \
.flags = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT, \
@@ -694,7 +767,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = 0, \
- .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.size = sizeof(_type), \
.vmsd = &(_vmsd), \
.flags = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT, \
@@ -703,7 +776,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.version_id = (_version), \
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
@@ -715,7 +788,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.name = (stringify(_field)), \
.version_id = (_version), \
.vmsd = &(_vmsd), \
- .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.size = sizeof(_type), \
.flags = VMS_STRUCT|VMS_VARRAY_INT32|VMS_ALLOC|VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
@@ -736,7 +809,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.name = (stringify(_field)), \
.version_id = (_version), \
.field_exists = (_test), \
- .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
+ .size_indirect = vmstate_field_offset(_state, _field_size), \
.size = (_multiply), \
.info = &vmstate_info_buffer, \
.flags = VMS_VBUFFER|VMS_POINTER|VMS_MULTIPLY, \
@@ -747,7 +820,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.name = (stringify(_field)), \
.version_id = (_version), \
.field_exists = (_test), \
- .size_offset = vmstate_offset_value(_state, _field_size, int32_t),\
+ .size_indirect = vmstate_field_offset(_state, _field_size), \
.info = &vmstate_info_buffer, \
.flags = VMS_VBUFFER|VMS_POINTER, \
.offset = offsetof(_state, _field), \
@@ -757,7 +830,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.name = (stringify(_field)), \
.version_id = (_version), \
.field_exists = (_test), \
- .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
+ .size_indirect = vmstate_field_offset(_state, _field_size), \
.info = &vmstate_info_buffer, \
.flags = VMS_VBUFFER|VMS_POINTER, \
.offset = offsetof(_state, _field), \
@@ -767,7 +840,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.name = (stringify(_field)), \
.version_id = (_version), \
.field_exists = (_test), \
- .size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
+ .size_indirect = vmstate_field_offset(_state, _field_size), \
.info = &vmstate_info_buffer, \
.flags = VMS_VBUFFER | VMS_POINTER, \
.offset = offsetof(_state, _field), \
@@ -778,7 +851,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.name = (stringify(_field)), \
.version_id = (_version), \
.field_exists = (_test), \
- .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
+ .size_indirect = vmstate_field_offset(_state, _field_size), \
.info = &vmstate_info_buffer, \
.flags = VMS_VBUFFER|VMS_POINTER|VMS_ALLOC, \
.offset = offsetof(_state, _field), \
@@ -838,7 +911,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_UNUSED_VARRAY_UINT32(_state, _test, _version, _field_num, _size) {\
.name = "unused", \
.field_exists = (_test), \
- .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+ .num_indirect = vmstate_field_offset(_state, _field_num), \
.version_id = (_version), \
.size = (_size), \
.info = &vmstate_info_unused_buffer, \
@@ -852,7 +925,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.name = (stringify(_field)), \
.field_exists = (_test), \
.version_id = (_version), \
- .size_offset = vmstate_offset_value(_state, _field_size, int32_t),\
+ .size_indirect = vmstate_field_offset(_state, _field_size), \
.info = &vmstate_info_bitmap, \
.flags = VMS_VBUFFER|VMS_POINTER, \
.offset = offsetof(_state, _field), \
diff --git a/migration/savevm.c b/migration/savevm.c
index 34dd06f9f73..e1b707dda63 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -873,14 +873,14 @@ static void vmstate_check(const VMStateDescription *vmsd)
* Size must be provided because dest QEMU needs that
* info to know what to allocate
*/
- assert(field->size || field->size_offset);
+ assert(field->size != 0 || field->size_indirect.size != 0);
} else {
/*
* Otherwise size info isn't useful (because it's
* always the size of host pointer), detect accidental
* setup of sizes in this case.
*/
- assert(field->size == 0 && field->size_offset == 0);
+ assert(field->size == 0 && field->size_indirect.size == 0);
}
/*
* VMS_ARRAY_OF_POINTER must be used only together with one
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 50ebe378452..372aed258f1 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -78,32 +78,44 @@ vmsd_init_ptr_marker_field(VMStateField *fake, const VMStateField *field)
};
}
-static int vmstate_n_elems(void *opaque, const VMStateField *field)
+static uint64_t vmstate_read_from_offset(const VMStateStructMember *member,
+ void *opaque)
{
- int n_elems = 1;
+ uint8_t *ptr = (uint8_t *)opaque + member->offset;
+ uint64_t v = 0;
+
+ switch (member->size) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ memcpy(&v, ptr, member->size);
+ return v;
+ }
+ g_assert_not_reached();
+}
+
+static uint64_t vmstate_n_elems(void *opaque, const VMStateField *field)
+{
+ uint64_t n_elems = 1;
if (field->flags & VMS_ARRAY) {
n_elems = field->num;
- } else if (field->flags & VMS_VARRAY_INT32) {
- n_elems = *(int32_t *)(opaque + field->num_offset);
- } else if (field->flags & VMS_VARRAY_UINT32) {
- n_elems = *(uint32_t *)(opaque + field->num_offset);
- } else if (field->flags & VMS_VARRAY_UINT16) {
- n_elems = *(uint16_t *)(opaque + field->num_offset);
- } else if (field->flags & VMS_VARRAY_UINT8) {
- n_elems = *(uint8_t *)(opaque + field->num_offset);
+ } else if (field->flags & (VMS_VARRAY_INT32 | VMS_VARRAY_UINT32
+ | VMS_VARRAY_UINT16 | VMS_VARRAY_UINT8)) {
+ n_elems = vmstate_read_from_offset(&field->num_indirect, opaque);
}
trace_vmstate_n_elems(field->name, n_elems);
return n_elems;
}
-static int vmstate_size(void *opaque, const VMStateField *field)
+static uint64_t vmstate_size(void *opaque, const VMStateField *field)
{
- int size;
+ uint64_t size;
if (field->flags & VMS_VBUFFER) {
- size = *(int32_t *)(opaque + field->size_offset);
+ size = vmstate_read_from_offset(&field->size_indirect, opaque);
if (field->flags & VMS_MULTIPLY) {
size *= field->size;
}
@@ -124,7 +136,7 @@ static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
void *opaque)
{
if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
- gsize size = vmstate_size(opaque, field);
+ uint64_t size = vmstate_size(opaque, field);
size *= vmstate_n_elems(opaque, field);
if (size) {
*(void **)ptr = g_malloc(size);
@@ -335,8 +347,9 @@ bool vmstate_load_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
if (exists) {
void *first_elem = opaque + field->offset;
- int i, n_elems = vmstate_n_elems(opaque, field);
- int size = vmstate_size(opaque, field);
+ int i;
+ uint64_t n_elems = vmstate_n_elems(opaque, field);
+ uint64_t size = vmstate_size(opaque, field);
vmstate_handle_alloc(first_elem, field, opaque);
if (field->flags & VMS_POINTER) {
@@ -650,8 +663,9 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd,
while (field->name) {
if (vmstate_field_exists(vmsd, field, opaque, version_id)) {
void *first_elem = opaque + field->offset;
- int i, n_elems = vmstate_n_elems(opaque, field);
- int size = vmstate_size(opaque, field);
+ int i;
+ uint64_t n_elems = vmstate_n_elems(opaque, field);
+ uint64_t size = vmstate_size(opaque, field);
JSONWriter *vmdesc_loop = vmdesc;
bool is_prev_null = false;
/*
diff --git a/rust/bindings/migration-sys/lib.rs b/rust/bindings/migration-sys/lib.rs
index 9581481e421..baa2730ca9d 100644
--- a/rust/bindings/migration-sys/lib.rs
+++ b/rust/bindings/migration-sys/lib.rs
@@ -47,6 +47,7 @@ fn default() -> Self {
unsafe impl Zeroable for VMStateFlags {}
unsafe impl Zeroable for VMStateField {}
unsafe impl Zeroable for VMStateDescription {}
+unsafe impl Zeroable for VMStateStructMember {}
// The following higher-level helpers could be in "migration"
// crate when Rust has const trait impl.
@@ -115,3 +116,12 @@ pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> Self {
self.with_varray_flag_unchecked(flag)
}
}
+
+impl VMStateStructMember {
+ pub const fn new(off: usize, size: usize) -> Self {
+ Self {
+ offset: off as u32,
+ size: size as u8,
+ }
+ }
+}
diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs
index 63d78b4f275..e60c0860cc5 100644
--- a/rust/migration/src/vmstate.rs
+++ b/rust/migration/src/vmstate.rs
@@ -42,7 +42,7 @@
};
use crate::bindings::{self, VMStateFlags};
-pub use crate::bindings::{MigrationPriority, VMStateField};
+pub use crate::bindings::{MigrationPriority, VMStateField, VMStateStructMember};
/// This macro is used to call a function with a generic argument bound
/// to the type of a field. The function must take a
@@ -120,6 +120,23 @@ pub const fn vmstate_varray_flag<T: VMState>(_: PhantomData<T>) -> VMStateFlags
T::VARRAY_FLAG
}
+pub const OPAQUE: &[u8; 1048576] = &[0; 1048576];
+
+pub const fn size_of_ptr_type<T>(_: *const T) -> usize {
+ ::core::mem::size_of::<T>()
+}
+
+#[macro_export]
+macro_rules! size_of_field_type {
+ ($struct_name:ty, $($field_name:ident).+) => {
+ $crate::vmstate::size_of_ptr_type(unsafe {
+ ::core::ptr::addr_of!(
+ (*$crate::vmstate::OPAQUE.as_ptr().cast::<$struct_name>()).$($field_name).+
+ )
+ })
+ };
+}
+
/// Return the `VMStateField` for a field of a struct. The field must be
/// visible in the current scope.
///
@@ -148,7 +165,10 @@ macro_rules! vmstate_of {
.as_bytes()
.as_ptr().cast::<::std::os::raw::c_char>(),
offset: ::std::mem::offset_of!($struct_name, $($field_name).+),
- $(num_offset: ::std::mem::offset_of!($struct_name, $($num).+),)?
+ $(num_indirect: $crate::vmstate::VMStateStructMember {
+ offset: ::std::mem::offset_of!($struct_name, $($num).+) as u32,
+ size: $crate::size_of_field_type!($struct_name, $($num).+) as u8,
+ },)?
$(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)?
// The calls to `call_func_with_field!` are the magic that
// computes most of the VMStateField from the type of the field.
diff --git a/rust/tests/tests/vmstate_tests.rs b/rust/tests/tests/vmstate_tests.rs
index c2c12cfab52..c002ffb2bc4 100644
--- a/rust/tests/tests/vmstate_tests.rs
+++ b/rust/tests/tests/vmstate_tests.rs
@@ -65,7 +65,7 @@ fn test_vmstate_uint16() {
b"elem\0"
);
assert_eq!(foo_fields[0].offset, 16);
- assert_eq!(foo_fields[0].num_offset, 0);
+ assert_eq!(foo_fields[0].num_indirect.size, 0);
assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int8 });
assert_eq!(foo_fields[0].version_id, 0);
assert_eq!(foo_fields[0].size, 1);
@@ -86,7 +86,7 @@ fn test_vmstate_unused() {
b"unused\0"
);
assert_eq!(foo_fields[1].offset, 0);
- assert_eq!(foo_fields[1].num_offset, 0);
+ assert_eq!(foo_fields[1].num_indirect.size, 0);
assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_unused_buffer });
assert_eq!(foo_fields[1].version_id, 0);
assert_eq!(foo_fields[1].size, 8);
@@ -108,7 +108,7 @@ fn test_vmstate_varray_uint16_unsafe() {
b"arr\0"
);
assert_eq!(foo_fields[2].offset, 0);
- assert_eq!(foo_fields[2].num_offset, 4);
+ assert_eq!(foo_fields[2].num_indirect.offset, 4);
assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
assert_eq!(foo_fields[2].version_id, 0);
assert_eq!(foo_fields[2].size, 1);
@@ -172,7 +172,7 @@ fn test_vmstate_bool_v() {
b"val\0"
);
assert_eq!(foo_fields[0].offset, 136);
- assert_eq!(foo_fields[0].num_offset, 0);
+ assert_eq!(foo_fields[0].num_indirect.size, 0);
assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_bool });
assert_eq!(foo_fields[0].version_id, 2);
assert_eq!(foo_fields[0].size, 1);
@@ -193,7 +193,7 @@ fn test_vmstate_uint64() {
b"wrap\0"
);
assert_eq!(foo_fields[1].offset, 128);
- assert_eq!(foo_fields[1].num_offset, 0);
+ assert_eq!(foo_fields[1].num_indirect.size, 0);
assert_eq!(foo_fields[1].info, unsafe { &vmstate_info_uint64 });
assert_eq!(foo_fields[1].version_id, 0);
assert_eq!(foo_fields[1].size, 8);
@@ -215,7 +215,7 @@ fn test_vmstate_struct_varray_uint8() {
b"arr_a\0"
);
assert_eq!(foo_fields[2].offset, 0);
- assert_eq!(foo_fields[2].num_offset, 60);
+ assert_eq!(foo_fields[2].num_indirect.offset, 60);
assert!(foo_fields[2].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field.
assert_eq!(foo_fields[2].version_id, 1);
assert_eq!(foo_fields[2].size, 20);
@@ -240,7 +240,7 @@ fn test_vmstate_macro_array() {
b"arr_i64\0"
);
assert_eq!(foo_fields[4].offset, 144);
- assert_eq!(foo_fields[4].num_offset, 0);
+ assert_eq!(foo_fields[4].num_indirect.size, 0);
assert_eq!(foo_fields[4].info, unsafe { &vmstate_info_int64 });
assert_eq!(foo_fields[4].version_id, 0);
assert_eq!(foo_fields[4].size, 8);
@@ -264,7 +264,7 @@ fn test_vmstate_struct_varray_uint8_wrapper() {
unsafe { CStr::from_ptr(foo_fields[5].name) }.to_bytes_with_nul(),
b"arr_a_wrap\0"
);
- assert_eq!(foo_fields[5].num_offset, 228);
+ assert_eq!(foo_fields[5].num_indirect.offset, 228);
assert!(unsafe { foo_fields[5].field_exists.unwrap()(foo_b_p, 0) });
// The last VMStateField in VMSTATE_FOOB.
@@ -316,7 +316,7 @@ fn test_vmstate_pointer() {
b"ptr\0"
);
assert_eq!(foo_fields[0].offset, 0);
- assert_eq!(foo_fields[0].num_offset, 0);
+ assert_eq!(foo_fields[0].num_indirect.size, 0);
assert_eq!(foo_fields[0].info, unsafe { &vmstate_info_int32 });
assert_eq!(foo_fields[0].version_id, 2);
assert_eq!(foo_fields[0].size, 4);
@@ -341,7 +341,7 @@ fn test_vmstate_struct_pointer() {
b"ptr_a\0"
);
assert_eq!(foo_fields[1].offset, PTR_SIZE);
- assert_eq!(foo_fields[1].num_offset, 0);
+ assert_eq!(foo_fields[1].num_indirect.size, 0);
assert_eq!(foo_fields[1].vmsd, VMSTATE_FOOA.as_ref());
assert_eq!(foo_fields[1].version_id, 0);
assert_eq!(foo_fields[1].size, size_of::<FooA>());
@@ -366,7 +366,7 @@ fn test_vmstate_macro_array_of_pointer() {
b"arr_ptr\0"
);
assert_eq!(foo_fields[2].offset, 2 * PTR_SIZE);
- assert_eq!(foo_fields[2].num_offset, 0);
+ assert_eq!(foo_fields[2].num_indirect.size, 0);
assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 });
assert_eq!(foo_fields[2].version_id, 0);
assert_eq!(foo_fields[2].size, PTR_SIZE);
@@ -391,7 +391,7 @@ fn test_vmstate_macro_array_of_pointer_wrapped() {
b"arr_ptr_wrap\0"
);
assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE);
- assert_eq!(foo_fields[3].num_offset, 0);
+ assert_eq!(foo_fields[3].num_indirect.size, 0);
assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_uint8 });
assert_eq!(foo_fields[3].version_id, 0);
assert_eq!(foo_fields[3].size, PTR_SIZE);
@@ -454,7 +454,7 @@ fn test_vmstate_validate() {
b"foo_d_0\0"
);
assert_eq!(foo_fields[0].offset, 0);
- assert_eq!(foo_fields[0].num_offset, 0);
+ assert_eq!(foo_fields[0].num_indirect.size, 0);
assert!(foo_fields[0].info.is_null());
assert_eq!(foo_fields[0].version_id, 0);
assert_eq!(foo_fields[0].size, 0);
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 2/8] migration: Introduce VMStateStructMember
2026-08-18 18:24 ` [PATCH v2 2/8] migration: Introduce VMStateStructMember Fabiano Rosas
@ 2026-08-18 19:12 ` Peter Xu
0 siblings, 0 replies; 11+ messages in thread
From: Peter Xu @ 2026-08-18 19:12 UTC (permalink / raw)
To: Fabiano Rosas
Cc: qemu-devel, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin, Seungjung Kim, Manos Pitsidianakis
On Tue, Aug 18, 2026 at 03:24:35PM -0300, Fabiano Rosas wrote:
> /*
> - * @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.
> + * @size directly specifies the size of the element being
> + * migrated.
> *
> - * When the field is an array of any type, this stores the size of one
> - * element of the array.
> + * @size_indirect specifies the offset inside a struct where the
> + * size of the element is stored.
> *
> - * 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.
> + * Only one of the above should be present (except for
> + * VMSTATE_MULTIPLY which uses .size as a multiplier). When
VMS_MULTIPLY
> + * @size_indirect 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, these refer to the size
> + * of one element of the array.
> + *
> + * NOTE: even if VMS_POINTER or VMS_ARRAY_OF_POINTER may be
> + * specified, these parameters always reflect the real size of the
> + * objects that a pointer point to.
> + *
> + * @num_indirect specifies the offset inside a struct where the
> + * number of elements of an array is stored.
> */
--
Peter Xu
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 3/8] migration: Remove redundant flags
2026-08-18 18:24 [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Fabiano Rosas
2026-08-18 18:24 ` [PATCH v2 1/8] migration: Remove unused " Fabiano Rosas
2026-08-18 18:24 ` [PATCH v2 2/8] migration: Introduce VMStateStructMember Fabiano Rosas
@ 2026-08-18 18:24 ` Fabiano Rosas
2026-08-18 18:24 ` [PATCH v2 4/8] migration: Remove duplicate vmstate macros Fabiano Rosas
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Fabiano Rosas @ 2026-08-18 18:24 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin, Manos Pitsidianakis
Remove the VMS_VARRAY and VMS_VBUFFER flags that became redundant due
to the previous commit which stores the size of the vmstate offset
variables along with the offset itself.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
include/migration/vmstate.h | 74 +++++++++++-------------------
migration/savevm.c | 6 +--
migration/vmstate.c | 3 +-
rust/bindings/migration-sys/lib.rs | 7 +--
rust/migration/src/vmstate.rs | 6 +--
rust/tests/tests/vmstate_tests.rs | 4 +-
6 files changed, 37 insertions(+), 63 deletions(-)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 12bfa64fb92..a168651a062 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -69,8 +69,9 @@ enum VMStateFlags {
* }). Dereference the pointer before using it as basis for
* further pointer arithmetic (see e.g. VMS_ARRAY). Does not
* affect the meaning of VMStateField.num_indirect or
- * VMStateField.size_indirect; see VMS_VARRAY* and VMS_VBUFFER for
- * those. */
+ * VMStateField.size_indirect; see VMS_VARRAY and VMS_VBUFFER for
+ * those.
+ */
VMS_POINTER = 0x002,
/* The field is an array of fixed size. VMStateField.num contains
@@ -80,12 +81,13 @@ enum VMStateFlags {
* VMS_MULTIPLY. Each array entry will be processed individually
* (VMStateField.info.get()/put() if VMS_STRUCT is not set,
* recursion into VMStateField.vmsd if VMS_STRUCT is set). May not
- * be combined with VMS_VARRAY*. */
+ * be combined with VMS_VARRAY.
+ */
VMS_ARRAY = 0x004,
/* The field is itself a struct, containing one or more
* fields. Recurse into VMStateField.vmsd. Most useful in
- * combination with VMS_ARRAY / VMS_VARRAY*, recursing into each
+ * combination with VMS_ARRAY / VMS_VARRAY, recursing into each
* array entry. */
VMS_STRUCT = 0x008,
@@ -93,9 +95,9 @@ enum VMStateFlags {
* The field is an array of variable size. The integer at opaque +
* VMStateField.num_indirect contains the number of entries in the
* array. See the VMS_ARRAY description regarding array handling
- * in general. May not be combined with VMS_ARRAY or any other
- * VMS_VARRAY*. */
- VMS_VARRAY_INT32 = 0x010,
+ * in general. May not be combined with VMS_ARRAY.
+ */
+ VMS_VARRAY = 0x010,
/* Ignored */
VMS_BUFFER = 0x020,
@@ -103,18 +105,12 @@ enum VMStateFlags {
/* The field is a (fixed-size or variable-size) array of pointers
* (e.g. struct a { uint8_t *b[]; }). Dereference each array entry
* before using it. Note: Does not imply any one of VMS_ARRAY /
- * VMS_VARRAY*; these need to be set explicitly. */
+ * VMS_VARRAY; these need to be set explicitly.
+ */
VMS_ARRAY_OF_POINTER = 0x040,
- /* The field is an array of variable size. The uint16_t at opaque
- * + VMStateField.num_indirect
- * contains the number of entries in the array. See the VMS_ARRAY
- * description regarding array handling in general. May not be
- * combined with VMS_ARRAY or any other VMS_VARRAY*. */
- VMS_VARRAY_UINT16 = 0x080,
-
/* The size of the individual entries (a single array entry if
- * VMS_ARRAY or any of VMS_VARRAY* are set, or the field itself if
+ * VMS_ARRAY or VMS_VARRAY are set, or the field itself if
* neither is set) is variable (i.e. not known at compile-time),
* but the same for all entries. Use the integer at opaque +
* VMStateField.size_indirect (subject to VMS_MULTIPLY) to determine
@@ -128,20 +124,6 @@ enum VMStateFlags {
* allocated. Only valid in combination with VMS_VBUFFER. */
VMS_MULTIPLY = 0x200,
- /* The field is an array of variable size. The uint8_t at opaque +
- * VMStateField.num_indirect
- * contains the number of entries in the array. See the VMS_ARRAY
- * description regarding array handling in general. May not be
- * combined with VMS_ARRAY or any other VMS_VARRAY*. */
- VMS_VARRAY_UINT8 = 0x400,
-
- /* The field is an array of variable size. The uint32_t at opaque
- * + VMStateField.num_indirect
- * contains the number of entries in the array. See the VMS_ARRAY
- * description regarding array handling in general. May not be
- * combined with VMS_ARRAY or any other VMS_VARRAY*. */
- VMS_VARRAY_UINT32 = 0x800,
-
/* Fail loading the serialised VM state if this field is missing
* from the input. */
VMS_MUST_EXIST = 0x1000,
@@ -530,7 +512,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
- .flags = VMS_VARRAY_INT32|VMS_POINTER, \
+ .flags = VMS_VARRAY | VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
@@ -540,7 +522,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
- .flags = VMS_VARRAY_UINT32|VMS_POINTER, \
+ .flags = VMS_VARRAY | VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
@@ -550,7 +532,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
- .flags = VMS_VARRAY_INT32 | VMS_POINTER | VMS_ALLOC, \
+ .flags = VMS_VARRAY | VMS_POINTER | VMS_ALLOC, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
@@ -560,7 +542,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
- .flags = VMS_VARRAY_UINT32|VMS_POINTER|VMS_ALLOC, \
+ .flags = VMS_VARRAY | VMS_POINTER | VMS_ALLOC, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
@@ -570,7 +552,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
- .flags = VMS_VARRAY_UINT16 | VMS_POINTER | VMS_ALLOC, \
+ .flags = VMS_VARRAY | VMS_POINTER | VMS_ALLOC, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
@@ -580,7 +562,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
.size = sizeof(_type), \
- .flags = VMS_VARRAY_UINT16, \
+ .flags = VMS_VARRAY, \
.offset = vmstate_offset_varray(_state, _field, _type), \
}
@@ -659,7 +641,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
- .flags = VMS_POINTER | VMS_VARRAY_UINT8 | \
+ .flags = VMS_POINTER | VMS_VARRAY | \
VMS_ARRAY_OF_POINTER | VMS_STRUCT | \
VMS_ARRAY_OF_POINTER_AUTO_ALLOC, \
.offset = vmstate_offset_pointer(_state, _field, _type *), \
@@ -672,7 +654,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
- .flags = VMS_POINTER | VMS_VARRAY_UINT32 | \
+ .flags = VMS_POINTER | VMS_VARRAY | \
VMS_ARRAY_OF_POINTER | VMS_STRUCT | \
VMS_ARRAY_OF_POINTER_AUTO_ALLOC, \
.offset = vmstate_offset_pointer(_state, _field, _type *), \
@@ -683,7 +665,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.version_id = (_version), \
.num_indirect = vmstate_field_offset(_state, _field_num), \
.info = &(_info), \
- .flags = VMS_VARRAY_UINT32 | VMS_ARRAY_OF_POINTER | VMS_POINTER, \
+ .flags = VMS_VARRAY | VMS_ARRAY_OF_POINTER | VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, _type *), \
}
@@ -727,7 +709,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.version_id = (_version), \
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
- .flags = VMS_STRUCT|VMS_VARRAY_UINT8, \
+ .flags = VMS_STRUCT | VMS_VARRAY, \
.offset = vmstate_offset_varray(_state, _field, _type), \
}
@@ -750,7 +732,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.size = sizeof(_type), \
.vmsd = &(_vmsd), \
- .flags = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT, \
+ .flags = VMS_POINTER | VMS_VARRAY | VMS_STRUCT, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
@@ -760,7 +742,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.size = sizeof(_type), \
.vmsd = &(_vmsd), \
- .flags = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT, \
+ .flags = VMS_POINTER | VMS_VARRAY | VMS_STRUCT, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
@@ -770,7 +752,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.num_indirect = vmstate_field_offset(_state, _field_num), \
.size = sizeof(_type), \
.vmsd = &(_vmsd), \
- .flags = VMS_POINTER | VMS_VARRAY_UINT16 | VMS_STRUCT, \
+ .flags = VMS_POINTER | VMS_VARRAY | VMS_STRUCT, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
@@ -780,7 +762,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.version_id = (_version), \
.vmsd = &(_vmsd), \
.size = sizeof(_type), \
- .flags = VMS_STRUCT|VMS_VARRAY_UINT32, \
+ .flags = VMS_STRUCT | VMS_VARRAY, \
.offset = vmstate_offset_varray(_state, _field, _type), \
}
@@ -790,7 +772,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.vmsd = &(_vmsd), \
.num_indirect = vmstate_field_offset(_state, _field_num), \
.size = sizeof(_type), \
- .flags = VMS_STRUCT|VMS_VARRAY_INT32|VMS_ALLOC|VMS_POINTER, \
+ .flags = VMS_STRUCT | VMS_VARRAY | VMS_ALLOC | VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
@@ -915,7 +897,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.version_id = (_version), \
.size = (_size), \
.info = &vmstate_info_unused_buffer, \
- .flags = VMS_VARRAY_UINT32 | VMS_BUFFER, \
+ .flags = VMS_VARRAY | VMS_BUFFER, \
}
/* _field_size should be a int32_t field in the _state struct giving the
diff --git a/migration/savevm.c b/migration/savevm.c
index e1b707dda63..3e5cce6520d 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -884,11 +884,9 @@ static void vmstate_check(const VMStateDescription *vmsd)
}
/*
* VMS_ARRAY_OF_POINTER must be used only together with one
- * of VMS_(V)ARRAY* flags.
+ * of VMS_(V)ARRAY flags.
*/
- assert(field->flags & (VMS_ARRAY | VMS_VARRAY_INT32 |
- VMS_VARRAY_UINT16 | VMS_VARRAY_UINT8 |
- VMS_VARRAY_UINT32));
+ assert(field->flags & (VMS_ARRAY | VMS_VARRAY));
}
if (field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC) {
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 372aed258f1..bc5285bcea2 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -101,8 +101,7 @@ static uint64_t vmstate_n_elems(void *opaque, const VMStateField *field)
if (field->flags & VMS_ARRAY) {
n_elems = field->num;
- } else if (field->flags & (VMS_VARRAY_INT32 | VMS_VARRAY_UINT32
- | VMS_VARRAY_UINT16 | VMS_VARRAY_UINT8)) {
+ } else if (field->flags & VMS_VARRAY) {
n_elems = vmstate_read_from_offset(&field->num_indirect, opaque);
}
diff --git a/rust/bindings/migration-sys/lib.rs b/rust/bindings/migration-sys/lib.rs
index baa2730ca9d..c8397dc8974 100644
--- a/rust/bindings/migration-sys/lib.rs
+++ b/rust/bindings/migration-sys/lib.rs
@@ -57,12 +57,7 @@ pub trait VMStateFlagsExt {
}
impl VMStateFlagsExt for VMStateFlags {
- const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(
- VMStateFlags::VMS_VARRAY_INT32.0
- | VMStateFlags::VMS_VARRAY_UINT8.0
- | VMStateFlags::VMS_VARRAY_UINT16.0
- | VMStateFlags::VMS_VARRAY_UINT32.0,
- );
+ const VMS_VARRAY_FLAGS: VMStateFlags = VMStateFlags(VMStateFlags::VMS_VARRAY.0);
}
// Add a couple builder-style methods to VMStateField, allowing
diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs
index e60c0860cc5..4ec54097148 100644
--- a/rust/migration/src/vmstate.rs
+++ b/rust/migration/src/vmstate.rs
@@ -287,9 +287,9 @@ unsafe impl $crate::vmstate::VMState for $type {
impl_vmstate_scalar!(vmstate_info_int16, i16);
impl_vmstate_scalar!(vmstate_info_int32, i32);
impl_vmstate_scalar!(vmstate_info_int64, i64);
-impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY_UINT8);
-impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY_UINT16);
-impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY_UINT32);
+impl_vmstate_scalar!(vmstate_info_uint8, u8, VMS_VARRAY);
+impl_vmstate_scalar!(vmstate_info_uint16, u16, VMS_VARRAY);
+impl_vmstate_scalar!(vmstate_info_uint32, u32, VMS_VARRAY);
impl_vmstate_scalar!(vmstate_info_uint64, u64);
impl_vmstate_scalar!(vmstate_info_timer, util::timer::Timer);
diff --git a/rust/tests/tests/vmstate_tests.rs b/rust/tests/tests/vmstate_tests.rs
index c002ffb2bc4..5f6dd8ae7f1 100644
--- a/rust/tests/tests/vmstate_tests.rs
+++ b/rust/tests/tests/vmstate_tests.rs
@@ -113,7 +113,7 @@ fn test_vmstate_varray_uint16_unsafe() {
assert_eq!(foo_fields[2].version_id, 0);
assert_eq!(foo_fields[2].size, 1);
assert_eq!(foo_fields[2].num, 0);
- assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY_UINT16);
+ assert_eq!(foo_fields[2].flags, VMStateFlags::VMS_VARRAY);
assert!(foo_fields[2].vmsd.is_null());
assert!(foo_fields[2].field_exists.is_none());
}
@@ -222,7 +222,7 @@ fn test_vmstate_struct_varray_uint8() {
assert_eq!(foo_fields[2].num, 0);
assert_eq!(
foo_fields[2].flags.0,
- VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY_UINT8.0
+ VMStateFlags::VMS_STRUCT.0 | VMStateFlags::VMS_VARRAY.0
);
assert_eq!(foo_fields[2].vmsd, VMSTATE_FOOA.as_ref());
assert!(foo_fields[2].field_exists.is_none());
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 4/8] migration: Remove duplicate vmstate macros
2026-08-18 18:24 [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Fabiano Rosas
` (2 preceding siblings ...)
2026-08-18 18:24 ` [PATCH v2 3/8] migration: Remove redundant flags Fabiano Rosas
@ 2026-08-18 18:24 ` Fabiano Rosas
2026-08-18 18:24 ` [PATCH v2 5/8] migration: Add VMS_NO_STATE flag Fabiano Rosas
` (4 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Fabiano Rosas @ 2026-08-18 18:24 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin
Now that type-checking is not being done per integer size anymore,
various macros have duplicated bodies. Remove them.
The original names are left the same so the device code can be altered
per-subsystem in the next patches.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
include/migration/vmstate.h | 135 ++++++++++++------------------------
1 file changed, 44 insertions(+), 91 deletions(-)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index a168651a062..4b6d52955ff 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -506,7 +506,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = vmstate_offset_sub_array(_state, _field, _type, _start), \
}
-#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\
+#define VMSTATE_VARRAY(_field, _state, _field_num, _version, _info, _type) {\
.name = (stringify(_field)), \
.version_id = (_version), \
.num_indirect = vmstate_field_offset(_state, _field_num), \
@@ -516,17 +516,11 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
-#define VMSTATE_VARRAY_UINT32(_field, _state, _field_num, _version, _info, _type) {\
- .name = (stringify(_field)), \
- .version_id = (_version), \
- .num_indirect = vmstate_field_offset(_state, _field_num), \
- .info = &(_info), \
- .size = sizeof(_type), \
- .flags = VMS_VARRAY | VMS_POINTER, \
- .offset = vmstate_offset_pointer(_state, _field, _type), \
-}
+#define VMSTATE_VARRAY_INT32 VMSTATE_VARRAY
+#define VMSTATE_VARRAY_UINT32 VMSTATE_VARRAY
-#define VMSTATE_VARRAY_INT32_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
+#define VMSTATE_VARRAY_ALLOC(_field, _state, _field_num, _version, _info, \
+ _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
.num_indirect = vmstate_field_offset(_state, _field_num), \
@@ -536,27 +530,12 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
-#define VMSTATE_VARRAY_UINT32_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
- .name = (stringify(_field)), \
- .version_id = (_version), \
- .num_indirect = vmstate_field_offset(_state, _field_num), \
- .info = &(_info), \
- .size = sizeof(_type), \
- .flags = VMS_VARRAY | VMS_POINTER | VMS_ALLOC, \
- .offset = vmstate_offset_pointer(_state, _field, _type), \
-}
-
-#define VMSTATE_VARRAY_UINT16_ALLOC(_field, _state, _field_num, _version, _info, _type) {\
- .name = (stringify(_field)), \
- .version_id = (_version), \
- .num_indirect = vmstate_field_offset(_state, _field_num), \
- .info = &(_info), \
- .size = sizeof(_type), \
- .flags = VMS_VARRAY | VMS_POINTER | VMS_ALLOC, \
- .offset = vmstate_offset_pointer(_state, _field, _type), \
-}
+#define VMSTATE_VARRAY_INT32_ALLOC VMSTATE_VARRAY_ALLOC
+#define VMSTATE_VARRAY_UINT32_ALLOC VMSTATE_VARRAY_ALLOC
+#define VMSTATE_VARRAY_UINT16_ALLOC VMSTATE_VARRAY_ALLOC
-#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\
+#define VMSTATE_VARRAY_UNSAFE(_field, _state, _field_num, _version, _info, \
+ _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
.num_indirect = vmstate_field_offset(_state, _field_num), \
@@ -566,6 +545,8 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = vmstate_offset_varray(_state, _field, _type), \
}
+#define VMSTATE_VARRAY_UINT16_UNSAFE VMSTATE_VARRAY_UNSAFE
+
#define VMSTATE_VSTRUCT_TEST(_field, _state, _test, _version, _vmsd, _type, _struct_version) { \
.name = (stringify(_field)), \
.version_id = (_version), \
@@ -634,7 +615,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
* _info: VMStateInfo for _type (when VMS_STRUCT is not set)
* start: size of (_type) pointed to (for auto memory allocation)
*/
-#define VMSTATE_VARRAY_OF_POINTER_TO_STRUCT_UINT8_ALLOC(\
+#define VMSTATE_VARRAY_OF_POINTER_TO_STRUCT_ALLOC( \
_field, _state, _field_num, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
@@ -647,20 +628,13 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = vmstate_offset_pointer(_state, _field, _type *), \
}
-#define VMSTATE_VARRAY_OF_POINTER_TO_STRUCT_UINT32_ALLOC(\
- _field, _state, _field_num, _version, _vmsd, _type) { \
- .name = (stringify(_field)), \
- .version_id = (_version), \
- .num_indirect = vmstate_field_offset(_state, _field_num), \
- .vmsd = &(_vmsd), \
- .size = sizeof(_type), \
- .flags = VMS_POINTER | VMS_VARRAY | \
- VMS_ARRAY_OF_POINTER | VMS_STRUCT | \
- VMS_ARRAY_OF_POINTER_AUTO_ALLOC, \
- .offset = vmstate_offset_pointer(_state, _field, _type *), \
-}
+#define VMSTATE_VARRAY_OF_POINTER_TO_STRUCT_UINT8_ALLOC \
+ VMSTATE_VARRAY_OF_POINTER_TO_STRUCT_ALLOC
+#define VMSTATE_VARRAY_OF_POINTER_TO_STRUCT_UINT32_ALLOC \
+ VMSTATE_VARRAY_OF_POINTER_TO_STRUCT_ALLOC
-#define VMSTATE_VARRAY_OF_POINTER_UINT32(_field, _state, _field_num, _version, _info, _type) { \
+#define VMSTATE_VARRAY_OF_POINTER(_field, _state, _field_num, _version, _info, \
+ _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
.num_indirect = vmstate_field_offset(_state, _field_num), \
@@ -669,6 +643,8 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = vmstate_offset_pointer(_state, _field, _type *), \
}
+#define VMSTATE_VARRAY_OF_POINTER_UINT32 VMSTATE_VARRAY_OF_POINTER
+
#define VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, _num, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
@@ -703,7 +679,8 @@ extern const VMStateInfo vmstate_info_g_byte_array;
_n1, _n2), \
}
-#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
+#define VMSTATE_STRUCT_VARRAY(_field, _state, _field_num, _version, _vmsd, \
+ _type) { \
.name = (stringify(_field)), \
.num_indirect = vmstate_field_offset(_state, _field_num), \
.version_id = (_version), \
@@ -712,6 +689,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.flags = VMS_STRUCT | VMS_VARRAY, \
.offset = vmstate_offset_varray(_state, _field, _type), \
}
+#define VMSTATE_STRUCT_VARRAY_UINT8 VMSTATE_STRUCT_VARRAY
/* a variable length array (i.e. _type *_field) but we know the
* length
@@ -726,7 +704,8 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = offsetof(_state, _field), \
}
-#define VMSTATE_STRUCT_VARRAY_POINTER_INT32(_field, _state, _field_num, _vmsd, _type) { \
+#define VMSTATE_STRUCT_VARRAY_POINTER(_field, _state, _field_num, _vmsd, \
+ _type) { \
.name = (stringify(_field)), \
.version_id = 0, \
.num_indirect = vmstate_field_offset(_state, _field_num), \
@@ -735,28 +714,12 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.flags = VMS_POINTER | VMS_VARRAY | VMS_STRUCT, \
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
+#define VMSTATE_STRUCT_VARRAY_POINTER_INT32 VMSTATE_STRUCT_VARRAY_POINTER
+#define VMSTATE_STRUCT_VARRAY_POINTER_UINT32 VMSTATE_STRUCT_VARRAY_POINTER
+#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16 VMSTATE_STRUCT_VARRAY_POINTER
-#define VMSTATE_STRUCT_VARRAY_POINTER_UINT32(_field, _state, _field_num, _vmsd, _type) { \
- .name = (stringify(_field)), \
- .version_id = 0, \
- .num_indirect = vmstate_field_offset(_state, _field_num), \
- .size = sizeof(_type), \
- .vmsd = &(_vmsd), \
- .flags = VMS_POINTER | VMS_VARRAY | VMS_STRUCT, \
- .offset = vmstate_offset_pointer(_state, _field, _type), \
-}
-
-#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \
- .name = (stringify(_field)), \
- .version_id = 0, \
- .num_indirect = vmstate_field_offset(_state, _field_num), \
- .size = sizeof(_type), \
- .vmsd = &(_vmsd), \
- .flags = VMS_POINTER | VMS_VARRAY | VMS_STRUCT, \
- .offset = vmstate_offset_pointer(_state, _field, _type), \
-}
-
-#define VMSTATE_STRUCT_VARRAY_UINT32(_field, _state, _field_num, _version, _vmsd, _type) { \
+#define VMSTATE_STRUCT_VARRAY(_field, _state, _field_num, _version, _vmsd, \
+ _type) { \
.name = (stringify(_field)), \
.num_indirect = vmstate_field_offset(_state, _field_num), \
.version_id = (_version), \
@@ -765,8 +728,11 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.flags = VMS_STRUCT | VMS_VARRAY, \
.offset = vmstate_offset_varray(_state, _field, _type), \
}
+#define VMSTATE_STRUCT_VARRAY_INT32 VMSTATE_STRUCT_VARRAY
+#define VMSTATE_STRUCT_VARRAY_UINT32 VMSTATE_STRUCT_VARRAY
-#define VMSTATE_STRUCT_VARRAY_ALLOC(_field, _state, _field_num, _version, _vmsd, _type) {\
+#define VMSTATE_STRUCT_VARRAY_ALLOC(_field, _state, _field_num, _version, \
+ _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
.vmsd = &(_vmsd), \
@@ -808,28 +774,11 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = offsetof(_state, _field), \
}
-#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _field_size) { \
- .name = (stringify(_field)), \
- .version_id = (_version), \
- .field_exists = (_test), \
- .size_indirect = vmstate_field_offset(_state, _field_size), \
- .info = &vmstate_info_buffer, \
- .flags = VMS_VBUFFER|VMS_POINTER, \
- .offset = offsetof(_state, _field), \
-}
+#define VMSTATE_VBUFFER_UINT32 VMSTATE_VBUFFER
+#define VMSTATE_VBUFFER_UINT64 VMSTATE_VBUFFER
-#define VMSTATE_VBUFFER_UINT64(_field, _state, _version, _test, _field_size) { \
- .name = (stringify(_field)), \
- .version_id = (_version), \
- .field_exists = (_test), \
- .size_indirect = vmstate_field_offset(_state, _field_size), \
- .info = &vmstate_info_buffer, \
- .flags = VMS_VBUFFER | VMS_POINTER, \
- .offset = offsetof(_state, _field), \
-}
-
-#define VMSTATE_VBUFFER_ALLOC_UINT32(_field, _state, _version, \
- _test, _field_size) { \
+#define VMSTATE_VBUFFER_ALLOC(_field, _state, _version, \
+ _test, _field_size) { \
.name = (stringify(_field)), \
.version_id = (_version), \
.field_exists = (_test), \
@@ -839,6 +788,8 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.offset = offsetof(_state, _field), \
}
+#define VMSTATE_VBUFFER_ALLOC_UINT32 VMSTATE_VBUFFER_ALLOC
+
#define VMSTATE_BUFFER_UNSAFE_INFO_TEST(_field, _state, _test, _version, _info, _size) { \
.name = (stringify(_field)), \
.version_id = (_version), \
@@ -890,7 +841,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
}
/* Discard size * field_num bytes, where field_num is a uint32 member */
-#define VMSTATE_UNUSED_VARRAY_UINT32(_state, _test, _version, _field_num, _size) {\
+#define VMSTATE_UNUSED_VARRAY(_state, _test, _version, _field_num, _size) {\
.name = "unused", \
.field_exists = (_test), \
.num_indirect = vmstate_field_offset(_state, _field_num), \
@@ -900,6 +851,8 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.flags = VMS_VARRAY | VMS_BUFFER, \
}
+#define VMSTATE_UNUSED_VARRAY_UINT32 VMSTATE_UNUSED_VARRAY
+
/* _field_size should be a int32_t field in the _state struct giving the
* size of the bitmap _field in bits.
*/
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 5/8] migration: Add VMS_NO_STATE flag
2026-08-18 18:24 [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Fabiano Rosas
` (3 preceding siblings ...)
2026-08-18 18:24 ` [PATCH v2 4/8] migration: Remove duplicate vmstate macros Fabiano Rosas
@ 2026-08-18 18:24 ` Fabiano Rosas
2026-08-18 18:24 ` [PATCH v2 6/8] migration: Check more vmstate flags Fabiano Rosas
` (3 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Fabiano Rosas @ 2026-08-18 18:24 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin, Paolo Bonzini, Fam Zheng,
Manos Pitsidianakis
There are a few special cases of vmstate usage:
The vmstate_msix and vmstate_scsi_device have fields that contain no
data, only a vmstate_info structure.
The VMSTATE_VALIDATE macro serves only to invoke the .field_exists
routine for validation.
Regardless whether these scenarios are valid, add a separate flag to
identify them so we can enforce common constraints for the normal
vmstates such as having a size greater than zero.
Note that n_elems is hardcoded to 1 for all vmstates, except
VMS_[V]ARRAY, so VMSTATE_VALIDATE needed to set VMS_ARRAY to be able
to force n_elems to 0. This patch now checks the flag at
vmstate_n_elems().
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
hw/pci/msix.c | 6 +-----
hw/scsi/scsi-bus.c | 6 +-----
include/migration/vmstate.h | 9 +++++++--
migration/vmstate.c | 6 +++++-
rust/migration/src/vmstate.rs | 2 +-
rust/tests/tests/vmstate_tests.rs | 2 +-
6 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 1b23eaf1007..adf76b5bccc 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -711,12 +711,8 @@ const VMStateDescription vmstate_msix = {
.fields = (const VMStateField[]) {
{
.name = "msix",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0, /* ouch */
.info = &vmstate_info_msix,
- .flags = VMS_SINGLE,
- .offset = 0,
+ .flags = VMS_SINGLE | VMS_NO_STATE,
},
VMSTATE_END_OF_LIST()
}
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index deb43d5560e..aa02ff631b7 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -1980,12 +1980,8 @@ const VMStateDescription vmstate_scsi_device = {
VMSTATE_UINT32(sense_len, SCSIDevice),
{
.name = "requests",
- .version_id = 0,
- .field_exists = NULL,
- .size = 0, /* ouch */
.info = &vmstate_info_scsi_requests,
- .flags = VMS_SINGLE,
- .offset = 0,
+ .flags = VMS_SINGLE | VMS_NO_STATE,
},
VMSTATE_END_OF_LIST()
},
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 4b6d52955ff..e72c3fae9a6 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -109,6 +109,12 @@ enum VMStateFlags {
*/
VMS_ARRAY_OF_POINTER = 0x040,
+ /*
+ * The field contains no data. Used for special cases such as
+ * invoking a custom VMStateInfo.
+ */
+ VMS_NO_STATE = 0x080,
+
/* The size of the individual entries (a single array entry if
* VMS_ARRAY or VMS_VARRAY are set, or the field itself if
* neither is set) is variable (i.e. not known at compile-time),
@@ -454,8 +460,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
#define VMSTATE_VALIDATE(_name, _test) { \
.name = (_name), \
.field_exists = (_test), \
- .flags = VMS_ARRAY | VMS_MUST_EXIST, \
- .num = 0, /* 0 elements: no data, only run _test */ \
+ .flags = VMS_MUST_EXIST | VMS_NO_STATE, \
}
#define VMSTATE_POINTER(_field, _state, _version, _info, _type) { \
diff --git a/migration/vmstate.c b/migration/vmstate.c
index bc5285bcea2..51d02b87e7e 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -97,12 +97,16 @@ static uint64_t vmstate_read_from_offset(const VMStateStructMember *member,
static uint64_t vmstate_n_elems(void *opaque, const VMStateField *field)
{
- uint64_t n_elems = 1;
+ uint64_t n_elems;
if (field->flags & VMS_ARRAY) {
n_elems = field->num;
} else if (field->flags & VMS_VARRAY) {
n_elems = vmstate_read_from_offset(&field->num_indirect, opaque);
+ } else if (field->flags & VMS_MUST_EXIST && field->flags & VMS_NO_STATE) {
+ n_elems = 0;
+ } else {
+ n_elems = 1;
}
trace_vmstate_n_elems(field->name, n_elems);
diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs
index 4ec54097148..a3a710ab3ac 100644
--- a/rust/migration/src/vmstate.rs
+++ b/rust/migration/src/vmstate.rs
@@ -418,7 +418,7 @@ macro_rules! vmstate_validate {
field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),
flags: $crate::bindings::VMStateFlags(
$crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
- | $crate::bindings::VMStateFlags::VMS_ARRAY.0,
+ | $crate::bindings::VMStateFlags::VMS_NO_STATE.0,
),
num: 0, // 0 elements: no data, only run test_fn callback
..::common::zeroable::Zeroable::ZERO
diff --git a/rust/tests/tests/vmstate_tests.rs b/rust/tests/tests/vmstate_tests.rs
index 5f6dd8ae7f1..6578d54b37d 100644
--- a/rust/tests/tests/vmstate_tests.rs
+++ b/rust/tests/tests/vmstate_tests.rs
@@ -461,7 +461,7 @@ fn test_vmstate_validate() {
assert_eq!(foo_fields[0].num, 0);
assert_eq!(
foo_fields[0].flags.0,
- VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_MUST_EXIST.0
+ VMStateFlags::VMS_NO_STATE.0 | VMStateFlags::VMS_MUST_EXIST.0
);
assert!(foo_fields[0].vmsd.is_null());
assert!(unsafe { foo_fields[0].field_exists.unwrap()(foo_d_p, 0) });
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 6/8] migration: Check more vmstate flags
2026-08-18 18:24 [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Fabiano Rosas
` (4 preceding siblings ...)
2026-08-18 18:24 ` [PATCH v2 5/8] migration: Add VMS_NO_STATE flag Fabiano Rosas
@ 2026-08-18 18:24 ` Fabiano Rosas
2026-08-18 18:24 ` [PATCH v2 7/8] migration: Harden vmstate_handle_alloc Fabiano Rosas
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Fabiano Rosas @ 2026-08-18 18:24 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin
Add more checks for vmstate flags constraints.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/savevm.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/migration/savevm.c b/migration/savevm.c
index 3e5cce6520d..c44df365cc8 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -893,6 +893,25 @@ static void vmstate_check(const VMStateDescription *vmsd)
assert(field->flags & VMS_ARRAY_OF_POINTER);
}
+ /*
+ * The VMS*ARRAY flags and VMS_VBUFFER affect allocation,
+ * they must have the proper fields set and no other
+ * vmstate types can set those fields, otherwise it won't
+ * be picked-up due to the missing flag.
+ */
+
+ if (field->flags & (VMS_ARRAY | VMS_VARRAY)) {
+ assert(field->num > 0 || field->num_indirect.size != 0);
+ } else {
+ assert(field->num == 0 && field->num_indirect.size == 0);
+ }
+
+ if (field->flags & VMS_VBUFFER) {
+ assert(field->size_indirect.size != 0);
+ } else {
+ assert(field->size_indirect.size == 0);
+ }
+
if (field->flags & (VMS_STRUCT | VMS_VSTRUCT)) {
/* Recurse to sub structures */
vmstate_check(field->vmsd);
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 7/8] migration: Harden vmstate_handle_alloc
2026-08-18 18:24 [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Fabiano Rosas
` (5 preceding siblings ...)
2026-08-18 18:24 ` [PATCH v2 6/8] migration: Check more vmstate flags Fabiano Rosas
@ 2026-08-18 18:24 ` Fabiano Rosas
2026-08-18 18:24 ` [PATCH v2 8/8] migration: Harden vmstate_size Fabiano Rosas
2026-08-18 19:12 ` [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Peter Xu
8 siblings, 0 replies; 11+ messages in thread
From: Fabiano Rosas @ 2026-08-18 18:24 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin
Harden the vmstate_handle_alloc function against overflow of the 64bit
integers it consumes and failure to allocate due to an exceedingly
large request.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/vmstate.c | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 51d02b87e7e..1d028bfe009 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -135,16 +135,28 @@ static uint64_t vmstate_size(void *opaque, const VMStateField *field)
return size;
}
-static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
- void *opaque)
+static bool vmstate_handle_alloc(void *ptr, const VMStateField *field,
+ uint64_t n, uint64_t size, Error **errp)
{
+ void *p;
+
if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
- uint64_t size = vmstate_size(opaque, field);
- size *= vmstate_n_elems(opaque, field);
- if (size) {
- *(void **)ptr = g_malloc(size);
- }
+ if (size && n) {
+ if (umul64_overflow(size, n, &size)) {
+ error_setg(errp, "%s: field '%s' multiply overflow",
+ __func__, field->name);
+ return false;
+ }
+ p = g_try_malloc(size);
+ if (!p) {
+ error_setg(errp, "%s: Could not allocate memory for field '%s'",
+ __func__, field->name);
+ return false;
+ }
+ *(void **)ptr = p;
+ }
}
+ return true;
}
static bool vmstate_ptr_marker_load(QEMUFile *f, bool *load_field,
@@ -354,7 +366,9 @@ bool vmstate_load_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
uint64_t n_elems = vmstate_n_elems(opaque, field);
uint64_t size = vmstate_size(opaque, field);
- vmstate_handle_alloc(first_elem, field, opaque);
+ if (!vmstate_handle_alloc(first_elem, field, n_elems, size, errp)) {
+ return false;
+ }
if (field->flags & VMS_POINTER) {
first_elem = *(void **)first_elem;
assert(first_elem || !n_elems || !size);
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH v2 8/8] migration: Harden vmstate_size
2026-08-18 18:24 [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Fabiano Rosas
` (6 preceding siblings ...)
2026-08-18 18:24 ` [PATCH v2 7/8] migration: Harden vmstate_handle_alloc Fabiano Rosas
@ 2026-08-18 18:24 ` Fabiano Rosas
2026-08-18 19:12 ` [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Peter Xu
8 siblings, 0 replies; 11+ messages in thread
From: Fabiano Rosas @ 2026-08-18 18:24 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin
Protect vmstate_size against overflow of the on-stack 64bit integer
during multiplication. The data at size_indirect.offset comes from the
migration stream.
Signed-off-by: Fabiano Rosas <farosas@suse.de>
---
migration/vmstate.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 1d028bfe009..08548ae7a1f 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -113,14 +113,20 @@ static uint64_t vmstate_n_elems(void *opaque, const VMStateField *field)
return n_elems;
}
-static uint64_t vmstate_size(void *opaque, const VMStateField *field)
+static bool vmstate_size(void *opaque, const VMStateField *field,
+ uint64_t *sz, Error **errp)
{
uint64_t size;
+ *sz = 0;
+
if (field->flags & VMS_VBUFFER) {
size = vmstate_read_from_offset(&field->size_indirect, opaque);
- if (field->flags & VMS_MULTIPLY) {
- size *= field->size;
+ if ((field->flags & VMS_MULTIPLY) &&
+ umul64_overflow(size, field->size, &size)) {
+ error_setg(errp, "%s: VMState field '%s' multiply overflow",
+ __func__, field->name);
+ return false;
}
} else if (field->flags & VMS_ARRAY_OF_POINTER) {
/*
@@ -132,7 +138,8 @@ static uint64_t vmstate_size(void *opaque, const VMStateField *field)
size = field->size;
}
- return size;
+ *sz = size;
+ return true;
}
static bool vmstate_handle_alloc(void *ptr, const VMStateField *field,
@@ -364,7 +371,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
void *first_elem = opaque + field->offset;
int i;
uint64_t n_elems = vmstate_n_elems(opaque, field);
- uint64_t size = vmstate_size(opaque, field);
+ uint64_t size;
+
+ if (!vmstate_size(opaque, field, &size, errp)) {
+ return false;
+ }
if (!vmstate_handle_alloc(first_elem, field, n_elems, size, errp)) {
return false;
@@ -682,9 +693,10 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd,
void *first_elem = opaque + field->offset;
int i;
uint64_t n_elems = vmstate_n_elems(opaque, field);
- uint64_t size = vmstate_size(opaque, field);
+ uint64_t size;
JSONWriter *vmdesc_loop = vmdesc;
bool is_prev_null = false;
+
/*
* When this is enabled, it means we will always push a ptr
* marker first for each element saying if it's populated.
@@ -692,6 +704,10 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd,
bool use_dynamic_array =
field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
+ if (!vmstate_size(opaque, field, &size, errp)) {
+ return false;
+ }
+
trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems);
if (field->flags & VMS_POINTER) {
first_elem = *(void **)first_elem;
--
2.53.0
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros
2026-08-18 18:24 [PATCH v2 0/8] migration: Remove extra type-checking from vmstate macros Fabiano Rosas
` (7 preceding siblings ...)
2026-08-18 18:24 ` [PATCH v2 8/8] migration: Harden vmstate_size Fabiano Rosas
@ 2026-08-18 19:12 ` Peter Xu
8 siblings, 0 replies; 11+ messages in thread
From: Peter Xu @ 2026-08-18 19:12 UTC (permalink / raw)
To: Fabiano Rosas
Cc: qemu-devel, Vladimir Sementsov-Ogievskiy, Alexandr Moshkov,
Michael S . Tsirkin
On Tue, Aug 18, 2026 at 03:24:33PM -0300, Fabiano Rosas wrote:
> Changes in v2:
>
> - Removed more unused vmstate macros
> - Fixed the type check macro
> - Renamed the new structure to something more explicit
> - Added a new flag to indicate an empty vmstate
> - Added the overflow and overallocation checks
>
> CI run: https://gitlab.com/farosas/qemu/-/pipelines/2769617319
> Also tested:
> - migration-test --full --thorough
> - x86_64 compat run forward and backwards for previous 3 QEMU releases
> - s390x compat run forward and backwards for previous 2 QEMU releases
> - ppc64 compat run forward and backwards for previous QEMU release
> - migration-test smoke ASAN/UBSAN run
>
> v1:
> https://lore.kernel.org/r/20260729225227.1170574-1-farosas@suse.de
>
> Hi, this is basically what I ranted about in:
> https://lore.kernel.org/r/87jyqeomqz.fsf@suse.de
>
> I'm replacing the per-integer-size type checks with a single "int that
> fits in 32bit" check. This allows several lines of duplicated code to
> be removed.
>
> I haven't changed the macro names in the device code yet. If this
> series gets positive feedback then I'll send per-subsystem patches
> doing that.
>
> CI run: https://gitlab.com/farosas/qemu/-/pipelines/2716814081
> Also tested:
> - migration-test --full --thorough
> - x86_64 compat run forwards and backwards for previous 3 QEMU releases
> - s390x compat run forwards and backwards for previous 2 QEMU releases
> - ppc64 compat run forwards and backwards for previous QEMU release
> - migration-test smoke ASAN/UBSAN run
>
> Fabiano Rosas (8):
> migration: Remove unused vmstate macros
> migration: Introduce VMStateStructMember
> migration: Remove redundant flags
> migration: Remove duplicate vmstate macros
> migration: Add VMS_NO_STATE flag
> migration: Check more vmstate flags
> migration: Harden vmstate_handle_alloc
> migration: Harden vmstate_size
>
> hw/pci/msix.c | 6 +-
> hw/scsi/scsi-bus.c | 6 +-
> include/migration/vmstate.h | 388 +++++++++++++----------------
> migration/savevm.c | 29 ++-
> migration/vmstate.c | 103 +++++---
> rust/bindings/migration-sys/lib.rs | 17 +-
> rust/migration/src/vmstate.rs | 32 ++-
> rust/tests/tests/vmstate_tests.rs | 32 +--
> 8 files changed, 331 insertions(+), 282 deletions(-)
For anything that is non-Rust:
Acked-by: Peter Xu <peterx@redhat.com>
One typo I'll comment inline, can be touched up when you queue.
--
Peter Xu
^ permalink raw reply [flat|nested] 11+ messages in thread