]> git.proxmox.com Git - mirror_qemu.git/blame - migration/vmstate.c
qemu-file: Add fast ftell code path
[mirror_qemu.git] / migration / vmstate.c
CommitLineData
b6fcfa59
EH
1#include "qemu-common.h"
2#include "migration/migration.h"
3#include "migration/qemu-file.h"
4#include "migration/vmstate.h"
5#include "qemu/bitops.h"
6a64b644 6#include "qemu/error-report.h"
9013dca5 7#include "trace.h"
b6fcfa59
EH
8
9static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
10 void *opaque);
11static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
12 void *opaque);
13
35fc1f71
MT
14static int vmstate_n_elems(void *opaque, VMStateField *field)
15{
16 int n_elems = 1;
17
18 if (field->flags & VMS_ARRAY) {
19 n_elems = field->num;
20 } else if (field->flags & VMS_VARRAY_INT32) {
21 n_elems = *(int32_t *)(opaque+field->num_offset);
22 } else if (field->flags & VMS_VARRAY_UINT32) {
23 n_elems = *(uint32_t *)(opaque+field->num_offset);
24 } else if (field->flags & VMS_VARRAY_UINT16) {
25 n_elems = *(uint16_t *)(opaque+field->num_offset);
26 } else if (field->flags & VMS_VARRAY_UINT8) {
27 n_elems = *(uint8_t *)(opaque+field->num_offset);
28 }
29
30 return n_elems;
31}
32
33static int vmstate_size(void *opaque, VMStateField *field)
34{
35 int size = field->size;
36
37 if (field->flags & VMS_VBUFFER) {
38 size = *(int32_t *)(opaque+field->size_offset);
39 if (field->flags & VMS_MULTIPLY) {
40 size *= field->size;
41 }
42 }
43
44 return size;
45}
46
f32935ea 47static void *vmstate_base_addr(void *opaque, VMStateField *field, bool alloc)
35fc1f71
MT
48{
49 void *base_addr = opaque + field->offset;
50
51 if (field->flags & VMS_POINTER) {
f32935ea 52 if (alloc && (field->flags & VMS_ALLOC)) {
94ed706d
AK
53 gsize size = 0;
54 if (field->flags & VMS_VBUFFER) {
55 size = vmstate_size(opaque, field);
56 } else {
57 int n_elems = vmstate_n_elems(opaque, field);
58 if (n_elems) {
59 size = n_elems * field->size;
60 }
61 }
62 if (size) {
f32935ea
AK
63 *((void **)base_addr + field->start) = g_malloc(size);
64 }
65 }
35fc1f71
MT
66 base_addr = *(void **)base_addr + field->start;
67 }
68
69 return base_addr;
70}
71
b6fcfa59
EH
72int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
73 void *opaque, int version_id)
74{
75 VMStateField *field = vmsd->fields;
a5df2a02 76 int ret = 0;
b6fcfa59 77
a5df2a02 78 trace_vmstate_load_state(vmsd->name, version_id);
b6fcfa59 79 if (version_id > vmsd->version_id) {
a5df2a02 80 trace_vmstate_load_state_end(vmsd->name, "too new", -EINVAL);
b6fcfa59
EH
81 return -EINVAL;
82 }
b6fcfa59 83 if (version_id < vmsd->minimum_version_id) {
767adce2
PM
84 if (vmsd->load_state_old &&
85 version_id >= vmsd->minimum_version_id_old) {
a5df2a02
DDAG
86 ret = vmsd->load_state_old(f, opaque, version_id);
87 trace_vmstate_load_state_end(vmsd->name, "old path", ret);
88 return ret;
767adce2 89 }
a5df2a02 90 trace_vmstate_load_state_end(vmsd->name, "too old", -EINVAL);
767adce2 91 return -EINVAL;
b6fcfa59
EH
92 }
93 if (vmsd->pre_load) {
94 int ret = vmsd->pre_load(opaque);
95 if (ret) {
96 return ret;
97 }
98 }
99 while (field->name) {
a5df2a02 100 trace_vmstate_load_state_field(vmsd->name, field->name);
b6fcfa59
EH
101 if ((field->field_exists &&
102 field->field_exists(opaque, version_id)) ||
103 (!field->field_exists &&
104 field->version_id <= version_id)) {
f32935ea 105 void *base_addr = vmstate_base_addr(opaque, field, true);
35fc1f71
MT
106 int i, n_elems = vmstate_n_elems(opaque, field);
107 int size = vmstate_size(opaque, field);
108
b6fcfa59
EH
109 for (i = 0; i < n_elems; i++) {
110 void *addr = base_addr + size * i;
111
112 if (field->flags & VMS_ARRAY_OF_POINTER) {
113 addr = *(void **)addr;
114 }
115 if (field->flags & VMS_STRUCT) {
116 ret = vmstate_load_state(f, field->vmsd, addr,
117 field->vmsd->version_id);
118 } else {
119 ret = field->info->get(f, addr, size);
120
121 }
13cde508
JQ
122 if (ret >= 0) {
123 ret = qemu_file_get_error(f);
124 }
b6fcfa59 125 if (ret < 0) {
13cde508 126 qemu_file_set_error(f, ret);
9013dca5 127 trace_vmstate_load_field_error(field->name, ret);
b6fcfa59
EH
128 return ret;
129 }
130 }
5bf81c8d 131 } else if (field->flags & VMS_MUST_EXIST) {
6a64b644
DDAG
132 error_report("Input validation failed: %s/%s",
133 vmsd->name, field->name);
5bf81c8d 134 return -1;
b6fcfa59
EH
135 }
136 field++;
137 }
138 ret = vmstate_subsection_load(f, vmsd, opaque);
139 if (ret != 0) {
140 return ret;
141 }
142 if (vmsd->post_load) {
a5df2a02 143 ret = vmsd->post_load(opaque, version_id);
b6fcfa59 144 }
a5df2a02
DDAG
145 trace_vmstate_load_state_end(vmsd->name, "end", ret);
146 return ret;
b6fcfa59
EH
147}
148
149void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
150 void *opaque)
151{
152 VMStateField *field = vmsd->fields;
153
154 if (vmsd->pre_save) {
155 vmsd->pre_save(opaque);
156 }
157 while (field->name) {
158 if (!field->field_exists ||
159 field->field_exists(opaque, vmsd->version_id)) {
f32935ea 160 void *base_addr = vmstate_base_addr(opaque, field, false);
35fc1f71
MT
161 int i, n_elems = vmstate_n_elems(opaque, field);
162 int size = vmstate_size(opaque, field);
163
b6fcfa59
EH
164 for (i = 0; i < n_elems; i++) {
165 void *addr = base_addr + size * i;
166
167 if (field->flags & VMS_ARRAY_OF_POINTER) {
168 addr = *(void **)addr;
169 }
170 if (field->flags & VMS_STRUCT) {
171 vmstate_save_state(f, field->vmsd, addr);
172 } else {
173 field->info->put(f, addr, size);
174 }
175 }
5bf81c8d
MT
176 } else {
177 if (field->flags & VMS_MUST_EXIST) {
6a64b644 178 error_report("Output state validation failed: %s/%s",
5bf81c8d
MT
179 vmsd->name, field->name);
180 assert(!(field->flags & VMS_MUST_EXIST));
181 }
b6fcfa59
EH
182 }
183 field++;
184 }
185 vmstate_subsection_save(f, vmsd, opaque);
186}
187
188static const VMStateDescription *
189 vmstate_get_subsection(const VMStateSubsection *sub, char *idstr)
190{
191 while (sub && sub->needed) {
192 if (strcmp(idstr, sub->vmsd->name) == 0) {
193 return sub->vmsd;
194 }
195 sub++;
196 }
197 return NULL;
198}
199
200static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd,
201 void *opaque)
202{
a5df2a02
DDAG
203 trace_vmstate_subsection_load(vmsd->name);
204
b6fcfa59
EH
205 while (qemu_peek_byte(f, 0) == QEMU_VM_SUBSECTION) {
206 char idstr[256];
207 int ret;
208 uint8_t version_id, len, size;
209 const VMStateDescription *sub_vmsd;
210
211 len = qemu_peek_byte(f, 1);
212 if (len < strlen(vmsd->name) + 1) {
213 /* subsection name has be be "section_name/a" */
a5df2a02 214 trace_vmstate_subsection_load_bad(vmsd->name, "(short)");
b6fcfa59
EH
215 return 0;
216 }
217 size = qemu_peek_buffer(f, (uint8_t *)idstr, len, 2);
218 if (size != len) {
a5df2a02 219 trace_vmstate_subsection_load_bad(vmsd->name, "(peek fail)");
b6fcfa59
EH
220 return 0;
221 }
222 idstr[size] = 0;
223
224 if (strncmp(vmsd->name, idstr, strlen(vmsd->name)) != 0) {
a5df2a02 225 trace_vmstate_subsection_load_bad(vmsd->name, idstr);
b6fcfa59
EH
226 /* it don't have a valid subsection name */
227 return 0;
228 }
229 sub_vmsd = vmstate_get_subsection(vmsd->subsections, idstr);
230 if (sub_vmsd == NULL) {
a5df2a02 231 trace_vmstate_subsection_load_bad(vmsd->name, "(lookup)");
b6fcfa59
EH
232 return -ENOENT;
233 }
234 qemu_file_skip(f, 1); /* subsection */
235 qemu_file_skip(f, 1); /* len */
236 qemu_file_skip(f, len); /* idstr */
237 version_id = qemu_get_be32(f);
238
239 ret = vmstate_load_state(f, sub_vmsd, opaque, version_id);
240 if (ret) {
a5df2a02 241 trace_vmstate_subsection_load_bad(vmsd->name, "(child)");
b6fcfa59
EH
242 return ret;
243 }
244 }
a5df2a02
DDAG
245
246 trace_vmstate_subsection_load_good(vmsd->name);
b6fcfa59
EH
247 return 0;
248}
249
250static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd,
251 void *opaque)
252{
253 const VMStateSubsection *sub = vmsd->subsections;
254
255 while (sub && sub->needed) {
256 if (sub->needed(opaque)) {
257 const VMStateDescription *vmsd = sub->vmsd;
258 uint8_t len;
259
260 qemu_put_byte(f, QEMU_VM_SUBSECTION);
261 len = strlen(vmsd->name);
262 qemu_put_byte(f, len);
263 qemu_put_buffer(f, (uint8_t *)vmsd->name, len);
264 qemu_put_be32(f, vmsd->version_id);
265 vmstate_save_state(f, vmsd, opaque);
266 }
267 sub++;
268 }
269}
270
271/* bool */
272
273static int get_bool(QEMUFile *f, void *pv, size_t size)
274{
275 bool *v = pv;
276 *v = qemu_get_byte(f);
277 return 0;
278}
279
280static void put_bool(QEMUFile *f, void *pv, size_t size)
281{
282 bool *v = pv;
283 qemu_put_byte(f, *v);
284}
285
286const VMStateInfo vmstate_info_bool = {
287 .name = "bool",
288 .get = get_bool,
289 .put = put_bool,
290};
291
292/* 8 bit int */
293
294static int get_int8(QEMUFile *f, void *pv, size_t size)
295{
296 int8_t *v = pv;
297 qemu_get_s8s(f, v);
298 return 0;
299}
300
301static void put_int8(QEMUFile *f, void *pv, size_t size)
302{
303 int8_t *v = pv;
304 qemu_put_s8s(f, v);
305}
306
307const VMStateInfo vmstate_info_int8 = {
308 .name = "int8",
309 .get = get_int8,
310 .put = put_int8,
311};
312
313/* 16 bit int */
314
315static int get_int16(QEMUFile *f, void *pv, size_t size)
316{
317 int16_t *v = pv;
318 qemu_get_sbe16s(f, v);
319 return 0;
320}
321
322static void put_int16(QEMUFile *f, void *pv, size_t size)
323{
324 int16_t *v = pv;
325 qemu_put_sbe16s(f, v);
326}
327
328const VMStateInfo vmstate_info_int16 = {
329 .name = "int16",
330 .get = get_int16,
331 .put = put_int16,
332};
333
334/* 32 bit int */
335
336static int get_int32(QEMUFile *f, void *pv, size_t size)
337{
338 int32_t *v = pv;
339 qemu_get_sbe32s(f, v);
340 return 0;
341}
342
343static void put_int32(QEMUFile *f, void *pv, size_t size)
344{
345 int32_t *v = pv;
346 qemu_put_sbe32s(f, v);
347}
348
349const VMStateInfo vmstate_info_int32 = {
350 .name = "int32",
351 .get = get_int32,
352 .put = put_int32,
353};
354
355/* 32 bit int. See that the received value is the same than the one
356 in the field */
357
358static int get_int32_equal(QEMUFile *f, void *pv, size_t size)
359{
360 int32_t *v = pv;
361 int32_t v2;
362 qemu_get_sbe32s(f, &v2);
363
364 if (*v == v2) {
365 return 0;
366 }
367 return -EINVAL;
368}
369
370const VMStateInfo vmstate_info_int32_equal = {
371 .name = "int32 equal",
372 .get = get_int32_equal,
373 .put = put_int32,
374};
375
d2ef4b61
MT
376/* 32 bit int. Check that the received value is non-negative
377 * and less than or equal to the one in the field.
378 */
b6fcfa59
EH
379
380static int get_int32_le(QEMUFile *f, void *pv, size_t size)
381{
24a370ef
DDAG
382 int32_t *cur = pv;
383 int32_t loaded;
384 qemu_get_sbe32s(f, &loaded);
b6fcfa59 385
d2ef4b61 386 if (loaded >= 0 && loaded <= *cur) {
24a370ef 387 *cur = loaded;
b6fcfa59
EH
388 return 0;
389 }
390 return -EINVAL;
391}
392
393const VMStateInfo vmstate_info_int32_le = {
24a370ef 394 .name = "int32 le",
b6fcfa59
EH
395 .get = get_int32_le,
396 .put = put_int32,
397};
398
399/* 64 bit int */
400
401static int get_int64(QEMUFile *f, void *pv, size_t size)
402{
403 int64_t *v = pv;
404 qemu_get_sbe64s(f, v);
405 return 0;
406}
407
408static void put_int64(QEMUFile *f, void *pv, size_t size)
409{
410 int64_t *v = pv;
411 qemu_put_sbe64s(f, v);
412}
413
414const VMStateInfo vmstate_info_int64 = {
415 .name = "int64",
416 .get = get_int64,
417 .put = put_int64,
418};
419
420/* 8 bit unsigned int */
421
422static int get_uint8(QEMUFile *f, void *pv, size_t size)
423{
424 uint8_t *v = pv;
425 qemu_get_8s(f, v);
426 return 0;
427}
428
429static void put_uint8(QEMUFile *f, void *pv, size_t size)
430{
431 uint8_t *v = pv;
432 qemu_put_8s(f, v);
433}
434
435const VMStateInfo vmstate_info_uint8 = {
436 .name = "uint8",
437 .get = get_uint8,
438 .put = put_uint8,
439};
440
441/* 16 bit unsigned int */
442
443static int get_uint16(QEMUFile *f, void *pv, size_t size)
444{
445 uint16_t *v = pv;
446 qemu_get_be16s(f, v);
447 return 0;
448}
449
450static void put_uint16(QEMUFile *f, void *pv, size_t size)
451{
452 uint16_t *v = pv;
453 qemu_put_be16s(f, v);
454}
455
456const VMStateInfo vmstate_info_uint16 = {
457 .name = "uint16",
458 .get = get_uint16,
459 .put = put_uint16,
460};
461
462/* 32 bit unsigned int */
463
464static int get_uint32(QEMUFile *f, void *pv, size_t size)
465{
466 uint32_t *v = pv;
467 qemu_get_be32s(f, v);
468 return 0;
469}
470
471static void put_uint32(QEMUFile *f, void *pv, size_t size)
472{
473 uint32_t *v = pv;
474 qemu_put_be32s(f, v);
475}
476
477const VMStateInfo vmstate_info_uint32 = {
478 .name = "uint32",
479 .get = get_uint32,
480 .put = put_uint32,
481};
482
483/* 32 bit uint. See that the received value is the same than the one
484 in the field */
485
486static int get_uint32_equal(QEMUFile *f, void *pv, size_t size)
487{
488 uint32_t *v = pv;
489 uint32_t v2;
490 qemu_get_be32s(f, &v2);
491
492 if (*v == v2) {
493 return 0;
494 }
495 return -EINVAL;
496}
497
498const VMStateInfo vmstate_info_uint32_equal = {
499 .name = "uint32 equal",
500 .get = get_uint32_equal,
501 .put = put_uint32,
502};
503
504/* 64 bit unsigned int */
505
506static int get_uint64(QEMUFile *f, void *pv, size_t size)
507{
508 uint64_t *v = pv;
509 qemu_get_be64s(f, v);
510 return 0;
511}
512
513static void put_uint64(QEMUFile *f, void *pv, size_t size)
514{
515 uint64_t *v = pv;
516 qemu_put_be64s(f, v);
517}
518
519const VMStateInfo vmstate_info_uint64 = {
520 .name = "uint64",
521 .get = get_uint64,
522 .put = put_uint64,
523};
524
525/* 64 bit unsigned int. See that the received value is the same than the one
526 in the field */
527
528static int get_uint64_equal(QEMUFile *f, void *pv, size_t size)
529{
530 uint64_t *v = pv;
531 uint64_t v2;
532 qemu_get_be64s(f, &v2);
533
534 if (*v == v2) {
535 return 0;
536 }
537 return -EINVAL;
538}
539
540const VMStateInfo vmstate_info_uint64_equal = {
541 .name = "int64 equal",
542 .get = get_uint64_equal,
543 .put = put_uint64,
544};
545
546/* 8 bit int. See that the received value is the same than the one
547 in the field */
548
549static int get_uint8_equal(QEMUFile *f, void *pv, size_t size)
550{
551 uint8_t *v = pv;
552 uint8_t v2;
553 qemu_get_8s(f, &v2);
554
555 if (*v == v2) {
556 return 0;
557 }
558 return -EINVAL;
559}
560
561const VMStateInfo vmstate_info_uint8_equal = {
562 .name = "uint8 equal",
563 .get = get_uint8_equal,
564 .put = put_uint8,
565};
566
567/* 16 bit unsigned int int. See that the received value is the same than the one
568 in the field */
569
570static int get_uint16_equal(QEMUFile *f, void *pv, size_t size)
571{
572 uint16_t *v = pv;
573 uint16_t v2;
574 qemu_get_be16s(f, &v2);
575
576 if (*v == v2) {
577 return 0;
578 }
579 return -EINVAL;
580}
581
582const VMStateInfo vmstate_info_uint16_equal = {
583 .name = "uint16 equal",
584 .get = get_uint16_equal,
585 .put = put_uint16,
586};
587
588/* floating point */
589
590static int get_float64(QEMUFile *f, void *pv, size_t size)
591{
592 float64 *v = pv;
593
594 *v = make_float64(qemu_get_be64(f));
595 return 0;
596}
597
598static void put_float64(QEMUFile *f, void *pv, size_t size)
599{
600 uint64_t *v = pv;
601
602 qemu_put_be64(f, float64_val(*v));
603}
604
605const VMStateInfo vmstate_info_float64 = {
606 .name = "float64",
607 .get = get_float64,
608 .put = put_float64,
609};
610
611/* uint8_t buffers */
612
613static int get_buffer(QEMUFile *f, void *pv, size_t size)
614{
615 uint8_t *v = pv;
616 qemu_get_buffer(f, v, size);
617 return 0;
618}
619
620static void put_buffer(QEMUFile *f, void *pv, size_t size)
621{
622 uint8_t *v = pv;
623 qemu_put_buffer(f, v, size);
624}
625
626const VMStateInfo vmstate_info_buffer = {
627 .name = "buffer",
628 .get = get_buffer,
629 .put = put_buffer,
630};
631
632/* unused buffers: space that was used for some fields that are
633 not useful anymore */
634
635static int get_unused_buffer(QEMUFile *f, void *pv, size_t size)
636{
637 uint8_t buf[1024];
638 int block_len;
639
640 while (size > 0) {
641 block_len = MIN(sizeof(buf), size);
642 size -= block_len;
643 qemu_get_buffer(f, buf, block_len);
644 }
645 return 0;
646}
647
648static void put_unused_buffer(QEMUFile *f, void *pv, size_t size)
649{
650 static const uint8_t buf[1024];
651 int block_len;
652
653 while (size > 0) {
654 block_len = MIN(sizeof(buf), size);
655 size -= block_len;
656 qemu_put_buffer(f, buf, block_len);
657 }
658}
659
660const VMStateInfo vmstate_info_unused_buffer = {
661 .name = "unused_buffer",
662 .get = get_unused_buffer,
663 .put = put_unused_buffer,
664};
665
666/* bitmaps (as defined by bitmap.h). Note that size here is the size
667 * of the bitmap in bits. The on-the-wire format of a bitmap is 64
668 * bit words with the bits in big endian order. The in-memory format
669 * is an array of 'unsigned long', which may be either 32 or 64 bits.
670 */
671/* This is the number of 64 bit words sent over the wire */
672#define BITS_TO_U64S(nr) DIV_ROUND_UP(nr, 64)
673static int get_bitmap(QEMUFile *f, void *pv, size_t size)
674{
675 unsigned long *bmp = pv;
676 int i, idx = 0;
677 for (i = 0; i < BITS_TO_U64S(size); i++) {
678 uint64_t w = qemu_get_be64(f);
679 bmp[idx++] = w;
680 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
681 bmp[idx++] = w >> 32;
682 }
683 }
684 return 0;
685}
686
687static void put_bitmap(QEMUFile *f, void *pv, size_t size)
688{
689 unsigned long *bmp = pv;
690 int i, idx = 0;
691 for (i = 0; i < BITS_TO_U64S(size); i++) {
692 uint64_t w = bmp[idx++];
693 if (sizeof(unsigned long) == 4 && idx < BITS_TO_LONGS(size)) {
694 w |= ((uint64_t)bmp[idx++]) << 32;
695 }
696 qemu_put_be64(f, w);
697 }
698}
699
700const VMStateInfo vmstate_info_bitmap = {
701 .name = "bitmap",
702 .get = get_bitmap,
703 .put = put_bitmap,
704};