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