qemu/migration/vmstate-types.c
<<
>>
Prefs
   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
  24static 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
  32static 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
  40const VMStateInfo vmstate_info_bool = {
  41    .name = "bool",
  42    .get  = get_bool,
  43    .put  = put_bool,
  44};
  45
  46/* 8 bit int */
  47
  48static 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
  56static 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
  64const VMStateInfo vmstate_info_int8 = {
  65    .name = "int8",
  66    .get  = get_int8,
  67    .put  = put_int8,
  68};
  69
  70/* 16 bit int */
  71
  72static 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
  80static 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
  88const VMStateInfo vmstate_info_int16 = {
  89    .name = "int16",
  90    .get  = get_int16,
  91    .put  = put_int16,
  92};
  93
  94/* 32 bit int */
  95
  96static 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
 104static 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
 112const 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
 121static 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
 138const 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
 148static 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
 165const 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
 173static 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
 181static 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
 189const VMStateInfo vmstate_info_int64 = {
 190    .name = "int64",
 191    .get  = get_int64,
 192    .put  = put_int64,
 193};
 194
 195/* 8 bit unsigned int */
 196
 197static 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
 205static 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
 213const VMStateInfo vmstate_info_uint8 = {
 214    .name = "uint8",
 215    .get  = get_uint8,
 216    .put  = put_uint8,
 217};
 218
 219/* 16 bit unsigned int */
 220
 221static 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
 229static 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
 237const VMStateInfo vmstate_info_uint16 = {
 238    .name = "uint16",
 239    .get  = get_uint16,
 240    .put  = put_uint16,
 241};
 242
 243/* 32 bit unsigned int */
 244
 245static 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
 253static 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
 261const 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
 270static 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
 287const 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
 295static 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
 303static 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
 311const VMStateInfo vmstate_info_uint64 = {
 312    .name = "uint64",
 313    .get  = get_uint64,
 314    .put  = put_uint64,
 315};
 316
 317static 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
 328static 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
 340const 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
 349static 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
 366const 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
 375static 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
 392const 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
 401static 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
 418const 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
 426static 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
 435static 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
 444const VMStateInfo vmstate_info_cpudouble = {
 445    .name = "CPU_Double_U",
 446    .get  = get_cpudouble,
 447    .put  = put_cpudouble,
 448};
 449
 450/* uint8_t buffers */
 451
 452static 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
 460static 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
 468const 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
 477static 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
 491static 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
 506const 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 */
 518static 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
 533static 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
 548const 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)
 561static 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
 576static 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
 592const 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 */
 601static 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 */
 640static 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}
 664const VMStateInfo vmstate_info_qtailq = {
 665    .name = "qtailq",
 666    .get  = get_qtailq,
 667    .put  = put_qtailq,
 668};
 669
 670struct put_gtree_data {
 671    QEMUFile *f;
 672    const VMStateDescription *key_vmsd;
 673    const VMStateDescription *val_vmsd;
 674    JSONWriter *vmdesc;
 675    int ret;
 676};
 677
 678static 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
 706static 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
 736static 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;
 805val_error:
 806    g_free(val);
 807key_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
 816const VMStateInfo vmstate_info_gtree = {
 817    .name = "gtree",
 818    .get  = get_gtree,
 819    .put  = put_gtree,
 820};
 821
 822static 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
 847static 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
 890const VMStateInfo vmstate_info_qlist = {
 891    .name = "qlist",
 892    .get  = get_qlist,
 893    .put  = put_qlist,
 894};
 895