xref: /qemu/migration/vmstate-types.c (revision 513823e7521a09ed7ad1e32e6454bac3b2cbf52d)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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  */
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 
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)
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 
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  */
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 */
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 
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 
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 
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 
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 
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