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 23 static 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 31 static 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 39 const VMStateInfo vmstate_info_bool = { 40 .name = "bool", 41 .get = get_bool, 42 .put = put_bool, 43 }; 44 45 /* 8 bit int */ 46 47 static 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 55 static 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 63 const VMStateInfo vmstate_info_int8 = { 64 .name = "int8", 65 .get = get_int8, 66 .put = put_int8, 67 }; 68 69 /* 16 bit int */ 70 71 static 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 79 static 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 87 const VMStateInfo vmstate_info_int16 = { 88 .name = "int16", 89 .get = get_int16, 90 .put = put_int16, 91 }; 92 93 /* 32 bit int */ 94 95 static 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 103 static 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 111 const 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 120 static 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 137 const 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 147 static 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 164 const 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 172 static 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 180 static 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 188 const VMStateInfo vmstate_info_int64 = { 189 .name = "int64", 190 .get = get_int64, 191 .put = put_int64, 192 }; 193 194 /* 8 bit unsigned int */ 195 196 static 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 204 static 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 212 const VMStateInfo vmstate_info_uint8 = { 213 .name = "uint8", 214 .get = get_uint8, 215 .put = put_uint8, 216 }; 217 218 /* 16 bit unsigned int */ 219 220 static 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 228 static 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 236 const VMStateInfo vmstate_info_uint16 = { 237 .name = "uint16", 238 .get = get_uint16, 239 .put = put_uint16, 240 }; 241 242 /* 32 bit unsigned int */ 243 244 static 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 252 static 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 260 const 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 269 static 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 286 const 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 294 static 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 302 static 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 310 const VMStateInfo vmstate_info_uint64 = { 311 .name = "uint64", 312 .get = get_uint64, 313 .put = put_uint64, 314 }; 315 316 static 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 327 static 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 339 const 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 348 static 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 365 const 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 374 static 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 391 const 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 400 static 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 417 const 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 425 static 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 434 static int put_cpudouble(QEMUFile *f, void *pv, size_t size, 435 const VMStateField *field, QJSON *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 443 const VMStateInfo vmstate_info_cpudouble = { 444 .name = "CPU_Double_U", 445 .get = get_cpudouble, 446 .put = put_cpudouble, 447 }; 448 449 /* uint8_t buffers */ 450 451 static 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 459 static int put_buffer(QEMUFile *f, void *pv, size_t size, 460 const VMStateField *field, QJSON *vmdesc) 461 { 462 uint8_t *v = pv; 463 qemu_put_buffer(f, v, size); 464 return 0; 465 } 466 467 const 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 476 static 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 490 static int put_unused_buffer(QEMUFile *f, void *pv, size_t size, 491 const VMStateField *field, QJSON *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 505 const 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 */ 517 static 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 532 static int put_tmp(QEMUFile *f, void *pv, size_t size, 533 const VMStateField *field, QJSON *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 547 const 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) 560 static 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 575 static int put_bitmap(QEMUFile *f, void *pv, size_t size, 576 const VMStateField *field, QJSON *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 591 const 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 */ 600 static 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 */ 639 static int put_qtailq(QEMUFile *f, void *pv, size_t unused_size, 640 const VMStateField *field, QJSON *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 } 663 const VMStateInfo vmstate_info_qtailq = { 664 .name = "qtailq", 665 .get = get_qtailq, 666 .put = put_qtailq, 667 }; 668 669 struct put_gtree_data { 670 QEMUFile *f; 671 const VMStateDescription *key_vmsd; 672 const VMStateDescription *val_vmsd; 673 QJSON *vmdesc; 674 int ret; 675 }; 676 677 static 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 705 static int put_gtree(QEMUFile *f, void *pv, size_t unused_size, 706 const VMStateField *field, QJSON *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 735 static 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; 804 val_error: 805 g_free(val); 806 key_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 815 const VMStateInfo vmstate_info_gtree = { 816 .name = "gtree", 817 .get = get_gtree, 818 .put = put_gtree, 819 }; 820 821 static int put_qlist(QEMUFile *f, void *pv, size_t unused_size, 822 const VMStateField *field, QJSON *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 846 static 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 889 const VMStateInfo vmstate_info_qlist = { 890 .name = "qlist", 891 .get = get_qlist, 892 .put = put_qlist, 893 }; 894