qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

vmstate-types.c (22885B)


      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 
     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 
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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)
    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 
    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  */
    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 */
    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 
    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 
    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 
    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 
    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 
    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 };