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, JSONWriter *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, JSONWriter *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, JSONWriter *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, JSONWriter *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, JSONWriter *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, JSONWriter *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, JSONWriter *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, JSONWriter *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, JSONWriter *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, JSONWriter *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/* CPU_DoubleU type */
 424
 425static int get_cpudouble(QEMUFile *f, void *pv, size_t size,
 426                         const VMStateField *field)
 427{
 428    CPU_DoubleU *v = pv;
 429    qemu_get_be32s(f, &v->l.upper);
 430    qemu_get_be32s(f, &v->l.lower);
 431    return 0;
 432}
 433
 434static int put_cpudouble(QEMUFile *f, void *pv, size_t size,
 435                         const VMStateField *field, JSONWriter *vmdesc)
 436{
 437    CPU_DoubleU *v = pv;
 438    qemu_put_be32s(f, &v->l.upper);
 439    qemu_put_be32s(f, &v->l.lower);
 440    return 0;
 441}
 442
 443const VMStateInfo vmstate_info_cpudouble = {
 444    .name = "CPU_Double_U",
 445    .get  = get_cpudouble,
 446    .put  = put_cpudouble,
 447};
 448
 449/* uint8_t buffers */
 450
 451static int get_buffer(QEMUFile *f, void *pv, size_t size,
 452                      const VMStateField *field)
 453{
 454    uint8_t *v = pv;
 455    qemu_get_buffer(f, v, size);
 456    return 0;
 457}
 458
 459static int put_buffer(QEMUFile *f, void *pv, size_t size,
 460                      const VMStateField *field, JSONWriter *vmdesc)
 461{
 462    uint8_t *v = pv;
 463    qemu_put_buffer(f, v, size);
 464    return 0;
 465}
 466
 467const VMStateInfo vmstate_info_buffer = {
 468    .name = "buffer",
 469    .get  = get_buffer,
 470    .put  = put_buffer,
 471};
 472
 473/* unused buffers: space that was used for some fields that are
 474   not useful anymore */
 475
 476static int get_unused_buffer(QEMUFile *f, void *pv, size_t size,
 477                             const VMStateField *field)
 478{
 479    uint8_t buf[1024];
 480    int block_len;
 481
 482    while (size > 0) {
 483        block_len = MIN(sizeof(buf), size);
 484        size -= block_len;
 485        qemu_get_buffer(f, buf, block_len);
 486    }
 487   return 0;
 488}
 489
 490static int put_unused_buffer(QEMUFile *f, void *pv, size_t size,
 491                             const VMStateField *field, JSONWriter *vmdesc)
 492{
 493    static const uint8_t buf[1024];
 494    int block_len;
 495
 496    while (size > 0) {
 497        block_len = MIN(sizeof(buf), size);
 498        size -= block_len;
 499        qemu_put_buffer(f, buf, block_len);
 500    }
 501
 502    return 0;
 503}
 504
 505const VMStateInfo vmstate_info_unused_buffer = {
 506    .name = "unused_buffer",
 507    .get  = get_unused_buffer,
 508    .put  = put_unused_buffer,
 509};
 510
 511/* vmstate_info_tmp, see VMSTATE_WITH_TMP, the idea is that we allocate
 512 * a temporary buffer and the pre_load/pre_save methods in the child vmsd
 513 * copy stuff from the parent into the child and do calculations to fill
 514 * in fields that don't really exist in the parent but need to be in the
 515 * stream.
 516 */
 517static int get_tmp(QEMUFile *f, void *pv, size_t size,
 518                   const VMStateField *field)
 519{
 520    int ret;
 521    const VMStateDescription *vmsd = field->vmsd;
 522    int version_id = field->version_id;
 523    void *tmp = g_malloc(size);
 524
 525    /* Writes the parent field which is at the start of the tmp */
 526    *(void **)tmp = pv;
 527    ret = vmstate_load_state(f, vmsd, tmp, version_id);
 528    g_free(tmp);
 529    return ret;
 530}
 531
 532static int put_tmp(QEMUFile *f, void *pv, size_t size,
 533                   const VMStateField *field, JSONWriter *vmdesc)
 534{
 535    const VMStateDescription *vmsd = field->vmsd;
 536    void *tmp = g_malloc(size);
 537    int ret;
 538
 539    /* Writes the parent field which is at the start of the tmp */
 540    *(void **)tmp = pv;
 541    ret = vmstate_save_state(f, vmsd, tmp, vmdesc);
 542    g_free(tmp);
 543
 544    return ret;
 545}
 546
 547const VMStateInfo vmstate_info_tmp = {
 548    .name = "tmp",
 549    .get = get_tmp,
 550    .put = put_tmp,
 551};
 552
 553/* bitmaps (as defined by bitmap.h). Note that size here is the size
 554 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
 555 * bit words with the bits in big endian order. The in-memory format
 556 * is an array of 'unsigned long', which may be either 32 or 64 bits.
 557 */
 558/* This is the number of 64 bit words sent over the wire */
 559#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
 560static int get_bitmap(QEMUFile *f, void *pv, size_t size,
 561                      const VMStateField *field)
 562{
 563    unsigned long *bmp = pv;
 564    int i, idx = 0;
 565    for (i = 0; i < BITS_TO_U64S(size); i++) {
 566        uint64_t w = qemu_get_be64(f);
 567        bmp[idx++] = w;
 568        if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
 569            bmp[idx++] = w >> 32;
 570        }
 571    }
 572    return 0;
 573}
 574
 575static int put_bitmap(QEMUFile *f, void *pv, size_t size,
 576                      const VMStateField *field, JSONWriter *vmdesc)
 577{
 578    unsigned long *bmp = pv;
 579    int i, idx = 0;
 580    for (i = 0; i < BITS_TO_U64S(size); i++) {
 581        uint64_t w = bmp[idx++];
 582        if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
 583            w |= ((uint64_t)bmp[idx++]) << 32;
 584        }
 585        qemu_put_be64(f, w);
 586    }
 587
 588    return 0;
 589}
 590
 591const VMStateInfo vmstate_info_bitmap = {
 592    .name = "bitmap",
 593    .get = get_bitmap,
 594    .put = put_bitmap,
 595};
 596
 597/* get for QTAILQ
 598 * meta data about the QTAILQ is encoded in a VMStateField structure
 599 */
 600static int get_qtailq(QEMUFile *f, void *pv, size_t unused_size,
 601                      const VMStateField *field)
 602{
 603    int ret = 0;
 604    const VMStateDescription *vmsd = field->vmsd;
 605    /* size of a QTAILQ element */
 606    size_t size = field->size;
 607    /* offset of the QTAILQ entry in a QTAILQ element */
 608    size_t entry_offset = field->start;
 609    int version_id = field->version_id;
 610    void *elm;
 611
 612    trace_get_qtailq(vmsd->name, version_id);
 613    if (version_id > vmsd->version_id) {
 614        error_report("%s %s",  vmsd->name, "too new");
 615        trace_get_qtailq_end(vmsd->name, "too new", -EINVAL);
 616
 617        return -EINVAL;
 618    }
 619    if (version_id < vmsd->minimum_version_id) {
 620        error_report("%s %s",  vmsd->name, "too old");
 621        trace_get_qtailq_end(vmsd->name, "too old", -EINVAL);
 622        return -EINVAL;
 623    }
 624
 625    while (qemu_get_byte(f)) {
 626        elm = g_malloc(size);
 627        ret = vmstate_load_state(f, vmsd, elm, version_id);
 628        if (ret) {
 629            return ret;
 630        }
 631        QTAILQ_RAW_INSERT_TAIL(pv, elm, entry_offset);
 632    }
 633
 634    trace_get_qtailq_end(vmsd->name, "end", ret);
 635    return ret;
 636}
 637
 638/* put for QTAILQ */
 639static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size,
 640                      const VMStateField *field, JSONWriter *vmdesc)
 641{
 642    const VMStateDescription *vmsd = field->vmsd;
 643    /* offset of the QTAILQ entry in a QTAILQ element*/
 644    size_t entry_offset = field->start;
 645    void *elm;
 646    int ret;
 647
 648    trace_put_qtailq(vmsd->name, vmsd->version_id);
 649
 650    QTAILQ_RAW_FOREACH(elm, pv, entry_offset) {
 651        qemu_put_byte(f, true);
 652        ret = vmstate_save_state(f, vmsd, elm, vmdesc);
 653        if (ret) {
 654            return ret;
 655        }
 656    }
 657    qemu_put_byte(f, false);
 658
 659    trace_put_qtailq_end(vmsd->name, "end");
 660
 661    return 0;
 662}
 663const VMStateInfo vmstate_info_qtailq = {
 664    .name = "qtailq",
 665    .get  = get_qtailq,
 666    .put  = put_qtailq,
 667};
 668
 669struct put_gtree_data {
 670    QEMUFile *f;
 671    const VMStateDescription *key_vmsd;
 672    const VMStateDescription *val_vmsd;
 673    JSONWriter *vmdesc;
 674    int ret;
 675};
 676
 677static gboolean put_gtree_elem(gpointer key, gpointer value, gpointer data)
 678{
 679    struct put_gtree_data *capsule = (struct put_gtree_data *)data;
 680    QEMUFile *f = capsule->f;
 681    int ret;
 682
 683    qemu_put_byte(f, true);
 684
 685    /* put the key */
 686    if (!capsule->key_vmsd) {
 687        qemu_put_be64(f, (uint64_t)(uintptr_t)(key)); /* direct key */
 688    } else {
 689        ret = vmstate_save_state(f, capsule->key_vmsd, key, capsule->vmdesc);
 690        if (ret) {
 691            capsule->ret = ret;
 692            return true;
 693        }
 694    }
 695
 696    /* put the data */
 697    ret = vmstate_save_state(f, capsule->val_vmsd, value, capsule->vmdesc);
 698    if (ret) {
 699        capsule->ret = ret;
 700        return true;
 701    }
 702    return false;
 703}
 704
 705static int put_gtree(QEMUFile *f, void *pv, size_t unused_size,
 706                     const VMStateField *field, JSONWriter *vmdesc)
 707{
 708    bool direct_key = (!field->start);
 709    const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
 710    const VMStateDescription *val_vmsd = &field->vmsd[0];
 711    const char *key_vmsd_name = direct_key ? "direct" : key_vmsd->name;
 712    struct put_gtree_data capsule = {
 713        .f = f,
 714        .key_vmsd = key_vmsd,
 715        .val_vmsd = val_vmsd,
 716        .vmdesc = vmdesc,
 717        .ret = 0};
 718    GTree **pval = pv;
 719    GTree *tree = *pval;
 720    uint32_t nnodes = g_tree_nnodes(tree);
 721    int ret;
 722
 723    trace_put_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
 724    qemu_put_be32(f, nnodes);
 725    g_tree_foreach(tree, put_gtree_elem, (gpointer)&capsule);
 726    qemu_put_byte(f, false);
 727    ret = capsule.ret;
 728    if (ret) {
 729        error_report("%s : failed to save gtree (%d)", field->name, ret);
 730    }
 731    trace_put_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
 732    return ret;
 733}
 734
 735static int get_gtree(QEMUFile *f, void *pv, size_t unused_size,
 736                     const VMStateField *field)
 737{
 738    bool direct_key = (!field->start);
 739    const VMStateDescription *key_vmsd = direct_key ? NULL : &field->vmsd[1];
 740    const VMStateDescription *val_vmsd = &field->vmsd[0];
 741    const char *key_vmsd_name = direct_key ? "direct" : key_vmsd->name;
 742    int version_id = field->version_id;
 743    size_t key_size = field->start;
 744    size_t val_size = field->size;
 745    int nnodes, count = 0;
 746    GTree **pval = pv;
 747    GTree *tree = *pval;
 748    void *key, *val;
 749    int ret = 0;
 750
 751    /* in case of direct key, the key vmsd can be {}, ie. check fields */
 752    if (!direct_key && version_id > key_vmsd->version_id) {
 753        error_report("%s %s",  key_vmsd->name, "too new");
 754        return -EINVAL;
 755    }
 756    if (!direct_key && version_id < key_vmsd->minimum_version_id) {
 757        error_report("%s %s",  key_vmsd->name, "too old");
 758        return -EINVAL;
 759    }
 760    if (version_id > val_vmsd->version_id) {
 761        error_report("%s %s",  val_vmsd->name, "too new");
 762        return -EINVAL;
 763    }
 764    if (version_id < val_vmsd->minimum_version_id) {
 765        error_report("%s %s",  val_vmsd->name, "too old");
 766        return -EINVAL;
 767    }
 768
 769    nnodes = qemu_get_be32(f);
 770    trace_get_gtree(field->name, key_vmsd_name, val_vmsd->name, nnodes);
 771
 772    while (qemu_get_byte(f)) {
 773        if ((++count) > nnodes) {
 774            ret = -EINVAL;
 775            break;
 776        }
 777        if (direct_key) {
 778            key = (void *)(uintptr_t)qemu_get_be64(f);
 779        } else {
 780            key = g_malloc0(key_size);
 781            ret = vmstate_load_state(f, key_vmsd, key, version_id);
 782            if (ret) {
 783                error_report("%s : failed to load %s (%d)",
 784                             field->name, key_vmsd->name, ret);
 785                goto key_error;
 786            }
 787        }
 788        val = g_malloc0(val_size);
 789        ret = vmstate_load_state(f, val_vmsd, val, version_id);
 790        if (ret) {
 791            error_report("%s : failed to load %s (%d)",
 792                         field->name, val_vmsd->name, ret);
 793            goto val_error;
 794        }
 795        g_tree_insert(tree, key, val);
 796    }
 797    if (count != nnodes) {
 798        error_report("%s inconsistent stream when loading the gtree",
 799                     field->name);
 800        return -EINVAL;
 801    }
 802    trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
 803    return ret;
 804val_error:
 805    g_free(val);
 806key_error:
 807    if (!direct_key) {
 808        g_free(key);
 809    }
 810    trace_get_gtree_end(field->name, key_vmsd_name, val_vmsd->name, ret);
 811    return ret;
 812}
 813
 814
 815const VMStateInfo vmstate_info_gtree = {
 816    .name = "gtree",
 817    .get  = get_gtree,
 818    .put  = put_gtree,
 819};
 820
 821static int put_qlist(QEMUFile *f, void *pv, size_t unused_size,
 822                     const VMStateField *field, JSONWriter *vmdesc)
 823{
 824    const VMStateDescription *vmsd = field->vmsd;
 825    /* offset of the QTAILQ entry in a QTAILQ element*/
 826    size_t entry_offset = field->start;
 827    void *elm;
 828    int ret;
 829
 830    trace_put_qlist(field->name, vmsd->name, vmsd->version_id);
 831    QLIST_RAW_FOREACH(elm, pv, entry_offset) {
 832        qemu_put_byte(f, true);
 833        ret = vmstate_save_state(f, vmsd, elm, vmdesc);
 834        if (ret) {
 835            error_report("%s: failed to save %s (%d)", field->name,
 836                         vmsd->name, ret);
 837            return ret;
 838        }
 839    }
 840    qemu_put_byte(f, false);
 841    trace_put_qlist_end(field->name, vmsd->name);
 842
 843    return 0;
 844}
 845
 846static int get_qlist(QEMUFile *f, void *pv, size_t unused_size,
 847                     const VMStateField *field)
 848{
 849    int ret = 0;
 850    const VMStateDescription *vmsd = field->vmsd;
 851    /* size of a QLIST element */
 852    size_t size = field->size;
 853    /* offset of the QLIST entry in a QLIST element */
 854    size_t entry_offset = field->start;
 855    int version_id = field->version_id;
 856    void *elm, *prev = NULL;
 857
 858    trace_get_qlist(field->name, vmsd->name, vmsd->version_id);
 859    if (version_id > vmsd->version_id) {
 860        error_report("%s %s",  vmsd->name, "too new");
 861        return -EINVAL;
 862    }
 863    if (version_id < vmsd->minimum_version_id) {
 864        error_report("%s %s",  vmsd->name, "too old");
 865        return -EINVAL;
 866    }
 867
 868    while (qemu_get_byte(f)) {
 869        elm = g_malloc(size);
 870        ret = vmstate_load_state(f, vmsd, elm, version_id);
 871        if (ret) {
 872            error_report("%s: failed to load %s (%d)", field->name,
 873                         vmsd->name, ret);
 874            g_free(elm);
 875            return ret;
 876        }
 877        if (!prev) {
 878            QLIST_RAW_INSERT_HEAD(pv, elm, entry_offset);
 879        } else {
 880            QLIST_RAW_INSERT_AFTER(pv, prev, elm, entry_offset);
 881        }
 882        prev = elm;
 883    }
 884    trace_get_qlist_end(field->name, vmsd->name);
 885
 886    return ret;
 887}
 888
 889const VMStateInfo vmstate_info_qlist = {
 890    .name = "qlist",
 891    .get  = get_qlist,
 892    .put  = put_qlist,
 893};
 894