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