153
return true;
154
}
155
156
+ if (byte == VMS_MARKER_PTR_VALID) {
157
+ /* We need to load the field right after the marker */
158
+ *load_field = true;
159
+ return true;
160
+ }
161
+
162
error_setg(errp, "Unexpected ptr marker: %d", byte);
163
return false;
164
}
240
return true;
241
}
242
243
+/*
244
+ * Try to prepare loading the next element, the object pointer to be put
245
+ * into @next_elem. When @next_elem is NULL, it means we should skip
246
+ * loading this element.
247
+ *
248
+ * Returns false for errors, in which case *errp will be set, migration
249
+ * must be aborted.
250
+ */
251
+static bool vmstate_load_next(QEMUFile *f, const VMStateField *field,
252
+ void *first_elem, void **next_elem,
253
+ int size, int i, Error **errp)
254
+{
255
+ bool auto_alloc = field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
256
+ void *ptr = first_elem + size * i, **pptr;
257
+ bool load_field;
258
+
259
+ if (!(field->flags & VMS_ARRAY_OF_POINTER)) {
260
+ /* Simplest case, no pointer involved */
261
+ *next_elem = ptr;
262
+ return true;
263
+ }
264
+
265
+ /*
266
+ * We're loading an array of pointers, switch to use pptr to make it
267
+ * easier to read later
268
+ */
269
+ pptr = (void **)ptr;
270
+
271
+ /*
272
+ * If auto_alloc is on, making sure the user provided an array of NULL
273
+ * pointers to start with
274
+ */
275
+ assert(!auto_alloc || *pptr == NULL);
276
+
277
+ /*
278
+ * When pointer is null, we must expect a ptr marker first. Use cases:
279
+ *
280
+ * (1) _AUTO_ALLOC implies a ptr marker will always exist, or,
281
+ *
282
+ * (2) the element on destination is NULL, which expects the src to send a
283
+ * NULL-only marker.
284
+ *
285
+ * Here, checking against a NULL pointer will work for both.
286
+ */
287
+ if (!*pptr) {
288
+ if (!vmstate_ptr_marker_load(f, &load_field, errp)) {
289
+ trace_vmstate_load_field_error(field->name, -EINVAL);
290
+ return false;
291
+ }
292
+
293
+ /*
294
+ * If loading is needed, do pre-allocation first (otherwise keeping
295
+ * *pptr==NULL to imply a skip below)
296
+ */
297
+ if (load_field) {
298
+ /* Only applies when auto_alloc=on on the field */
299
+ assert(auto_alloc);
300
+ /*
301
+ * NOTE: do not use vmstate_size() here, because we need the
302
+ * object size, not entry size of the array.
303
+ */
304
+ *pptr = g_malloc0(field->size);
305
+ }
306
+ }
307
+
308
+ /* Move the cursor to the next element for loading */
309
+ *next_elem = *pptr;
310
+ return true;
311
+}
312
+
313
bool vmstate_load_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
314
void *opaque, int version_id, Error **errp)
315
{
355
}
356
357
for (i = 0; i < n_elems; i++) {
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;
358
+ void *curr_elem;
359
+ bool ok;
360
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
- }
361
+ ok = vmstate_load_next(f, field, first_elem, &curr_elem,
362
+ size, i, errp);
363
+ if (!ok) {
364
+ return false;
365
}
366
299
- if (load_field) {
300
- ok = vmstate_load_field(f, curr_elem, size, field, errp);
367
+ if (!curr_elem) {
368
+ /* Implies a skip */
369
+ continue;
370
}
371
372
+ ok = vmstate_load_field(f, curr_elem, size, field, errp);
373
+
374
if (ok) {
375
int ret = qemu_file_get_error(f);
376
if (ret < 0) {
468
return false;
469
}
470
471
+ if (field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC) {
472
+ /*
473
+ * This may involve two VMSD fields to be saved, one for the
474
+ * marker to show if the pointer is NULL, followed by the real
475
+ * vmstate object. To make it simple at least for now, skip
476
+ * compression for this one.
477
+ */
478
+ return false;
479
+ }
480
+
481
if (field->flags & VMS_STRUCT) {
482
const VMStateField *sfield = field->vmsd->fields;
483
while (sfield->name) {
664
int size = vmstate_size(opaque, field);
665
JSONWriter *vmdesc_loop = vmdesc;
666
bool is_prev_null = false;
667
+ /*
668
+ * When this is enabled, it means we will always push a ptr
669
+ * marker first for each element saying if it's populated.
670
+ */
671
+ bool use_dynamic_array =
672
+ field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
673
674
trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems);
675
if (field->flags & VMS_POINTER) {
690
}
691
692
is_null = !curr_elem && size;
606
- use_marker_field = is_null;
693
+ use_marker_field = use_dynamic_array || is_null;
694
695
if (use_marker_field) {
609
- /*
610
- * If null pointer found (which should only happen in
611
- * an array of pointers), use null placeholder and do
612
- * not follow.
613
- */
696
inner_field = vmsd_create_ptr_marker_field(field);
697
} else {
698
inner_field = field;
739
goto out;
740
}
741
742
+ /*
743
+ * If we're using dynamic array and the element is
744
+ * populated, save the real object right after the marker.
745
+ */
746
+ if (use_dynamic_array && curr_elem) {
747
+ /*
748
+ * NOTE: do not use vmstate_size() here because we want
749
+ * to save the real VMSD object now.
750
+ */
751
+ ok = vmstate_save_field_with_vmdesc(f, curr_elem,
752
+ field->size, vmsd,
753
+ field, vmdesc_loop,
754
+ i, max_elems, errp);
755
+
756
+ if (!ok) {
757
+ goto out;
758
+ }
759
+ }
760
+
761
/* Compressed arrays only care about the first element */
762
if (vmdesc_loop && max_elems > 1) {
763
vmdesc_loop = NULL;