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