@samitouri / QOSamiQemu / commits / 69c6d694bc

vmstate: Implement load of ptr marker in vmstate core

The loader side of ptr marker is pretty straightforward, instead of playing the inner_field trick, just do the load manually assuming the marker layout is a stable ABI (which it is true already). This will remove some logic while loading VMSD, and hopefully it makes it slightly easier to read. Unfortunately, we still need to keep the sender side because of the JSON blob we're maintaining.. This paves way for future processing of non-NULL markers as well. When at it, not check "size" anymore for existing NULL markers, and move it under the same VMS_ARRAY_OF_POINTER section because that's the only place that NULL marker can happen (which guarantess size==host ptr size, which is non-zero). Reviewed-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io> Signed-off-by: Peter Xu <peterx@redhat.com> Reviewed-by: Juraj Marcin <jmarcin@redhat.com> Link: https://lore.kernel.org/qemu-devel/20260401202844.673494-9-peterx@redhat.com Signed-off-by: Fabiano Rosas <farosas@suse.de>

Peter Xu committed Apr 1, 2026 at 16:28 UTC 69c6d694bc91c3c43c9df713dfff8acb8d154005
2 files changed +32 -26
migration/vmstate-types.c
+4 -8
@@ -363,14 +363,10 @@ static bool load_ptr_marker(QEMUFile *f, void *pv, size_t size,
363 const VMStateField *field, Error **errp)
364
365 {
366 - int byte = qemu_get_byte(f);
367 -
368 - if (byte == VMS_MARKER_PTR_NULL || byte == VMS_MARKER_PTR_VALID) {
369 - /* TODO: process PTR_VALID case */
370 - return true;
371 - }
372 -
373 - error_setg(errp, "%s: unexpected ptr marker: %d", __func__, byte);
366 + /*
367 + * Load is done in vmstate core, see vmstate_ptr_marker_load().
368 + */
369 + g_assert_not_reached();
370 return false;
371 }
372
migration/vmstate.c
+28 -18
@@ -142,6 +142,21 @@ static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
142 }
143 }
144
145 +static bool vmstate_ptr_marker_load(QEMUFile *f, bool *load_field,
146 + Error **errp)
147 +{
148 + int byte = qemu_get_byte(f);
149 +
150 + if (byte == VMS_MARKER_PTR_NULL) {
151 + /* When it's a null ptr marker, do not continue the load */
152 + *load_field = false;
153 + return true;
154 + }
155 +
156 + error_setg(errp, "Unexpected ptr marker: %d", byte);
157 + return false;
158 +}
159 +
160 static bool vmstate_pre_load(const VMStateDescription *vmsd, void *opaque,
161 Error **errp)
162 {
@@ -264,30 +279,25 @@ bool vmstate_load_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
279 }
280
281 for (i = 0; i < n_elems; i++) {
267 - bool ok;
282 + /* If we will process the load of field? */
283 + bool load_field = true;
284 + bool ok = true;
285 void *curr_elem = first_elem + size * i;
269 - const VMStateField *inner_field;
286
287 if (field->flags & VMS_ARRAY_OF_POINTER) {
288 curr_elem = *(void **)curr_elem;
289 + if (!curr_elem) {
290 + /* Read the marker instead of VMSD itself */
291 + if (!vmstate_ptr_marker_load(f, &load_field, errp)) {
292 + trace_vmstate_load_field_error(field->name,
293 + -EINVAL);
294 + return false;
295 + }
296 + }
297 }
298
275 - if (!curr_elem && size) {
276 - /*
277 - * If null pointer found (which should only happen in
278 - * an array of pointers), use null placeholder and do
279 - * not follow.
280 - */
281 - inner_field = vmsd_create_ptr_marker_field(field);
282 - } else {
283 - inner_field = field;
284 - }
285 -
286 - ok = vmstate_load_field(f, curr_elem, size, inner_field, errp);
287 -
288 - /* If we used a fake temp field.. free it now */
289 - if (inner_field != field) {
290 - g_clear_pointer((gpointer *)&inner_field, g_free);
299 + if (load_field) {
300 + ok = vmstate_load_field(f, curr_elem, size, field, errp);
301 }
302
303 if (ok) {