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