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