vmstate-types.c 23 KB

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