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) });