vmstate-types.c (22857B)
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};