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