1
2
3
4
5
6
7
8
9
10
11
12
13#include "qemu/osdep.h"
14#include "migration.h"
15#include "migration/vmstate.h"
16#include "savevm.h"
17#include "qapi/qmp/json-writer.h"
18#include "qemu-file.h"
19#include "qemu/bitops.h"
20#include "qemu/error-report.h"
21#include "trace.h"
22
23static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
24 void *opaque, JSONWriter *vmdesc);
25static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
26 void *opaque);
27
28static int vmstate_n_elems(void *opaque, const VMStateField *field)
29{
30 int n_elems = 1;
31
32 if (field->flags & VMS_ARRAY) {
33 n_elems = field->num;
34 } else if (field->flags & VMS_VARRAY_INT32) {
35 n_elems = *(int32_t *)(opaque + field->num_offset);
36 } else if (field->flags & VMS_VARRAY_UINT32) {
37 n_elems = *(uint32_t *)(opaque + field->num_offset);
38 } else if (field->flags & VMS_VARRAY_UINT16) {
39 n_elems = *(uint16_t *)(opaque + field->num_offset);
40 } else if (field->flags & VMS_VARRAY_UINT8) {
41 n_elems = *(uint8_t *)(opaque + field->num_offset);
42 }
43
44 if (field->flags & VMS_MULTIPLY_ELEMENTS) {
45 n_elems *= field->num;
46 }
47
48 trace_vmstate_n_elems(field->name, n_elems);
49 return n_elems;
50}
51
52static int vmstate_size(void *opaque, const VMStateField *field)
53{
54 int size = field->size;
55
56 if (field->flags & VMS_VBUFFER) {
57 size = *(int32_t *)(opaque + field->size_offset);
58 if (field->flags & VMS_MULTIPLY) {
59 size *= field->size;
60 }
61 }
62
63 return size;
64}
65
66static void vmstate_handle_alloc(void *ptr, const VMStateField *field,
67 void *opaque)
68{
69 if (field->flags & VMS_POINTER && field->flags & VMS_ALLOC) {
70 gsize size = vmstate_size(opaque, field);
71 size *= vmstate_n_elems(opaque, field);
72 if (size) {
73 *(void **)ptr = g_malloc(size);
74 }
75 }
76}
77
78int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
79 void *opaque, int version_id)
80{
81 const VMStateField *field = vmsd->fields;
82 int ret = 0;
83
84 trace_vmstate_load_state(vmsd->name, version_id);
85 if (version_id > vmsd->version_id) {
86 error_report("%s: incoming version_id %d is too new "
87 "for local version_id %d",
88 vmsd->name, version_id, vmsd->version_id);
89 trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
90 return -EINVAL;
91 }
92 if (version_id < vmsd->minimum_version_id) {
93 error_report("%s: incoming version_id %d is too old "
94 "for local minimum version_id %d",
95 vmsd->name, version_id, vmsd->minimum_version_id);
96 trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
97 return -EINVAL;
98 }
99 if (vmsd->pre_load) {
100 int ret = vmsd->pre_load(opaque);
101 if (ret) {
102 return ret;
103 }
104 }
105 while (field->name) {
106 trace_vmstate_load_state_field(vmsd->name, field->name);
107 if ((field->field_exists &&
108 field->field_exists(opaque, version_id)) ||
109 (!field->field_exists &&
110 field->version_id <= version_id)) {
111 void *first_elem = opaque + field->offset;
112 int i, n_elems = vmstate_n_elems(opaque, field);
113 int size = vmstate_size(opaque, field);
114
115 vmstate_handle_alloc(first_elem, field, opaque);
116 if (field->flags & VMS_POINTER) {
117 first_elem = *(void **)first_elem;
118 assert(first_elem || !n_elems || !size);
119 }
120 for (i = 0; i < n_elems; i++) {
121 void *curr_elem = first_elem + size * i;
122
123 if (field->flags & VMS_ARRAY_OF_POINTER) {
124 curr_elem = *(void **)curr_elem;
125 }
126 if (!curr_elem && size) {
127
128 assert(field->flags & VMS_ARRAY_OF_POINTER);
129 ret = vmstate_info_nullptr.get(f, curr_elem, size, NULL);
130 } else if (field->flags & VMS_STRUCT) {
131 ret = vmstate_load_state(f, field->vmsd, curr_elem,
132 field->vmsd->version_id);
133 } else if (field->flags & VMS_VSTRUCT) {
134 ret = vmstate_load_state(f, field->vmsd, curr_elem,
135 field->struct_version_id);
136 } else {
137 ret = field->info->get(f, curr_elem, size, field);
138 }
139 if (ret >= 0) {
140 ret = qemu_file_get_error(f);
141 }
142 if (ret < 0) {
143 qemu_file_set_error(f, ret);
144 error_report("Failed to load %s:%s", vmsd->name,
145 field->name);
146 trace_vmstate_load_field_error(field->name, ret);
147 return ret;
148 }
149 }
150 } else if (field->flags & VMS_MUST_EXIST) {
151 error_report("Input validation failed: %s/%s",
152 vmsd->name, field->name);
153 return -1;
154 }
155 field++;
156 }
157 ret = vmstate_subsection_load(f, vmsd, opaque);
158 if (ret != 0) {
159 return ret;
160 }
161 if (vmsd->post_load) {
162 ret = vmsd->post_load(opaque, version_id);
163 }
164 trace_vmstate_load_state_end(vmsd->name, "end", ret);
165 return ret;
166}
167
168static int vmfield_name_num(const VMStateField *start,
169 const VMStateField *search)
170{
171 const VMStateField *field;
172 int found = 0;
173
174 for (field = start; field->name; field++) {
175 if (!strcmp(field->name, search->name)) {
176 if (field == search) {
177 return found;
178 }
179 found++;
180 }
181 }
182
183 return -1;
184}
185
186static bool vmfield_name_is_unique(const VMStateField *start,
187 const VMStateField *search)
188{
189 const VMStateField *field;
190 int found = 0;
191
192 for (field = start; field->name; field++) {
193 if (!strcmp(field->name, search->name)) {
194 found++;
195
196 if (found > 1) {
197 return false;
198 }
199 }
200 }
201
202 return true;
203}
204
205static const char *vmfield_get_type_name(const VMStateField *field)
206{
207 const char *type = "unknown";
208
209 if (field->flags & VMS_STRUCT) {
210 type = "struct";
211 } else if (field->flags & VMS_VSTRUCT) {
212 type = "vstruct";
213 } else if (field->info->name) {
214 type = field->info->name;
215 }
216
217 return type;
218}
219
220static bool vmsd_can_compress(const VMStateField *field)
221{
222 if (field->field_exists) {
223
224 return false;
225 }
226
227 if (field->flags & VMS_STRUCT) {
228 const VMStateField *sfield = field->vmsd->fields;
229 while (sfield->name) {
230 if (!vmsd_can_compress(sfield)) {
231
232 return false;
233 }
234 sfield++;
235 }
236
237 if (field->vmsd->subsections) {
238
239 return false;
240 }
241 }
242
243 return true;
244}
245
246static void vmsd_desc_field_start(const VMStateDescription *vmsd,
247 JSONWriter *vmdesc,
248 const VMStateField *field, int i, int max)
249{
250 char *name, *old_name;
251 bool is_array = max > 1;
252 bool can_compress = vmsd_can_compress(field);
253
254 if (!vmdesc) {
255 return;
256 }
257
258 name = g_strdup(field->name);
259
260
261 if (!vmfield_name_is_unique(vmsd->fields, field)) {
262 int num = vmfield_name_num(vmsd->fields, field);
263 old_name = name;
264 name = g_strdup_printf("%s[%d]", name, num);
265 g_free(old_name);
266 }
267
268 json_writer_start_object(vmdesc, NULL);
269 json_writer_str(vmdesc, "name", name);
270 if (is_array) {
271 if (can_compress) {
272 json_writer_int64(vmdesc, "array_len", max);
273 } else {
274 json_writer_int64(vmdesc, "index", i);
275 }
276 }
277 json_writer_str(vmdesc, "type", vmfield_get_type_name(field));
278
279 if (field->flags & VMS_STRUCT) {
280 json_writer_start_object(vmdesc, "struct");
281 }
282
283 g_free(name);
284}
285
286static void vmsd_desc_field_end(const VMStateDescription *vmsd,
287 JSONWriter *vmdesc,
288 const VMStateField *field, size_t size, int i)
289{
290 if (!vmdesc) {
291 return;
292 }
293
294 if (field->flags & VMS_STRUCT) {
295
296 json_writer_end_object(vmdesc);
297 }
298
299 json_writer_int64(vmdesc, "size", size);
300 json_writer_end_object(vmdesc);
301}
302
303
304bool vmstate_save_needed(const VMStateDescription *vmsd, void *opaque)
305{
306 if (vmsd->needed && !vmsd->needed(opaque)) {
307
308 return false;
309 }
310 return true;
311}
312
313
314int vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
315 void *opaque, JSONWriter *vmdesc_id)
316{
317 return vmstate_save_state_v(f, vmsd, opaque, vmdesc_id, vmsd->version_id);
318}
319
320int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd,
321 void *opaque, JSONWriter *vmdesc, int version_id)
322{
323 int ret = 0;
324 const VMStateField *field = vmsd->fields;
325
326 trace_vmstate_save_state_top(vmsd->name);
327
328 if (vmsd->pre_save) {
329 ret = vmsd->pre_save(opaque);
330 trace_vmstate_save_state_pre_save_res(vmsd->name, ret);
331 if (ret) {
332 error_report("pre-save failed: %s", vmsd->name);
333 return ret;
334 }
335 }
336
337 if (vmdesc) {
338 json_writer_str(vmdesc, "vmsd_name", vmsd->name);
339 json_writer_int64(vmdesc, "version", version_id);
340 json_writer_start_array(vmdesc, "fields");
341 }
342
343 while (field->name) {
344 if ((field->field_exists &&
345 field->field_exists(opaque, version_id)) ||
346 (!field->field_exists &&
347 field->version_id <= version_id)) {
348 void *first_elem = opaque + field->offset;
349 int i, n_elems = vmstate_n_elems(opaque, field);
350 int size = vmstate_size(opaque, field);
351 int64_t old_offset, written_bytes;
352 JSONWriter *vmdesc_loop = vmdesc;
353
354 trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems);
355 if (field->flags & VMS_POINTER) {
356 first_elem = *(void **)first_elem;
357 assert(first_elem || !n_elems || !size);
358 }
359 for (i = 0; i < n_elems; i++) {
360 void *curr_elem = first_elem + size * i;
361
362 vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems);
363 old_offset = qemu_file_total_transferred_fast(f);
364 if (field->flags & VMS_ARRAY_OF_POINTER) {
365 assert(curr_elem);
366 curr_elem = *(void **)curr_elem;
367 }
368 if (!curr_elem && size) {
369
370 assert(field->flags & VMS_ARRAY_OF_POINTER);
371 ret = vmstate_info_nullptr.put(f, curr_elem, size, NULL,
372 NULL);
373 } else if (field->flags & VMS_STRUCT) {
374 ret = vmstate_save_state(f, field->vmsd, curr_elem,
375 vmdesc_loop);
376 } else if (field->flags & VMS_VSTRUCT) {
377 ret = vmstate_save_state_v(f, field->vmsd, curr_elem,
378 vmdesc_loop,
379 field->struct_version_id);
380 } else {
381 ret = field->info->put(f, curr_elem, size, field,
382 vmdesc_loop);
383 }
384 if (ret) {
385 error_report("Save of field %s/%s failed",
386 vmsd->name, field->name);
387 if (vmsd->post_save) {
388 vmsd->post_save(opaque);
389 }
390 return ret;
391 }
392
393 written_bytes = qemu_file_total_transferred_fast(f) -
394 old_offset;
395 vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i);
396
397
398 if (vmdesc_loop && vmsd_can_compress(field)) {
399 vmdesc_loop = NULL;
400 }
401 }
402 } else {
403 if (field->flags & VMS_MUST_EXIST) {
404 error_report("Output state validation failed: %s/%s",
405 vmsd->name, field->name);
406 assert(!(field->flags & VMS_MUST_EXIST));
407 }
408 }
409 field++;
410 }
411
412 if (vmdesc) {
413 json_writer_end_array(vmdesc);
414 }
415
416 ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc);
417
418 if (vmsd->post_save) {
419 int ps_ret = vmsd->post_save(opaque);
420 if (!ret) {
421 ret = ps_ret;
422 }
423 }
424 return ret;
425}
426
427static const VMStateDescription *
428vmstate_get_subsection(const VMStateDescription **sub, char *idstr)
429{
430 while (sub && *sub) {
431 if (strcmp(idstr, (*sub)->name) == 0) {
432 return *sub;
433 }
434 sub++;
435 }
436 return NULL;
437}
438
439static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
440 void *opaque)
441{
442 trace_vmstate_subsection_load(vmsd->name);
443
444 while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
445 char idstr[256], *idstr_ret;
446 int ret;
447 uint8_t version_id, len, size;
448 const VMStateDescription *sub_vmsd;
449
450 len = qemu_peek_byte(f, 1);
451 if (len < strlen(vmsd->name) + 1) {
452
453 trace_vmstate_subsection_load_bad(vmsd->name, "(short)", "");
454 return 0;
455 }
456 size = qemu_peek_buffer(f, (uint8_t **)&idstr_ret, len, 2);
457 if (size != len) {
458 trace_vmstate_subsection_load_bad(vmsd->name, "(peek fail)", "");
459 return 0;
460 }
461 memcpy(idstr, idstr_ret, size);
462 idstr[size] = 0;
463
464 if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
465 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(prefix)");
466
467 return 0;
468 }
469 sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
470 if (sub_vmsd == NULL) {
471 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(lookup)");
472 return -ENOENT;
473 }
474 qemu_file_skip(f, 1);
475 qemu_file_skip(f, 1);
476 qemu_file_skip(f, len);
477 version_id = qemu_get_be32(f);
478
479 ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
480 if (ret) {
481 trace_vmstate_subsection_load_bad(vmsd->name, idstr, "(child)");
482 return ret;
483 }
484 }
485
486 trace_vmstate_subsection_load_good(vmsd->name);
487 return 0;
488}
489
490static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
491 void *opaque, JSONWriter *vmdesc)
492{
493 const VMStateDescription **sub = vmsd->subsections;
494 bool vmdesc_has_subsections = false;
495 int ret = 0;
496
497 trace_vmstate_subsection_save_top(vmsd->name);
498 while (sub && *sub) {
499 if (vmstate_save_needed(*sub, opaque)) {
500 const VMStateDescription *vmsdsub = *sub;
501 uint8_t len;
502
503 trace_vmstate_subsection_save_loop(vmsd->name, vmsdsub->name);
504 if (vmdesc) {
505
506 if (!vmdesc_has_subsections) {
507 json_writer_start_array(vmdesc, "subsections");
508 vmdesc_has_subsections = true;
509 }
510
511 json_writer_start_object(vmdesc, NULL);
512 }
513
514 qemu_put_byte(f, QEMU_VM_SUBSECTION);
515 len = strlen(vmsdsub->name);
516 qemu_put_byte(f, len);
517 qemu_put_buffer(f, (uint8_t *)vmsdsub->name, len);
518 qemu_put_be32(f, vmsdsub->version_id);
519 ret = vmstate_save_state(f, vmsdsub, opaque, vmdesc);
520 if (ret) {
521 return ret;
522 }
523
524 if (vmdesc) {
525 json_writer_end_object(vmdesc);
526 }
527 }
528 sub++;
529 }
530
531 if (vmdesc_has_subsections) {
532 json_writer_end_array(vmdesc);
533 }
534
535 return ret;
536}
537