vmstate-types.c 23 KB

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