Commit 797b88eddd for qemu.org
commit 797b88eddd7066febfb103b7d48ed8b6a693c06b
Author: Fabiano Rosas <farosas@suse.de>
Date: Tue Aug 18 15:24:38 2026 -0300
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>
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 1b23eaf100..adf76b5bcc 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 deb43d5560..aa02ff631b 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 4b6d52955f..e72c3fae9a 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 9556030f89..1f9cb45923 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -110,12 +110,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 45c0b52738..5ed061f2ab 100644
--- a/rust/migration/src/vmstate.rs
+++ b/rust/migration/src/vmstate.rs
@@ -381,7 +381,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 5f6dd8ae7f..6578d54b37 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) });