@samitouri / QOSamiQemu / commits / 797b88eddd

migration: Add VMS_NO_STATE flag

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(). Acked-by: Peter Xu <peterx@redhat.com> Signed-off-by: Fabiano Rosas <farosas@suse.de>

Fabiano Rosas committed Aug 18, 2026 at 15:24 UTC 797b88eddd7066febfb103b7d48ed8b6a693c06b
6 files changed +16 -15
hw/pci/msix.c
+1 -5
@@ -711,12 +711,8 @@ const VMStateDescription vmstate_msix = {
711 .fields = (const VMStateField[]) {
712 {
713 .name = "msix",
714 - .version_id = 0,
715 - .field_exists = NULL,
716 - .size = 0, /* ouch */
714 .info = &vmstate_info_msix,
718 - .flags = VMS_SINGLE,
719 - .offset = 0,
715 + .flags = VMS_SINGLE | VMS_NO_STATE,
716 },
717 VMSTATE_END_OF_LIST()
718 }
hw/scsi/scsi-bus.c
+1 -5
@@ -1980,12 +1980,8 @@ const VMStateDescription vmstate_scsi_device = {
1980 VMSTATE_UINT32(sense_len, SCSIDevice),
1981 {
1982 .name = "requests",
1983 - .version_id = 0,
1984 - .field_exists = NULL,
1985 - .size = 0, /* ouch */
1983 .info = &vmstate_info_scsi_requests,
1987 - .flags = VMS_SINGLE,
1988 - .offset = 0,
1984 + .flags = VMS_SINGLE | VMS_NO_STATE,
1985 },
1986 VMSTATE_END_OF_LIST()
1987 },
include/migration/vmstate.h
+7 -2
@@ -109,6 +109,12 @@ enum VMStateFlags {
109 */
110 VMS_ARRAY_OF_POINTER = 0x040,
111
112 + /*
113 + * The field contains no data. Used for special cases such as
114 + * invoking a custom VMStateInfo.
115 + */
116 + VMS_NO_STATE = 0x080,
117 +
118 /* The size of the individual entries (a single array entry if
119 * VMS_ARRAY or VMS_VARRAY are set, or the field itself if
120 * neither is set) is variable (i.e. not known at compile-time),
@@ -454,8 +460,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
460 #define VMSTATE_VALIDATE(_name, _test) { \
461 .name = (_name), \
462 .field_exists = (_test), \
457 - .flags = VMS_ARRAY | VMS_MUST_EXIST, \
458 - .num = 0, /* 0 elements: no data, only run _test */ \
463 + .flags = VMS_MUST_EXIST | VMS_NO_STATE, \
464 }
465
466 #define VMSTATE_POINTER(_field, _state, _version, _info, _type) { \
migration/vmstate.c
+5 -1
@@ -110,12 +110,16 @@ static uint64_t vmstate_read_from_offset(const VMStateStructMember *member,
110
111 static uint64_t vmstate_n_elems(void *opaque, const VMStateField *field)
112 {
113 - uint64_t n_elems = 1;
113 + uint64_t n_elems;
114
115 if (field->flags & VMS_ARRAY) {
116 n_elems = field->num;
117 } else if (field->flags & VMS_VARRAY) {
118 n_elems = vmstate_read_from_offset(&field->num_indirect, opaque);
119 + } else if (field->flags & VMS_MUST_EXIST && field->flags & VMS_NO_STATE) {
120 + n_elems = 0;
121 + } else {
122 + n_elems = 1;
123 }
124
125 trace_vmstate_n_elems(field->name, n_elems);
rust/migration/src/vmstate.rs
+1 -1
@@ -381,7 +381,7 @@ macro_rules! vmstate_validate {
381 field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),
382 flags: $crate::bindings::VMStateFlags(
383 $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0
384 - | $crate::bindings::VMStateFlags::VMS_ARRAY.0,
384 + | $crate::bindings::VMStateFlags::VMS_NO_STATE.0,
385 ),
386 num: 0, // 0 elements: no data, only run test_fn callback
387 ..::common::zeroable::Zeroable::ZERO
rust/tests/tests/vmstate_tests.rs
+1 -1
@@ -461,7 +461,7 @@ fn test_vmstate_validate() {
461 assert_eq!(foo_fields[0].num, 0);
462 assert_eq!(
463 foo_fields[0].flags.0,
464 - VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_MUST_EXIST.0
464 + VMStateFlags::VMS_NO_STATE.0 | VMStateFlags::VMS_MUST_EXIST.0
465 );
466 assert!(foo_fields[0].vmsd.is_null());
467 assert!(unsafe { foo_fields[0].field_exists.unwrap()(foo_d_p, 0) });