1 /*
2 * VMStateInfo's for basic typse
3 *
4 * Copyright (c) 2009-2017 Red Hat Inc
5 *
6 * Authors:
7 * Juan Quintela <quintela@redhat.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 */
12
13 #include "qemu/osdep.h"
14 #include "qemu/cpu-float.h"
15 #include "qemu-file.h"
16 #include "migration.h"
17 #include "migration/vmstate.h"
18 #include "migration/client-options.h"
19 #include "qemu/error-report.h"
20 #include "qemu/queue.h"
21 #include "trace.h"
22
23 /* bool */
24
get_bool(QEMUFile * f,void * pv,size_t size,const VMStateField * field)25 static int get_bool(QEMUFile *f, void *pv, size_t size,
26 const VMStateField *field)
27 {
28 bool *v = pv;
29 *v = qemu_get_byte(f);
30 return 0;
31 }
32
put_bool(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)33 static int put_bool(QEMUFile *f, void *pv, size_t size,
34 const VMStateField *field, JSONWriter *vmdesc)
35 {
36 bool *v = pv;
37 qemu_put_byte(f, *v);
38 return 0;
39 }
40
41 const VMStateInfo vmstate_info_bool = {
42 .name = "bool",
43 .get = get_bool,
44 .put = put_bool,
45 };
46
47 /* 8 bit int */
48
get_int8(QEMUFile * f,void * pv,size_t size,const VMStateField * field)49 static int get_int8(QEMUFile *f, void *pv, size_t size,
50 const VMStateField *field)
51 {
52 int8_t *v = pv;
53 qemu_get_s8s(f, v);
54 return 0;
55 }
56
put_int8(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)57 static int put_int8(QEMUFile *f, void *pv, size_t size,
58 const VMStateField *field, JSONWriter *vmdesc)
59 {
60 int8_t *v = pv;
61 qemu_put_s8s(f, v);
62 return 0;
63 }
64
65 const VMStateInfo vmstate_info_int8 = {
66 .name = "int8",
67 .get = get_int8,
68 .put = put_int8,
69 };
70
71 /* 16 bit int */
72
get_int16(QEMUFile * f,void * pv,size_t size,const VMStateField * field)73 static int get_int16(QEMUFile *f, void *pv, size_t size,
74 const VMStateField *field)
75 {
76 int16_t *v = pv;
77 qemu_get_sbe16s(f, v);
78 return 0;
79 }
80
put_int16(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)81 static int put_int16(QEMUFile *f, void *pv, size_t size,
82 const VMStateField *field, JSONWriter *vmdesc)
83 {
84 int16_t *v = pv;
85 qemu_put_sbe16s(f, v);
86 return 0;
87 }
88
89 const VMStateInfo vmstate_info_int16 = {
90 .name = "int16",
91 .get = get_int16,
92 .put = put_int16,
93 };
94
95 /* 32 bit int */
96
get_int32(QEMUFile * f,void * pv,size_t size,const VMStateField * field)97 static int get_int32(QEMUFile *f, void *pv, size_t size,
98 const VMStateField *field)
99 {
100 int32_t *v = pv;
101 qemu_get_sbe32s(f, v);
102 return 0;
103 }
104
put_int32(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)105 static int put_int32(QEMUFile *f, void *pv, size_t size,
106 const VMStateField *field, JSONWriter *vmdesc)
107 {
108 int32_t *v = pv;
109 qemu_put_sbe32s(f, v);
110 return 0;
111 }
112
113 const VMStateInfo vmstate_info_int32 = {
114 .name = "int32",
115 .get = get_int32,
116 .put = put_int32,
117 };
118
119 /* 32 bit int. See that the received value is the same than the one
120 in the field */
121
get_int32_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)122 static int get_int32_equal(QEMUFile *f, void *pv, size_t size,
123 const VMStateField *field)
124 {
125 int32_t *v = pv;
126 int32_t v2;
127 qemu_get_sbe32s(f, &v2);
128
129 if (*v == v2) {
130 return 0;
131 }
132 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
133 if (field->err_hint) {
134 error_printf("%s\n", field->err_hint);
135 }
136 return -EINVAL;
137 }
138
139 const VMStateInfo vmstate_info_int32_equal = {
140 .name = "int32 equal",
141 .get = get_int32_equal,
142 .put = put_int32,
143 };
144
145 /* 32 bit int. Check that the received value is non-negative
146 * and less than or equal to the one in the field.
147 */
148
get_int32_le(QEMUFile * f,void * pv,size_t size,const VMStateField * field)149 static int get_int32_le(QEMUFile *f, void *pv, size_t size,
150 const VMStateField *field)
151 {
152 int32_t *cur = pv;
153 int32_t loaded;
154 qemu_get_sbe32s(f, &loaded);
155
156 if (loaded >= 0 && loaded <= *cur) {
157 *cur = loaded;
158 return 0;
159 }
160 error_report("Invalid value %" PRId32
161 " expecting positive value <= %" PRId32,
162 loaded, *cur);
163 return -EINVAL;
164 }
165
166 const VMStateInfo vmstate_info_int32_le = {
167 .name = "int32 le",
168 .get = get_int32_le,
169 .put = put_int32,
170 };
171
172 /* 64 bit int */
173
get_int64(QEMUFile * f,void * pv,size_t size,const VMStateField * field)174 static int get_int64(QEMUFile *f, void *pv, size_t size,
175 const VMStateField *field)
176 {
177 int64_t *v = pv;
178 qemu_get_sbe64s(f, v);
179 return 0;
180 }
181
put_int64(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)182 static int put_int64(QEMUFile *f, void *pv, size_t size,
183 const VMStateField *field, JSONWriter *vmdesc)
184 {
185 int64_t *v = pv;
186 qemu_put_sbe64s(f, v);
187 return 0;
188 }
189
190 const VMStateInfo vmstate_info_int64 = {
191 .name = "int64",
192 .get = get_int64,
193 .put = put_int64,
194 };
195
196 /* 8 bit unsigned int */
197
get_uint8(QEMUFile * f,void * pv,size_t size,const VMStateField * field)198 static int get_uint8(QEMUFile *f, void *pv, size_t size,
199 const VMStateField *field)
200 {
201 uint8_t *v = pv;
202 qemu_get_8s(f, v);
203 return 0;
204 }
205
put_uint8(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)206 static int put_uint8(QEMUFile *f, void *pv, size_t size,
207 const VMStateField *field, JSONWriter *vmdesc)
208 {
209 uint8_t *v = pv;
210 qemu_put_8s(f, v);
211 return 0;
212 }
213
214 const VMStateInfo vmstate_info_uint8 = {
215 .name = "uint8",
216 .get = get_uint8,
217 .put = put_uint8,
218 };
219
220 /* 16 bit unsigned int */
221
get_uint16(QEMUFile * f,void * pv,size_t size,const VMStateField * field)222 static int get_uint16(QEMUFile *f, void *pv, size_t size,
223 const VMStateField *field)
224 {
225 uint16_t *v = pv;
226 qemu_get_be16s(f, v);
227 return 0;
228 }
229
put_uint16(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)230 static int put_uint16(QEMUFile *f, void *pv, size_t size,
231 const VMStateField *field, JSONWriter *vmdesc)
232 {
233 uint16_t *v = pv;
234 qemu_put_be16s(f, v);
235 return 0;
236 }
237
238 const VMStateInfo vmstate_info_uint16 = {
239 .name = "uint16",
240 .get = get_uint16,
241 .put = put_uint16,
242 };
243
244 /* 32 bit unsigned int */
245
get_uint32(QEMUFile * f,void * pv,size_t size,const VMStateField * field)246 static int get_uint32(QEMUFile *f, void *pv, size_t size,
247 const VMStateField *field)
248 {
249 uint32_t *v = pv;
250 qemu_get_be32s(f, v);
251 return 0;
252 }
253
put_uint32(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)254 static int put_uint32(QEMUFile *f, void *pv, size_t size,
255 const VMStateField *field, JSONWriter *vmdesc)
256 {
257 uint32_t *v = pv;
258 qemu_put_be32s(f, v);
259 return 0;
260 }
261
262 const VMStateInfo vmstate_info_uint32 = {
263 .name = "uint32",
264 .get = get_uint32,
265 .put = put_uint32,
266 };
267
268 /* 32 bit uint. See that the received value is the same than the one
269 in the field */
270
get_uint32_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)271 static int get_uint32_equal(QEMUFile *f, void *pv, size_t size,
272 const VMStateField *field)
273 {
274 uint32_t *v = pv;
275 uint32_t v2;
276 qemu_get_be32s(f, &v2);
277
278 if (*v == v2) {
279 return 0;
280 }
281 error_report("%" PRIx32 " != %" PRIx32, *v, v2);
282 if (field->err_hint) {
283 error_printf("%s\n", field->err_hint);
284 }
285 return -EINVAL;
286 }
287
288 const VMStateInfo vmstate_info_uint32_equal = {
289 .name = "uint32 equal",
290 .get = get_uint32_equal,
291 .put = put_uint32,
292 };
293
294 /* 64 bit unsigned int */
295
get_uint64(QEMUFile * f,void * pv,size_t size,const VMStateField * field)296 static int get_uint64(QEMUFile *f, void *pv, size_t size,
297 const VMStateField *field)
298 {
299 uint64_t *v = pv;
300 qemu_get_be64s(f, v);
301 return 0;
302 }
303
put_uint64(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)304 static int put_uint64(QEMUFile *f, void *pv, size_t size,
305 const VMStateField *field, JSONWriter *vmdesc)
306 {
307 uint64_t *v = pv;
308 qemu_put_be64s(f, v);
309 return 0;
310 }
311
312 const VMStateInfo vmstate_info_uint64 = {
313 .name = "uint64",
314 .get = get_uint64,
315 .put = put_uint64,
316 };
317
318 /* File descriptor communicated via SCM_RIGHTS */
319
get_fd(QEMUFile * f,void * pv,size_t size,const VMStateField * field)320 static int get_fd(QEMUFile *f, void *pv, size_t size,
321 const VMStateField *field)
322 {
323 int32_t *v = pv;
324 *v = qemu_file_get_fd(f);
325 return 0;
326 }
327
put_fd(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)328 static int put_fd(QEMUFile *f, void *pv, size_t size,
329 const VMStateField *field, JSONWriter *vmdesc)
330 {
331 int32_t *v = pv;
332 return qemu_file_put_fd(f, *v);
333 }
334
335 const VMStateInfo vmstate_info_fd = {
336 .name = "fd",
337 .get = get_fd,
338 .put = put_fd,
339 };
340
get_nullptr(QEMUFile * f,void * pv,size_t size,const VMStateField * field)341 static int get_nullptr(QEMUFile *f, void *pv, size_t size,
342 const VMStateField *field)
343
344 {
345 if (qemu_get_byte(f) == VMS_NULLPTR_MARKER) {
346 return 0;
347 }
348 error_report("vmstate: get_nullptr expected VMS_NULLPTR_MARKER");
349 return -EINVAL;
350 }
351
put_nullptr(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)352 static int put_nullptr(QEMUFile *f, void *pv, size_t size,
353 const VMStateField *field, JSONWriter *vmdesc)
354
355 {
356 if (pv == NULL) {
357 qemu_put_byte(f, VMS_NULLPTR_MARKER);
358 return 0;
359 }
360 error_report("vmstate: put_nullptr must be called with pv == NULL");
361 return -EINVAL;
362 }
363
364 const VMStateInfo vmstate_info_nullptr = {
365 .name = "nullptr",
366 .get = get_nullptr,
367 .put = put_nullptr,
368 };
369
370 /* 64 bit unsigned int. See that the received value is the same than the one
371 in the field */
372
get_uint64_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)373 static int get_uint64_equal(QEMUFile *f, void *pv, size_t size,
374 const VMStateField *field)
375 {
376 uint64_t *v = pv;
377 uint64_t v2;
378 qemu_get_be64s(f, &v2);
379
380 if (*v == v2) {
381 return 0;
382 }
383 error_report("%" PRIx64 " != %" PRIx64, *v, v2);
384 if (field->err_hint) {
385 error_printf("%s\n", field->err_hint);
386 }
387 return -EINVAL;
388 }
389
390 const VMStateInfo vmstate_info_uint64_equal = {
391 .name = "int64 equal",
392 .get = get_uint64_equal,
393 .put = put_uint64,
394 };
395
396 /* 8 bit int. See that the received value is the same than the one
397 in the field */
398
get_uint8_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)399 static int get_uint8_equal(QEMUFile *f, void *pv, size_t size,
400 const VMStateField *field)
401 {
402 uint8_t *v = pv;
403 uint8_t v2;
404 qemu_get_8s(f, &v2);
405
406 if (*v == v2) {
407 return 0;
408 }
409 error_report("%x != %x", *v, v2);
410 if (field->err_hint) {
411 error_printf("%s\n", field->err_hint);
412 }
413 return -EINVAL;
414 }
415
416 const VMStateInfo vmstate_info_uint8_equal = {
417 .name = "uint8 equal",
418 .get = get_uint8_equal,
419 .put = put_uint8,
420 };
421
422 /* 16 bit unsigned int int. See that the received value is the same than the one
423 in the field */
424
get_uint16_equal(QEMUFile * f,void * pv,size_t size,const VMStateField * field)425 static int get_uint16_equal(QEMUFile *f, void *pv, size_t size,
426 const VMStateField *field)
427 {
428 uint16_t *v = pv;
429 uint16_t v2;
430 qemu_get_be16s(f, &v2);
431
432 if (*v == v2) {
433 return 0;
434 }
435 error_report("%x != %x", *v, v2);
436 if (field->err_hint) {
437 error_printf("%s\n", field->err_hint);
438 }
439 return -EINVAL;
440 }
441
442 const VMStateInfo vmstate_info_uint16_equal = {
443 .name = "uint16 equal",
444 .get = get_uint16_equal,
445 .put = put_uint16,
446 };
447
448 /* CPU_DoubleU type */
449
get_cpudouble(QEMUFile * f,void * pv,size_t size,const VMStateField * field)450 static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
451 const VMStateField *field)
452 {
453 CPU_DoubleU *v = pv;
454 qemu_get_be32s(f, &v->l.upper);
455 qemu_get_be32s(f, &v->l.lower);
456 return 0;
457 }
458
put_cpudouble(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)459 static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
460 const VMStateField *field, JSONWriter *vmdesc)
461 {
462 CPU_DoubleU *v = pv;
463 qemu_put_be32s(f, &v->l.upper);
464 qemu_put_be32s(f, &v->l.lower);
465 return 0;
466 }
467
468 const VMStateInfo vmstate_info_cpudouble = {
469 .name = "CPU_Double_U",
470 .get = get_cpudouble,
471 .put = put_cpudouble,
472 };
473
474 /* uint8_t buffers */
475
get_buffer(QEMUFile * f,void * pv,size_t size,const VMStateField * field)476 static int get_buffer(QEMUFile *f, void *pv, size_t size,
477 const VMStateField *field)
478 {
479 uint8_t *v = pv;
480 qemu_get_buffer(f, v, size);
481 return 0;
482 }
483
put_buffer(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)484 static int put_buffer(QEMUFile *f, void *pv, size_t size,
485 const VMStateField *field, JSONWriter *vmdesc)
486 {
487 uint8_t *v = pv;
488 qemu_put_buffer(f, v, size);
489 return 0;
490 }
491
492 const VMStateInfo vmstate_info_buffer = {
493 .name = "buffer",
494 .get = get_buffer,
495 .put = put_buffer,
496 };
497
498 /* unused buffers: space that was used for some fields that are
499 not useful anymore */
500
get_unused_buffer(QEMUFile * f,void * pv,size_t size,const VMStateField * field)501 static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
502 const VMStateField *field)
503 {
504 uint8_t buf[1024];
505 int block_len;
506
507 while (size > 0) {
508 block_len = MIN(sizeof(buf), size);
509 size -= block_len;
510 qemu_get_buffer(f, buf, block_len);
511 }
512 return 0;
513 }
514
put_unused_buffer(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)515 static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
516 const VMStateField *field, JSONWriter *vmdesc)
517 {
518 static const uint8_t buf[1024];
519 int block_len;
520
521 while (size > 0) {
522 block_len = MIN(sizeof(buf), size);
523 size -= block_len;
524 qemu_put_buffer(f, buf, block_len);
525 }
526
527 return 0;
528 }
529
530 const VMStateInfo vmstate_info_unused_buffer = {
531 .name = "unused_buffer",
532 .get = get_unused_buffer,
533 .put = put_unused_buffer,
534 };
535
536 /* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
537 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
538 * copy stuff from the parent into the child and do calculations to fill
539 * in fields that don't really exist in the parent but need to be in the
540 * stream.
541 */
get_tmp(QEMUFile * f,void * pv,size_t size,const VMStateField * field)542 static int get_tmp(QEMUFile *f, void *pv, size_t size,
543 const VMStateField *field)
544 {
545 int ret;
546 const VMStateDescription *vmsd = field->vmsd;
547 int version_id = field->version_id;
548 void *tmp = g_malloc(size);
549
550 /* Writes the parent field which is at the start of the tmp */
551 *(void **)tmp = pv;
552 ret = vmstate_load_state(f, vmsd, tmp, version_id);
553 g_free(tmp);
554 return ret;
555 }
556
put_tmp(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)557 static int put_tmp(QEMUFile *f, void *pv, size_t size,
558 const VMStateField *field, JSONWriter *vmdesc)
559 {
560 const VMStateDescription *vmsd = field->vmsd;
561 void *tmp = g_malloc(size);
562 int ret;
563
564 /* Writes the parent field which is at the start of the tmp */
565 *(void **)tmp = pv;
566 ret = vmstate_save_state(f, vmsd, tmp, vmdesc);
567 g_free(tmp);
568
569 return ret;
570 }
571
572 const VMStateInfo vmstate_info_tmp = {
573 .name = "tmp",
574 .get = get_tmp,
575 .put = put_tmp,
576 };
577
578 /* bitmaps (as defined by bitmap.h). Note that size here is the size
579 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
580 * bit words with the bits in big endian order. The in-memory format
581 * is an array of 'unsigned long', which may be either 32 or 64 bits.
582 */
583 /* This is the number of 64 bit words sent over the wire */
584 #define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
get_bitmap(QEMUFile * f,void * pv,size_t size,const VMStateField * field)585 static int get_bitmap(QEMUFile *f, void *pv, size_t size,
586 const VMStateField *field)
587 {
588 unsigned long *bmp = pv;
589 int i, idx = 0;
590 for (i = 0; i < BITS_TO_U64S(size); i++) {
591 uint64_t w = qemu_get_be64(f);
592 bmp[idx++] = w;
593 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
594 bmp[idx++] = w >> 32;
595 }
596 }
597 return 0;
598 }
599
put_bitmap(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)600 static int put_bitmap(QEMUFile *f, void *pv, size_t size,
601 const VMStateField *field, JSONWriter *vmdesc)
602 {
603 unsigned long *bmp = pv;
604 int i, idx = 0;
605 for (i = 0; i < BITS_TO_U64S(size); i++) {
606 uint64_t w = bmp[idx++];
607 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
608 w |= ((uint64_t)bmp[idx++]) << 32;
609 }
610 qemu_put_be64(f, w);
611 }
612
613 return 0;
614 }
615
616 const VMStateInfo vmstate_info_bitmap = {
617 .name = "bitmap",
618 .get = get_bitmap,
619 .put = put_bitmap,
620 };
621
622 /* get for QTAILQ
623 * meta data about the QTAILQ is encoded in a VMStateField structure
624 */
get_qtailq(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field)625 static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
626 const VMStateField *field)
627 {
628 int ret = 0;
629 const VMStateDescription *vmsd = field->vmsd;
630 /* size of a QTAILQ element */
631 size_t size = field->size;
632 /* offset of the QTAILQ entry in a QTAILQ element */
633 size_t entry_offset = field->start;
634 int version_id = field->version_id;
635 void *elm;
636
637 trace_get_qtailq(vmsd->name, version_id);
638 if (version_id > vmsd->version_id) {
639 error_report("%s %s", vmsd->name, "too new");
640 trace_get_qtailq_end(vmsd->name, "too new", -EINVAL);
641
642 return -EINVAL;
643 }
644 if (version_id < vmsd->minimum_version_id) {
645 error_report("%s %s", vmsd->name, "too old");
646 trace_get_qtailq_end(vmsd->name, "too old", -EINVAL);
647 return -EINVAL;
648 }
649
650 while (qemu_get_byte(f)) {
651 elm = g_malloc(size);
652 ret = vmstate_load_state(f, vmsd, elm, version_id);
653 if (ret) {
654 return ret;
655 }
656 QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset);
657 }
658
659 trace_get_qtailq_end(vmsd->name, "end", ret);
660 return ret;
661 }
662
663 /* put for QTAILQ */
put_qtailq(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field,JSONWriter * vmdesc)664 static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size,
665 const VMStateField *field, JSONWriter *vmdesc)
666 {
667 const VMStateDescription *vmsd = field->vmsd;
668 /* offset of the QTAILQ entry in a QTAILQ element*/
669 size_t entry_offset = field->start;
670 void *elm;
671 int ret;
672
673 trace_put_qtailq(vmsd->name, vmsd->version_id);
674
675 QTAILQ_RAW_FOREACH(elm, pv, entry_offset) {
676 qemu_put_byte(f, true);
677 ret = vmstate_save_state(f, vmsd, elm, vmdesc);
678 if (ret) {
679 return ret;
680 }
681 }
682 qemu_put_byte(f, false);
683
684 trace_put_qtailq_end(vmsd->name, "end");
685
686 return 0;
687 }
688 const VMStateInfo vmstate_info_qtailq = {
689 .name = "qtailq",
690 .get = get_qtailq,
691 .put = put_qtailq,
692 };
693
694 struct put_gtree_data {
695 QEMUFile *f;
696 const VMStateDescription *key_vmsd;
697 const VMStateDescription *val_vmsd;
698 JSONWriter *vmdesc;
699 int ret;
700 };
701
put_gtree_elem(gpointer key,gpointer value,gpointer data)702 static gboolean put_gtree_elem(gpointer key, gpointer value, gpointer data)
703 {
704 struct put_gtree_data *capsule = (struct put_gtree_data *)data;
705 QEMUFile *f = capsule->f;
706 int ret;
707
708 qemu_put_byte(f, true);
709
710 /* put the key */
711 if (!capsule->key_vmsd) {
712 qemu_put_be64(f, (uint64_t)(uintptr_t)(key)); /* direct key */
713 } else {
714 ret = vmstate_save_state(f, capsule->key_vmsd, key, capsule->vmdesc);
715 if (ret) {
716 capsule->ret = ret;
717 return true;
718 }
719 }
720
721 /* put the data */
722 ret = vmstate_save_state(f, capsule->val_vmsd, value, capsule->vmdesc);
723 if (ret) {
724 capsule->ret = ret;
725 return true;
726 }
727 return false;
728 }
729
put_gtree(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field,JSONWriter * vmdesc)730 static int put_gtree(QEMUFile *f, void *pv, size_t unused_size,
731 const VMStateField *field, JSONWriter *vmdesc)
732 {
733 bool direct_key = (!field->start);
734 const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
735 const VMStateDescription *val_vmsd = &field->vmsd[0];
736 const char *key_vmsd_name = direct_key ? "direct" : key_vmsd->name;
737 struct put_gtree_data capsule = {
738 .f = f,
739 .key_vmsd = key_vmsd,
740 .val_vmsd = val_vmsd,
741 .vmdesc = vmdesc,
742 .ret = 0};
743 GTree **pval = pv;
744 GTree *tree = *pval;
745 uint32_t nnodes = g_tree_nnodes(tree);
746 int ret;
747
748 trace_put_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
749 qemu_put_be32(f, nnodes);
750 g_tree_foreach(tree, put_gtree_elem, (gpointer)&capsule);
751 qemu_put_byte(f, false);
752 ret = capsule.ret;
753 if (ret) {
754 error_report("%s : failed to save gtree (%d)", field->name, ret);
755 }
756 trace_put_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
757 return ret;
758 }
759
get_gtree(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field)760 static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
761 const VMStateField *field)
762 {
763 bool direct_key = (!field->start);
764 const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
765 const VMStateDescription *val_vmsd = &field->vmsd[0];
766 const char *key_vmsd_name = direct_key ? "direct" : key_vmsd->name;
767 int version_id = field->version_id;
768 size_t key_size = field->start;
769 size_t val_size = field->size;
770 int nnodes, count = 0;
771 GTree **pval = pv;
772 GTree *tree = *pval;
773 void *key, *val;
774 int ret = 0;
775
776 /* in case of direct key, the key vmsd can be {}, ie. check fields */
777 if (!direct_key && version_id > key_vmsd->version_id) {
778 error_report("%s %s", key_vmsd->name, "too new");
779 return -EINVAL;
780 }
781 if (!direct_key && version_id < key_vmsd->minimum_version_id) {
782 error_report("%s %s", key_vmsd->name, "too old");
783 return -EINVAL;
784 }
785 if (version_id > val_vmsd->version_id) {
786 error_report("%s %s", val_vmsd->name, "too new");
787 return -EINVAL;
788 }
789 if (version_id < val_vmsd->minimum_version_id) {
790 error_report("%s %s", val_vmsd->name, "too old");
791 return -EINVAL;
792 }
793
794 nnodes = qemu_get_be32(f);
795 trace_get_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
796
797 while (qemu_get_byte(f)) {
798 if ((++count) > nnodes) {
799 ret = -EINVAL;
800 break;
801 }
802 if (direct_key) {
803 key = (void *)(uintptr_t)qemu_get_be64(f);
804 } else {
805 key = g_malloc0(key_size);
806 ret = vmstate_load_state(f, key_vmsd, key, version_id);
807 if (ret) {
808 error_report("%s : failed to load %s (%d)",
809 field->name, key_vmsd->name, ret);
810 goto key_error;
811 }
812 }
813 val = g_malloc0(val_size);
814 ret = vmstate_load_state(f, val_vmsd, val, version_id);
815 if (ret) {
816 error_report("%s : failed to load %s (%d)",
817 field->name, val_vmsd->name, ret);
818 goto val_error;
819 }
820 g_tree_insert(tree, key, val);
821 }
822 if (count != nnodes) {
823 error_report("%s inconsistent stream when loading the gtree",
824 field->name);
825 return -EINVAL;
826 }
827 trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
828 return ret;
829 val_error:
830 g_free(val);
831 key_error:
832 if (!direct_key) {
833 g_free(key);
834 }
835 trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
836 return ret;
837 }
838
839
840 const VMStateInfo vmstate_info_gtree = {
841 .name = "gtree",
842 .get = get_gtree,
843 .put = put_gtree,
844 };
845
put_qlist(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field,JSONWriter * vmdesc)846 static int put_qlist(QEMUFile *f, void *pv, size_t unused_size,
847 const VMStateField *field, JSONWriter *vmdesc)
848 {
849 const VMStateDescription *vmsd = field->vmsd;
850 /* offset of the QTAILQ entry in a QTAILQ element*/
851 size_t entry_offset = field->start;
852 void *elm;
853 int ret;
854
855 trace_put_qlist(field->name, vmsd->name, vmsd->version_id);
856 QLIST_RAW_FOREACH(elm, pv, entry_offset) {
857 qemu_put_byte(f, true);
858 ret = vmstate_save_state(f, vmsd, elm, vmdesc);
859 if (ret) {
860 error_report("%s: failed to save %s (%d)", field->name,
861 vmsd->name, ret);
862 return ret;
863 }
864 }
865 qemu_put_byte(f, false);
866 trace_put_qlist_end(field->name, vmsd->name);
867
868 return 0;
869 }
870
get_qlist(QEMUFile * f,void * pv,size_t unused_size,const VMStateField * field)871 static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
872 const VMStateField *field)
873 {
874 int ret = 0;
875 const VMStateDescription *vmsd = field->vmsd;
876 /* size of a QLIST element */
877 size_t size = field->size;
878 /* offset of the QLIST entry in a QLIST element */
879 size_t entry_offset = field->start;
880 int version_id = field->version_id;
881 void *elm, *prev = NULL;
882
883 trace_get_qlist(field->name, vmsd->name, vmsd->version_id);
884 if (version_id > vmsd->version_id) {
885 error_report("%s %s", vmsd->name, "too new");
886 return -EINVAL;
887 }
888 if (version_id < vmsd->minimum_version_id) {
889 error_report("%s %s", vmsd->name, "too old");
890 return -EINVAL;
891 }
892
893 while (qemu_get_byte(f)) {
894 elm = g_malloc(size);
895 ret = vmstate_load_state(f, vmsd, elm, version_id);
896 if (ret) {
897 error_report("%s: failed to load %s (%d)", field->name,
898 vmsd->name, ret);
899 g_free(elm);
900 return ret;
901 }
902 if (!prev) {
903 QLIST_RAW_INSERT_HEAD(pv, elm, entry_offset);
904 } else {
905 QLIST_RAW_INSERT_AFTER(pv, prev, elm, entry_offset);
906 }
907 prev = elm;
908 }
909 trace_get_qlist_end(field->name, vmsd->name);
910
911 return ret;
912 }
913
914 const VMStateInfo vmstate_info_qlist = {
915 .name = "qlist",
916 .get = get_qlist,
917 .put = put_qlist,
918 };
919