1c3049a56SJuan Quintela /*
2c3049a56SJuan Quintela * QEMU System Emulator
3c3049a56SJuan Quintela *
4c3049a56SJuan Quintela * Copyright (c) 2003-2008 Fabrice Bellard
576cc7b58SJuan Quintela * Copyright (c) 2009-2015 Red Hat Inc
676cc7b58SJuan Quintela *
776cc7b58SJuan Quintela * Authors:
876cc7b58SJuan Quintela * Juan Quintela <quintela@redhat.com>
9c3049a56SJuan Quintela *
10c3049a56SJuan Quintela * Permission is hereby granted, free of charge, to any person obtaining a copy
11c3049a56SJuan Quintela * of this software and associated documentation files (the "Software"), to deal
12c3049a56SJuan Quintela * in the Software without restriction, including without limitation the rights
13c3049a56SJuan Quintela * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14c3049a56SJuan Quintela * copies of the Software, and to permit persons to whom the Software is
15c3049a56SJuan Quintela * furnished to do so, subject to the following conditions:
16c3049a56SJuan Quintela *
17c3049a56SJuan Quintela * The above copyright notice and this permission notice shall be included in
18c3049a56SJuan Quintela * all copies or substantial portions of the Software.
19c3049a56SJuan Quintela *
20c3049a56SJuan Quintela * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21c3049a56SJuan Quintela * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22c3049a56SJuan Quintela * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23c3049a56SJuan Quintela * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24c3049a56SJuan Quintela * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25c3049a56SJuan Quintela * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26c3049a56SJuan Quintela * THE SOFTWARE.
27c3049a56SJuan Quintela */
28c3049a56SJuan Quintela
291393a485SPeter Maydell #include "qemu/osdep.h"
30c3049a56SJuan Quintela #include "hw/boards.h"
31c3049a56SJuan Quintela #include "net/net.h"
326666c96aSJuan Quintela #include "migration.h"
335e22479aSJuan Quintela #include "migration/snapshot.h"
34947701ccSJuan Quintela #include "migration-stats.h"
35d6454270SMarkus Armbruster #include "migration/vmstate.h"
36f8d806c9SJuan Quintela #include "migration/misc.h"
37f2a8f0a6SJuan Quintela #include "migration/register.h"
3884a899deSJuan Quintela #include "migration/global_state.h"
3967bdabe2SDaniel P. Berrangé #include "migration/channel-block.h"
407b1e1a22SJuan Quintela #include "ram.h"
4108a0aee1SJuan Quintela #include "qemu-file.h"
4220a519a0SJuan Quintela #include "savevm.h"
43be07b0acSJuan Quintela #include "postcopy-ram.h"
44e688df6bSMarkus Armbruster #include "qapi/error.h"
45112ed241SMarkus Armbruster #include "qapi/qapi-commands-migration.h"
46f1a9fcddSDaniel P. Berrangé #include "qapi/clone-visitor.h"
47f1a9fcddSDaniel P. Berrangé #include "qapi/qapi-builtin-visit.h"
48d49b6836SMarkus Armbruster #include "qemu/error-report.h"
49c3049a56SJuan Quintela #include "sysemu/cpus.h"
50c3049a56SJuan Quintela #include "exec/memory.h"
5151180423SJuan Quintela #include "exec/target_page.h"
52c3049a56SJuan Quintela #include "trace.h"
53c3049a56SJuan Quintela #include "qemu/iov.h"
54e2c1c34fSMarkus Armbruster #include "qemu/job.h"
55db725815SMarkus Armbruster #include "qemu/main-loop.h"
56c3049a56SJuan Quintela #include "block/snapshot.h"
57f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
5861b67d47SDaniel P. Berrange #include "io/channel-buffer.h"
598925839fSDaniel P. Berrange #include "io/channel-file.h"
60377b21ccSPavel Dovgalyuk #include "sysemu/replay.h"
6154d31236SMarkus Armbruster #include "sysemu/runstate.h"
6246517dd4SMarkus Armbruster #include "sysemu/sysemu.h"
63da278d58SPhilippe Mathieu-Daudé #include "sysemu/xen.h"
64aad555c2SZhang Chen #include "migration/colo.h"
656cafc8e4SYury Kotov #include "qemu/bitmap.h"
667659505cSDr. David Alan Gilbert #include "net/announce.h"
67b5eea99eSLukas Straub #include "qemu/yank.h"
6839675fffSPeter Xu #include "yank_functions.h"
69bb25a728SDr. David Alan Gilbert #include "sysemu/qtest.h"
701f0776f1SJuan Quintela #include "options.h"
71c3049a56SJuan Quintela
7249324e93SBihong Yu const unsigned int postcopy_ram_discard_version;
73093e3c42SDr. David Alan Gilbert
7420a519a0SJuan Quintela /* Subcommands for QEMU_VM_COMMAND */
7520a519a0SJuan Quintela enum qemu_vm_cmd {
7620a519a0SJuan Quintela MIG_CMD_INVALID = 0, /* Must be 0 */
7720a519a0SJuan Quintela MIG_CMD_OPEN_RETURN_PATH, /* Tell the dest to open the Return path */
7820a519a0SJuan Quintela MIG_CMD_PING, /* Request a PONG on the RP */
7920a519a0SJuan Quintela
8020a519a0SJuan Quintela MIG_CMD_POSTCOPY_ADVISE, /* Prior to any page transfers, just
8120a519a0SJuan Quintela warn we might want to do PC */
8220a519a0SJuan Quintela MIG_CMD_POSTCOPY_LISTEN, /* Start listening for incoming
8320a519a0SJuan Quintela pages as it's running. */
8420a519a0SJuan Quintela MIG_CMD_POSTCOPY_RUN, /* Start execution */
8520a519a0SJuan Quintela
8620a519a0SJuan Quintela MIG_CMD_POSTCOPY_RAM_DISCARD, /* A list of pages to discard that
8720a519a0SJuan Quintela were previously sent during
8820a519a0SJuan Quintela precopy but are dirty. */
8920a519a0SJuan Quintela MIG_CMD_PACKAGED, /* Send a wrapped stream within this stream */
90aad555c2SZhang Chen MIG_CMD_ENABLE_COLO, /* Enable COLO */
91858b6d62SPeter Xu MIG_CMD_POSTCOPY_RESUME, /* resume postcopy on dest */
92f25d4225SPeter Xu MIG_CMD_RECV_BITMAP, /* Request for recved bitmap on dst */
9320a519a0SJuan Quintela MIG_CMD_MAX
9420a519a0SJuan Quintela };
9520a519a0SJuan Quintela
96ee555cdfSDaniel Henrique Barboza #define MAX_VM_CMD_PACKAGED_SIZE UINT32_MAX
97c76ca188SDr. David Alan Gilbert static struct mig_cmd_args {
98c76ca188SDr. David Alan Gilbert ssize_t len; /* -1 = variable */
99c76ca188SDr. David Alan Gilbert const char *name;
100c76ca188SDr. David Alan Gilbert } mig_cmd_args[] = {
101c76ca188SDr. David Alan Gilbert [MIG_CMD_INVALID] = { .len = -1, .name = "INVALID" },
1022e37701eSDr. David Alan Gilbert [MIG_CMD_OPEN_RETURN_PATH] = { .len = 0, .name = "OPEN_RETURN_PATH" },
1032e37701eSDr. David Alan Gilbert [MIG_CMD_PING] = { .len = sizeof(uint32_t), .name = "PING" },
10458110f0aSVladimir Sementsov-Ogievskiy [MIG_CMD_POSTCOPY_ADVISE] = { .len = -1, .name = "POSTCOPY_ADVISE" },
105093e3c42SDr. David Alan Gilbert [MIG_CMD_POSTCOPY_LISTEN] = { .len = 0, .name = "POSTCOPY_LISTEN" },
106093e3c42SDr. David Alan Gilbert [MIG_CMD_POSTCOPY_RUN] = { .len = 0, .name = "POSTCOPY_RUN" },
107093e3c42SDr. David Alan Gilbert [MIG_CMD_POSTCOPY_RAM_DISCARD] = {
108093e3c42SDr. David Alan Gilbert .len = -1, .name = "POSTCOPY_RAM_DISCARD" },
1093f5875ecSPeter Xu [MIG_CMD_POSTCOPY_RESUME] = { .len = 0, .name = "POSTCOPY_RESUME" },
11011cf1d98SDr. David Alan Gilbert [MIG_CMD_PACKAGED] = { .len = 4, .name = "PACKAGED" },
111f25d4225SPeter Xu [MIG_CMD_RECV_BITMAP] = { .len = -1, .name = "RECV_BITMAP" },
112c76ca188SDr. David Alan Gilbert [MIG_CMD_MAX] = { .len = -1, .name = "MAX" },
113c76ca188SDr. David Alan Gilbert };
114c76ca188SDr. David Alan Gilbert
11558110f0aSVladimir Sementsov-Ogievskiy /* Note for MIG_CMD_POSTCOPY_ADVISE:
11658110f0aSVladimir Sementsov-Ogievskiy * The format of arguments is depending on postcopy mode:
11758110f0aSVladimir Sementsov-Ogievskiy * - postcopy RAM only
11858110f0aSVladimir Sementsov-Ogievskiy * uint64_t host page size
119d8b71d96SMichael Tokarev * uint64_t target page size
12058110f0aSVladimir Sementsov-Ogievskiy *
12158110f0aSVladimir Sementsov-Ogievskiy * - postcopy RAM and postcopy dirty bitmaps
12258110f0aSVladimir Sementsov-Ogievskiy * format is the same as for postcopy RAM only
12358110f0aSVladimir Sementsov-Ogievskiy *
12458110f0aSVladimir Sementsov-Ogievskiy * - postcopy dirty bitmaps only
12558110f0aSVladimir Sementsov-Ogievskiy * Nothing. Command length field is 0.
12658110f0aSVladimir Sementsov-Ogievskiy *
12758110f0aSVladimir Sementsov-Ogievskiy * Be careful: adding a new postcopy entity with some other parameters should
12858110f0aSVladimir Sementsov-Ogievskiy * not break format self-description ability. Good way is to introduce some
12958110f0aSVladimir Sementsov-Ogievskiy * generic extendable format with an exception for two old entities.
13058110f0aSVladimir Sementsov-Ogievskiy */
13158110f0aSVladimir Sementsov-Ogievskiy
132c3049a56SJuan Quintela /***********************************************************/
133c3049a56SJuan Quintela /* savevm/loadvm support */
134c3049a56SJuan Quintela
qemu_fopen_bdrv(BlockDriverState * bs,int is_writable)135c3049a56SJuan Quintela static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int is_writable)
136c3049a56SJuan Quintela {
137c3049a56SJuan Quintela if (is_writable) {
13877ef2dc1SDaniel P. Berrangé return qemu_file_new_output(QIO_CHANNEL(qio_channel_block_new(bs)));
13967bdabe2SDaniel P. Berrangé } else {
14077ef2dc1SDaniel P. Berrangé return qemu_file_new_input(QIO_CHANNEL(qio_channel_block_new(bs)));
141c3049a56SJuan Quintela }
142c3049a56SJuan Quintela }
143c3049a56SJuan Quintela
144c3049a56SJuan Quintela
145c3049a56SJuan Quintela /* QEMUFile timer support.
146c3049a56SJuan Quintela * Not in qemu-file.c to not add qemu-timer.c as dependency to qemu-file.c
147c3049a56SJuan Quintela */
148c3049a56SJuan Quintela
timer_put(QEMUFile * f,QEMUTimer * ts)149c3049a56SJuan Quintela void timer_put(QEMUFile *f, QEMUTimer *ts)
150c3049a56SJuan Quintela {
151c3049a56SJuan Quintela uint64_t expire_time;
152c3049a56SJuan Quintela
153c3049a56SJuan Quintela expire_time = timer_expire_time_ns(ts);
154c3049a56SJuan Quintela qemu_put_be64(f, expire_time);
155c3049a56SJuan Quintela }
156c3049a56SJuan Quintela
timer_get(QEMUFile * f,QEMUTimer * ts)157c3049a56SJuan Quintela void timer_get(QEMUFile *f, QEMUTimer *ts)
158c3049a56SJuan Quintela {
159c3049a56SJuan Quintela uint64_t expire_time;
160c3049a56SJuan Quintela
161c3049a56SJuan Quintela expire_time = qemu_get_be64(f);
162c3049a56SJuan Quintela if (expire_time != -1) {
163c3049a56SJuan Quintela timer_mod_ns(ts, expire_time);
164c3049a56SJuan Quintela } else {
165c3049a56SJuan Quintela timer_del(ts);
166c3049a56SJuan Quintela }
167c3049a56SJuan Quintela }
168c3049a56SJuan Quintela
169c3049a56SJuan Quintela
170c3049a56SJuan Quintela /* VMState timer support.
171c3049a56SJuan Quintela * Not in vmstate.c to not add qemu-timer.c as dependency to vmstate.c
172c3049a56SJuan Quintela */
173c3049a56SJuan Quintela
get_timer(QEMUFile * f,void * pv,size_t size,const VMStateField * field)17403fee66fSMarc-André Lureau static int get_timer(QEMUFile *f, void *pv, size_t size,
17503fee66fSMarc-André Lureau const VMStateField *field)
176c3049a56SJuan Quintela {
177c3049a56SJuan Quintela QEMUTimer *v = pv;
178c3049a56SJuan Quintela timer_get(f, v);
179c3049a56SJuan Quintela return 0;
180c3049a56SJuan Quintela }
181c3049a56SJuan Quintela
put_timer(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)18203fee66fSMarc-André Lureau static int put_timer(QEMUFile *f, void *pv, size_t size,
1833ddba9a9SMarkus Armbruster const VMStateField *field, JSONWriter *vmdesc)
184c3049a56SJuan Quintela {
185c3049a56SJuan Quintela QEMUTimer *v = pv;
186c3049a56SJuan Quintela timer_put(f, v);
1872c21ee76SJianjun Duan
1882c21ee76SJianjun Duan return 0;
189c3049a56SJuan Quintela }
190c3049a56SJuan Quintela
191c3049a56SJuan Quintela const VMStateInfo vmstate_info_timer = {
192c3049a56SJuan Quintela .name = "timer",
193c3049a56SJuan Quintela .get = get_timer,
194c3049a56SJuan Quintela .put = put_timer,
195c3049a56SJuan Quintela };
196c3049a56SJuan Quintela
197c3049a56SJuan Quintela
198c3049a56SJuan Quintela typedef struct CompatEntry {
199c3049a56SJuan Quintela char idstr[256];
200c3049a56SJuan Quintela int instance_id;
201c3049a56SJuan Quintela } CompatEntry;
202c3049a56SJuan Quintela
203c3049a56SJuan Quintela typedef struct SaveStateEntry {
204c3049a56SJuan Quintela QTAILQ_ENTRY(SaveStateEntry) entry;
205c3049a56SJuan Quintela char idstr[256];
20693062e23SPeter Xu uint32_t instance_id;
207c3049a56SJuan Quintela int alias_id;
208c3049a56SJuan Quintela int version_id;
2090f42f657SJuan Quintela /* version id read from the stream */
2100f42f657SJuan Quintela int load_version_id;
211c3049a56SJuan Quintela int section_id;
2120f42f657SJuan Quintela /* section id read from the stream */
2130f42f657SJuan Quintela int load_section_id;
214de22ded0SMarc-André Lureau const SaveVMHandlers *ops;
215c3049a56SJuan Quintela const VMStateDescription *vmsd;
216c3049a56SJuan Quintela void *opaque;
217c3049a56SJuan Quintela CompatEntry *compat;
218c3049a56SJuan Quintela int is_ram;
219c3049a56SJuan Quintela } SaveStateEntry;
220c3049a56SJuan Quintela
2210163a2e0SJuan Quintela typedef struct SaveState {
2220163a2e0SJuan Quintela QTAILQ_HEAD(, SaveStateEntry) handlers;
223174723ffSScott Cheloha SaveStateEntry *handler_pri_head[MIG_PRI_MAX + 1];
2240163a2e0SJuan Quintela int global_section_id;
22561964c23SJuan Quintela uint32_t len;
22661964c23SJuan Quintela const char *name;
22759811a32SPeter Maydell uint32_t target_page_bits;
2286cafc8e4SYury Kotov uint32_t caps_count;
2296cafc8e4SYury Kotov MigrationCapability *capabilities;
230b9d68df6SYury Kotov QemuUUID uuid;
2310163a2e0SJuan Quintela } SaveState;
232c3049a56SJuan Quintela
2330163a2e0SJuan Quintela static SaveState savevm_state = {
2340163a2e0SJuan Quintela .handlers = QTAILQ_HEAD_INITIALIZER(savevm_state.handlers),
235174723ffSScott Cheloha .handler_pri_head = { [MIG_PRI_DEFAULT ... MIG_PRI_MAX] = NULL },
2360163a2e0SJuan Quintela .global_section_id = 0,
23761964c23SJuan Quintela };
23861964c23SJuan Quintela
239caa91b3cSPeter Xu static SaveStateEntry *find_se(const char *idstr, uint32_t instance_id);
240caa91b3cSPeter Xu
should_validate_capability(int capability)2416cafc8e4SYury Kotov static bool should_validate_capability(int capability)
2426cafc8e4SYury Kotov {
2436cafc8e4SYury Kotov assert(capability >= 0 && capability < MIGRATION_CAPABILITY__MAX);
2446cafc8e4SYury Kotov /* Validate only new capabilities to keep compatibility. */
2456cafc8e4SYury Kotov switch (capability) {
2466cafc8e4SYury Kotov case MIGRATION_CAPABILITY_X_IGNORE_SHARED:
2474ed49febSFabiano Rosas case MIGRATION_CAPABILITY_MAPPED_RAM:
2486cafc8e4SYury Kotov return true;
2496cafc8e4SYury Kotov default:
2506cafc8e4SYury Kotov return false;
2516cafc8e4SYury Kotov }
2526cafc8e4SYury Kotov }
2536cafc8e4SYury Kotov
get_validatable_capabilities_count(void)2546cafc8e4SYury Kotov static uint32_t get_validatable_capabilities_count(void)
2556cafc8e4SYury Kotov {
2566cafc8e4SYury Kotov MigrationState *s = migrate_get_current();
2576cafc8e4SYury Kotov uint32_t result = 0;
2586cafc8e4SYury Kotov int i;
2596cafc8e4SYury Kotov for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
2600cec2056SJuan Quintela if (should_validate_capability(i) && s->capabilities[i]) {
2616cafc8e4SYury Kotov result++;
2626cafc8e4SYury Kotov }
2636cafc8e4SYury Kotov }
2646cafc8e4SYury Kotov return result;
2656cafc8e4SYury Kotov }
2666cafc8e4SYury Kotov
configuration_pre_save(void * opaque)26744b1ff31SDr. David Alan Gilbert static int configuration_pre_save(void *opaque)
26861964c23SJuan Quintela {
26961964c23SJuan Quintela SaveState *state = opaque;
27061964c23SJuan Quintela const char *current_name = MACHINE_GET_CLASS(current_machine)->name;
2716cafc8e4SYury Kotov MigrationState *s = migrate_get_current();
2726cafc8e4SYury Kotov int i, j;
27361964c23SJuan Quintela
27461964c23SJuan Quintela state->len = strlen(current_name);
27561964c23SJuan Quintela state->name = current_name;
27646d702b1SJuan Quintela state->target_page_bits = qemu_target_page_bits();
27744b1ff31SDr. David Alan Gilbert
2786cafc8e4SYury Kotov state->caps_count = get_validatable_capabilities_count();
2796cafc8e4SYury Kotov state->capabilities = g_renew(MigrationCapability, state->capabilities,
2806cafc8e4SYury Kotov state->caps_count);
2816cafc8e4SYury Kotov for (i = j = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
2820cec2056SJuan Quintela if (should_validate_capability(i) && s->capabilities[i]) {
2836cafc8e4SYury Kotov state->capabilities[j++] = i;
2846cafc8e4SYury Kotov }
2856cafc8e4SYury Kotov }
286b9d68df6SYury Kotov state->uuid = qemu_uuid;
2876cafc8e4SYury Kotov
28844b1ff31SDr. David Alan Gilbert return 0;
28959811a32SPeter Maydell }
29059811a32SPeter Maydell
configuration_post_save(void * opaque)29139f633d4SJinhao Gao static int configuration_post_save(void *opaque)
29239f633d4SJinhao Gao {
29339f633d4SJinhao Gao SaveState *state = opaque;
29439f633d4SJinhao Gao
29539f633d4SJinhao Gao g_free(state->capabilities);
29639f633d4SJinhao Gao state->capabilities = NULL;
29739f633d4SJinhao Gao state->caps_count = 0;
29839f633d4SJinhao Gao return 0;
29939f633d4SJinhao Gao }
30039f633d4SJinhao Gao
configuration_pre_load(void * opaque)30159811a32SPeter Maydell static int configuration_pre_load(void *opaque)
30259811a32SPeter Maydell {
30359811a32SPeter Maydell SaveState *state = opaque;
30459811a32SPeter Maydell
30559811a32SPeter Maydell /* If there is no target-page-bits subsection it means the source
30659811a32SPeter Maydell * predates the variable-target-page-bits support and is using the
30759811a32SPeter Maydell * minimum possible value for this CPU.
30859811a32SPeter Maydell */
30946d702b1SJuan Quintela state->target_page_bits = qemu_target_page_bits_min();
31059811a32SPeter Maydell return 0;
31161964c23SJuan Quintela }
31261964c23SJuan Quintela
configuration_validate_capabilities(SaveState * state)3136cafc8e4SYury Kotov static bool configuration_validate_capabilities(SaveState *state)
3146cafc8e4SYury Kotov {
3156cafc8e4SYury Kotov bool ret = true;
3166cafc8e4SYury Kotov MigrationState *s = migrate_get_current();
3176cafc8e4SYury Kotov unsigned long *source_caps_bm;
3186cafc8e4SYury Kotov int i;
3196cafc8e4SYury Kotov
3206cafc8e4SYury Kotov source_caps_bm = bitmap_new(MIGRATION_CAPABILITY__MAX);
3216cafc8e4SYury Kotov for (i = 0; i < state->caps_count; i++) {
3226cafc8e4SYury Kotov MigrationCapability capability = state->capabilities[i];
3236cafc8e4SYury Kotov set_bit(capability, source_caps_bm);
3246cafc8e4SYury Kotov }
3256cafc8e4SYury Kotov
3266cafc8e4SYury Kotov for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
3276cafc8e4SYury Kotov bool source_state, target_state;
3286cafc8e4SYury Kotov if (!should_validate_capability(i)) {
3296cafc8e4SYury Kotov continue;
3306cafc8e4SYury Kotov }
3316cafc8e4SYury Kotov source_state = test_bit(i, source_caps_bm);
3320cec2056SJuan Quintela target_state = s->capabilities[i];
3336cafc8e4SYury Kotov if (source_state != target_state) {
3346cafc8e4SYury Kotov error_report("Capability %s is %s, but received capability is %s",
3356cafc8e4SYury Kotov MigrationCapability_str(i),
3366cafc8e4SYury Kotov target_state ? "on" : "off",
3376cafc8e4SYury Kotov source_state ? "on" : "off");
3386cafc8e4SYury Kotov ret = false;
3396cafc8e4SYury Kotov /* Don't break here to report all failed capabilities */
3406cafc8e4SYury Kotov }
3416cafc8e4SYury Kotov }
3426cafc8e4SYury Kotov
3436cafc8e4SYury Kotov g_free(source_caps_bm);
3446cafc8e4SYury Kotov return ret;
3456cafc8e4SYury Kotov }
3466cafc8e4SYury Kotov
configuration_post_load(void * opaque,int version_id)34761964c23SJuan Quintela static int configuration_post_load(void *opaque, int version_id)
34861964c23SJuan Quintela {
34961964c23SJuan Quintela SaveState *state = opaque;
35061964c23SJuan Quintela const char *current_name = MACHINE_GET_CLASS(current_machine)->name;
35139f633d4SJinhao Gao int ret = 0;
35261964c23SJuan Quintela
35361964c23SJuan Quintela if (strncmp(state->name, current_name, state->len) != 0) {
35415d61692SGreg Kurz error_report("Machine type received is '%.*s' and local is '%s'",
35515d61692SGreg Kurz (int) state->len, state->name, current_name);
35639f633d4SJinhao Gao ret = -EINVAL;
35739f633d4SJinhao Gao goto out;
35861964c23SJuan Quintela }
35959811a32SPeter Maydell
36046d702b1SJuan Quintela if (state->target_page_bits != qemu_target_page_bits()) {
36159811a32SPeter Maydell error_report("Received TARGET_PAGE_BITS is %d but local is %d",
36246d702b1SJuan Quintela state->target_page_bits, qemu_target_page_bits());
36339f633d4SJinhao Gao ret = -EINVAL;
36439f633d4SJinhao Gao goto out;
36559811a32SPeter Maydell }
36659811a32SPeter Maydell
3676cafc8e4SYury Kotov if (!configuration_validate_capabilities(state)) {
36839f633d4SJinhao Gao ret = -EINVAL;
36939f633d4SJinhao Gao goto out;
3706cafc8e4SYury Kotov }
3716cafc8e4SYury Kotov
37239f633d4SJinhao Gao out:
37339f633d4SJinhao Gao g_free((void *)state->name);
37439f633d4SJinhao Gao state->name = NULL;
37539f633d4SJinhao Gao state->len = 0;
37639f633d4SJinhao Gao g_free(state->capabilities);
37739f633d4SJinhao Gao state->capabilities = NULL;
37839f633d4SJinhao Gao state->caps_count = 0;
37939f633d4SJinhao Gao
38039f633d4SJinhao Gao return ret;
38161964c23SJuan Quintela }
38261964c23SJuan Quintela
get_capability(QEMUFile * f,void * pv,size_t size,const VMStateField * field)3836cafc8e4SYury Kotov static int get_capability(QEMUFile *f, void *pv, size_t size,
3846cafc8e4SYury Kotov const VMStateField *field)
3856cafc8e4SYury Kotov {
3866cafc8e4SYury Kotov MigrationCapability *capability = pv;
3876cafc8e4SYury Kotov char capability_str[UINT8_MAX + 1];
3886cafc8e4SYury Kotov uint8_t len;
3896cafc8e4SYury Kotov int i;
3906cafc8e4SYury Kotov
3916cafc8e4SYury Kotov len = qemu_get_byte(f);
3926cafc8e4SYury Kotov qemu_get_buffer(f, (uint8_t *)capability_str, len);
3936cafc8e4SYury Kotov capability_str[len] = '\0';
3946cafc8e4SYury Kotov for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
3956cafc8e4SYury Kotov if (!strcmp(MigrationCapability_str(i), capability_str)) {
3966cafc8e4SYury Kotov *capability = i;
3976cafc8e4SYury Kotov return 0;
3986cafc8e4SYury Kotov }
3996cafc8e4SYury Kotov }
4006cafc8e4SYury Kotov error_report("Received unknown capability %s", capability_str);
4016cafc8e4SYury Kotov return -EINVAL;
4026cafc8e4SYury Kotov }
4036cafc8e4SYury Kotov
put_capability(QEMUFile * f,void * pv,size_t size,const VMStateField * field,JSONWriter * vmdesc)4046cafc8e4SYury Kotov static int put_capability(QEMUFile *f, void *pv, size_t size,
4053ddba9a9SMarkus Armbruster const VMStateField *field, JSONWriter *vmdesc)
4066cafc8e4SYury Kotov {
4076cafc8e4SYury Kotov MigrationCapability *capability = pv;
4086cafc8e4SYury Kotov const char *capability_str = MigrationCapability_str(*capability);
4096cafc8e4SYury Kotov size_t len = strlen(capability_str);
4106cafc8e4SYury Kotov assert(len <= UINT8_MAX);
4116cafc8e4SYury Kotov
4126cafc8e4SYury Kotov qemu_put_byte(f, len);
4136cafc8e4SYury Kotov qemu_put_buffer(f, (uint8_t *)capability_str, len);
4146cafc8e4SYury Kotov return 0;
4156cafc8e4SYury Kotov }
4166cafc8e4SYury Kotov
4176cafc8e4SYury Kotov static const VMStateInfo vmstate_info_capability = {
4186cafc8e4SYury Kotov .name = "capability",
4196cafc8e4SYury Kotov .get = get_capability,
4206cafc8e4SYury Kotov .put = put_capability,
4216cafc8e4SYury Kotov };
4226cafc8e4SYury Kotov
42359811a32SPeter Maydell /* The target-page-bits subsection is present only if the
42459811a32SPeter Maydell * target page size is not the same as the default (ie the
42559811a32SPeter Maydell * minimum page size for a variable-page-size guest CPU).
42659811a32SPeter Maydell * If it is present then it contains the actual target page
42759811a32SPeter Maydell * bits for the machine, and migration will fail if the
42859811a32SPeter Maydell * two ends don't agree about it.
42959811a32SPeter Maydell */
vmstate_target_page_bits_needed(void * opaque)43059811a32SPeter Maydell static bool vmstate_target_page_bits_needed(void *opaque)
43159811a32SPeter Maydell {
43246d702b1SJuan Quintela return qemu_target_page_bits()
43346d702b1SJuan Quintela > qemu_target_page_bits_min();
43459811a32SPeter Maydell }
43559811a32SPeter Maydell
43659811a32SPeter Maydell static const VMStateDescription vmstate_target_page_bits = {
43759811a32SPeter Maydell .name = "configuration/target-page-bits",
43859811a32SPeter Maydell .version_id = 1,
43959811a32SPeter Maydell .minimum_version_id = 1,
44059811a32SPeter Maydell .needed = vmstate_target_page_bits_needed,
441a77ffe95SRichard Henderson .fields = (const VMStateField[]) {
44259811a32SPeter Maydell VMSTATE_UINT32(target_page_bits, SaveState),
44359811a32SPeter Maydell VMSTATE_END_OF_LIST()
44459811a32SPeter Maydell }
44559811a32SPeter Maydell };
44659811a32SPeter Maydell
vmstate_capabilites_needed(void * opaque)4476cafc8e4SYury Kotov static bool vmstate_capabilites_needed(void *opaque)
4486cafc8e4SYury Kotov {
4496cafc8e4SYury Kotov return get_validatable_capabilities_count() > 0;
4506cafc8e4SYury Kotov }
4516cafc8e4SYury Kotov
4526cafc8e4SYury Kotov static const VMStateDescription vmstate_capabilites = {
4536cafc8e4SYury Kotov .name = "configuration/capabilities",
4546cafc8e4SYury Kotov .version_id = 1,
4556cafc8e4SYury Kotov .minimum_version_id = 1,
4566cafc8e4SYury Kotov .needed = vmstate_capabilites_needed,
457a77ffe95SRichard Henderson .fields = (const VMStateField[]) {
4586cafc8e4SYury Kotov VMSTATE_UINT32_V(caps_count, SaveState, 1),
4596cafc8e4SYury Kotov VMSTATE_VARRAY_UINT32_ALLOC(capabilities, SaveState, caps_count, 1,
4606cafc8e4SYury Kotov vmstate_info_capability,
4616cafc8e4SYury Kotov MigrationCapability),
4626cafc8e4SYury Kotov VMSTATE_END_OF_LIST()
4636cafc8e4SYury Kotov }
4646cafc8e4SYury Kotov };
4656cafc8e4SYury Kotov
vmstate_uuid_needed(void * opaque)466b9d68df6SYury Kotov static bool vmstate_uuid_needed(void *opaque)
467b9d68df6SYury Kotov {
468b9d68df6SYury Kotov return qemu_uuid_set && migrate_validate_uuid();
469b9d68df6SYury Kotov }
470b9d68df6SYury Kotov
vmstate_uuid_post_load(void * opaque,int version_id)471b9d68df6SYury Kotov static int vmstate_uuid_post_load(void *opaque, int version_id)
472b9d68df6SYury Kotov {
473b9d68df6SYury Kotov SaveState *state = opaque;
474721da039SCédric Le Goater char uuid_src[UUID_STR_LEN];
475721da039SCédric Le Goater char uuid_dst[UUID_STR_LEN];
476b9d68df6SYury Kotov
477b9d68df6SYury Kotov if (!qemu_uuid_set) {
478b9d68df6SYury Kotov /*
479b9d68df6SYury Kotov * It's warning because user might not know UUID in some cases,
480b9d68df6SYury Kotov * e.g. load an old snapshot
481b9d68df6SYury Kotov */
482b9d68df6SYury Kotov qemu_uuid_unparse(&state->uuid, uuid_src);
483b9d68df6SYury Kotov warn_report("UUID is received %s, but local uuid isn't set",
484b9d68df6SYury Kotov uuid_src);
485b9d68df6SYury Kotov return 0;
486b9d68df6SYury Kotov }
487b9d68df6SYury Kotov if (!qemu_uuid_is_equal(&state->uuid, &qemu_uuid)) {
488b9d68df6SYury Kotov qemu_uuid_unparse(&state->uuid, uuid_src);
489b9d68df6SYury Kotov qemu_uuid_unparse(&qemu_uuid, uuid_dst);
490b9d68df6SYury Kotov error_report("UUID received is %s and local is %s", uuid_src, uuid_dst);
491b9d68df6SYury Kotov return -EINVAL;
492b9d68df6SYury Kotov }
493b9d68df6SYury Kotov return 0;
494b9d68df6SYury Kotov }
495b9d68df6SYury Kotov
496b9d68df6SYury Kotov static const VMStateDescription vmstate_uuid = {
497b9d68df6SYury Kotov .name = "configuration/uuid",
498b9d68df6SYury Kotov .version_id = 1,
499b9d68df6SYury Kotov .minimum_version_id = 1,
500b9d68df6SYury Kotov .needed = vmstate_uuid_needed,
501b9d68df6SYury Kotov .post_load = vmstate_uuid_post_load,
502a77ffe95SRichard Henderson .fields = (const VMStateField[]) {
503b9d68df6SYury Kotov VMSTATE_UINT8_ARRAY_V(uuid.data, SaveState, sizeof(QemuUUID), 1),
504b9d68df6SYury Kotov VMSTATE_END_OF_LIST()
505b9d68df6SYury Kotov }
506b9d68df6SYury Kotov };
507b9d68df6SYury Kotov
50861964c23SJuan Quintela static const VMStateDescription vmstate_configuration = {
50961964c23SJuan Quintela .name = "configuration",
51061964c23SJuan Quintela .version_id = 1,
51159811a32SPeter Maydell .pre_load = configuration_pre_load,
51261964c23SJuan Quintela .post_load = configuration_post_load,
51361964c23SJuan Quintela .pre_save = configuration_pre_save,
51439f633d4SJinhao Gao .post_save = configuration_post_save,
515a77ffe95SRichard Henderson .fields = (const VMStateField[]) {
51661964c23SJuan Quintela VMSTATE_UINT32(len, SaveState),
51759046ec2SHalil Pasic VMSTATE_VBUFFER_ALLOC_UINT32(name, SaveState, 0, NULL, len),
51861964c23SJuan Quintela VMSTATE_END_OF_LIST()
51961964c23SJuan Quintela },
520a77ffe95SRichard Henderson .subsections = (const VMStateDescription * const []) {
52159811a32SPeter Maydell &vmstate_target_page_bits,
5226cafc8e4SYury Kotov &vmstate_capabilites,
523b9d68df6SYury Kotov &vmstate_uuid,
52459811a32SPeter Maydell NULL
52559811a32SPeter Maydell }
5260163a2e0SJuan Quintela };
527c3049a56SJuan Quintela
528c3049a56SJuan Quintela static void dump_vmstate_vmsd(FILE *out_file,
529c3049a56SJuan Quintela const VMStateDescription *vmsd, int indent,
530c3049a56SJuan Quintela bool is_subsection);
531c3049a56SJuan Quintela
dump_vmstate_vmsf(FILE * out_file,const VMStateField * field,int indent)532c3049a56SJuan Quintela static void dump_vmstate_vmsf(FILE *out_file, const VMStateField *field,
533c3049a56SJuan Quintela int indent)
534c3049a56SJuan Quintela {
535c3049a56SJuan Quintela fprintf(out_file, "%*s{\n", indent, "");
536c3049a56SJuan Quintela indent += 2;
537c3049a56SJuan Quintela fprintf(out_file, "%*s\"field\": \"%s\",\n", indent, "", field->name);
538c3049a56SJuan Quintela fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",
539c3049a56SJuan Quintela field->version_id);
540c3049a56SJuan Quintela fprintf(out_file, "%*s\"field_exists\": %s,\n", indent, "",
541c3049a56SJuan Quintela field->field_exists ? "true" : "false");
54212c81e5aSPeter Xu if (field->flags & VMS_ARRAY) {
54312c81e5aSPeter Xu fprintf(out_file, "%*s\"num\": %d,\n", indent, "", field->num);
54412c81e5aSPeter Xu }
545c3049a56SJuan Quintela fprintf(out_file, "%*s\"size\": %zu", indent, "", field->size);
546c3049a56SJuan Quintela if (field->vmsd != NULL) {
547c3049a56SJuan Quintela fprintf(out_file, ",\n");
548c3049a56SJuan Quintela dump_vmstate_vmsd(out_file, field->vmsd, indent, false);
549c3049a56SJuan Quintela }
550c3049a56SJuan Quintela fprintf(out_file, "\n%*s}", indent - 2, "");
551c3049a56SJuan Quintela }
552c3049a56SJuan Quintela
dump_vmstate_vmss(FILE * out_file,const VMStateDescription * subsection,int indent)553c3049a56SJuan Quintela static void dump_vmstate_vmss(FILE *out_file,
55420270019SRichard Henderson const VMStateDescription *subsection,
555c3049a56SJuan Quintela int indent)
556c3049a56SJuan Quintela {
55720270019SRichard Henderson if (subsection != NULL) {
55820270019SRichard Henderson dump_vmstate_vmsd(out_file, subsection, indent, true);
559c3049a56SJuan Quintela }
560c3049a56SJuan Quintela }
561c3049a56SJuan Quintela
dump_vmstate_vmsd(FILE * out_file,const VMStateDescription * vmsd,int indent,bool is_subsection)562c3049a56SJuan Quintela static void dump_vmstate_vmsd(FILE *out_file,
563c3049a56SJuan Quintela const VMStateDescription *vmsd, int indent,
564c3049a56SJuan Quintela bool is_subsection)
565c3049a56SJuan Quintela {
566c3049a56SJuan Quintela if (is_subsection) {
567c3049a56SJuan Quintela fprintf(out_file, "%*s{\n", indent, "");
568c3049a56SJuan Quintela } else {
569c3049a56SJuan Quintela fprintf(out_file, "%*s\"%s\": {\n", indent, "", "Description");
570c3049a56SJuan Quintela }
571c3049a56SJuan Quintela indent += 2;
572c3049a56SJuan Quintela fprintf(out_file, "%*s\"name\": \"%s\",\n", indent, "", vmsd->name);
573c3049a56SJuan Quintela fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",
574c3049a56SJuan Quintela vmsd->version_id);
575c3049a56SJuan Quintela fprintf(out_file, "%*s\"minimum_version_id\": %d", indent, "",
576c3049a56SJuan Quintela vmsd->minimum_version_id);
577c3049a56SJuan Quintela if (vmsd->fields != NULL) {
578c3049a56SJuan Quintela const VMStateField *field = vmsd->fields;
579c3049a56SJuan Quintela bool first;
580c3049a56SJuan Quintela
581c3049a56SJuan Quintela fprintf(out_file, ",\n%*s\"Fields\": [\n", indent, "");
582c3049a56SJuan Quintela first = true;
583c3049a56SJuan Quintela while (field->name != NULL) {
584c3049a56SJuan Quintela if (field->flags & VMS_MUST_EXIST) {
585c3049a56SJuan Quintela /* Ignore VMSTATE_VALIDATE bits; these don't get migrated */
586c3049a56SJuan Quintela field++;
587c3049a56SJuan Quintela continue;
588c3049a56SJuan Quintela }
589c3049a56SJuan Quintela if (!first) {
590c3049a56SJuan Quintela fprintf(out_file, ",\n");
591c3049a56SJuan Quintela }
592c3049a56SJuan Quintela dump_vmstate_vmsf(out_file, field, indent + 2);
593c3049a56SJuan Quintela field++;
594c3049a56SJuan Quintela first = false;
595c3049a56SJuan Quintela }
59689c56848SDr. David Alan Gilbert assert(field->flags == VMS_END);
597c3049a56SJuan Quintela fprintf(out_file, "\n%*s]", indent, "");
598c3049a56SJuan Quintela }
599c3049a56SJuan Quintela if (vmsd->subsections != NULL) {
60020270019SRichard Henderson const VMStateDescription * const *subsection = vmsd->subsections;
601c3049a56SJuan Quintela bool first;
602c3049a56SJuan Quintela
603c3049a56SJuan Quintela fprintf(out_file, ",\n%*s\"Subsections\": [\n", indent, "");
604c3049a56SJuan Quintela first = true;
6055cd8cadaSJuan Quintela while (*subsection != NULL) {
606c3049a56SJuan Quintela if (!first) {
607c3049a56SJuan Quintela fprintf(out_file, ",\n");
608c3049a56SJuan Quintela }
60920270019SRichard Henderson dump_vmstate_vmss(out_file, *subsection, indent + 2);
610c3049a56SJuan Quintela subsection++;
611c3049a56SJuan Quintela first = false;
612c3049a56SJuan Quintela }
613c3049a56SJuan Quintela fprintf(out_file, "\n%*s]", indent, "");
614c3049a56SJuan Quintela }
615c3049a56SJuan Quintela fprintf(out_file, "\n%*s}", indent - 2, "");
616c3049a56SJuan Quintela }
617c3049a56SJuan Quintela
dump_machine_type(FILE * out_file)618c3049a56SJuan Quintela static void dump_machine_type(FILE *out_file)
619c3049a56SJuan Quintela {
620c3049a56SJuan Quintela MachineClass *mc;
621c3049a56SJuan Quintela
622c3049a56SJuan Quintela mc = MACHINE_GET_CLASS(current_machine);
623c3049a56SJuan Quintela
624c3049a56SJuan Quintela fprintf(out_file, " \"vmschkmachine\": {\n");
625c3049a56SJuan Quintela fprintf(out_file, " \"Name\": \"%s\"\n", mc->name);
626c3049a56SJuan Quintela fprintf(out_file, " },\n");
627c3049a56SJuan Quintela }
628c3049a56SJuan Quintela
dump_vmstate_json_to_file(FILE * out_file)629c3049a56SJuan Quintela void dump_vmstate_json_to_file(FILE *out_file)
630c3049a56SJuan Quintela {
631c3049a56SJuan Quintela GSList *list, *elt;
632c3049a56SJuan Quintela bool first;
633c3049a56SJuan Quintela
634c3049a56SJuan Quintela fprintf(out_file, "{\n");
635c3049a56SJuan Quintela dump_machine_type(out_file);
636c3049a56SJuan Quintela
637c3049a56SJuan Quintela first = true;
638c3049a56SJuan Quintela list = object_class_get_list(TYPE_DEVICE, true);
639c3049a56SJuan Quintela for (elt = list; elt; elt = elt->next) {
640c3049a56SJuan Quintela DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data,
641c3049a56SJuan Quintela TYPE_DEVICE);
642c3049a56SJuan Quintela const char *name;
643c3049a56SJuan Quintela int indent = 2;
644c3049a56SJuan Quintela
645c3049a56SJuan Quintela if (!dc->vmsd) {
646c3049a56SJuan Quintela continue;
647c3049a56SJuan Quintela }
648c3049a56SJuan Quintela
649c3049a56SJuan Quintela if (!first) {
650c3049a56SJuan Quintela fprintf(out_file, ",\n");
651c3049a56SJuan Quintela }
652c3049a56SJuan Quintela name = object_class_get_name(OBJECT_CLASS(dc));
653c3049a56SJuan Quintela fprintf(out_file, "%*s\"%s\": {\n", indent, "", name);
654c3049a56SJuan Quintela indent += 2;
655c3049a56SJuan Quintela fprintf(out_file, "%*s\"Name\": \"%s\",\n", indent, "", name);
656c3049a56SJuan Quintela fprintf(out_file, "%*s\"version_id\": %d,\n", indent, "",
657c3049a56SJuan Quintela dc->vmsd->version_id);
658c3049a56SJuan Quintela fprintf(out_file, "%*s\"minimum_version_id\": %d,\n", indent, "",
659c3049a56SJuan Quintela dc->vmsd->minimum_version_id);
660c3049a56SJuan Quintela
661c3049a56SJuan Quintela dump_vmstate_vmsd(out_file, dc->vmsd, indent, false);
662c3049a56SJuan Quintela
663c3049a56SJuan Quintela fprintf(out_file, "\n%*s}", indent - 2, "");
664c3049a56SJuan Quintela first = false;
665c3049a56SJuan Quintela }
666c3049a56SJuan Quintela fprintf(out_file, "\n}\n");
667c3049a56SJuan Quintela fclose(out_file);
66826daeba4SPan Nengyuan g_slist_free(list);
669c3049a56SJuan Quintela }
670c3049a56SJuan Quintela
calculate_new_instance_id(const char * idstr)67193062e23SPeter Xu static uint32_t calculate_new_instance_id(const char *idstr)
672c3049a56SJuan Quintela {
673c3049a56SJuan Quintela SaveStateEntry *se;
67493062e23SPeter Xu uint32_t instance_id = 0;
675c3049a56SJuan Quintela
6760163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
677c3049a56SJuan Quintela if (strcmp(idstr, se->idstr) == 0
678c3049a56SJuan Quintela && instance_id <= se->instance_id) {
679c3049a56SJuan Quintela instance_id = se->instance_id + 1;
680c3049a56SJuan Quintela }
681c3049a56SJuan Quintela }
68293062e23SPeter Xu /* Make sure we never loop over without being noticed */
68393062e23SPeter Xu assert(instance_id != VMSTATE_INSTANCE_ID_ANY);
684c3049a56SJuan Quintela return instance_id;
685c3049a56SJuan Quintela }
686c3049a56SJuan Quintela
calculate_compat_instance_id(const char * idstr)687c3049a56SJuan Quintela static int calculate_compat_instance_id(const char *idstr)
688c3049a56SJuan Quintela {
689c3049a56SJuan Quintela SaveStateEntry *se;
690c3049a56SJuan Quintela int instance_id = 0;
691c3049a56SJuan Quintela
6920163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
693c3049a56SJuan Quintela if (!se->compat) {
694c3049a56SJuan Quintela continue;
695c3049a56SJuan Quintela }
696c3049a56SJuan Quintela
697c3049a56SJuan Quintela if (strcmp(idstr, se->compat->idstr) == 0
698c3049a56SJuan Quintela && instance_id <= se->compat->instance_id) {
699c3049a56SJuan Quintela instance_id = se->compat->instance_id + 1;
700c3049a56SJuan Quintela }
701c3049a56SJuan Quintela }
702c3049a56SJuan Quintela return instance_id;
703c3049a56SJuan Quintela }
704c3049a56SJuan Quintela
save_state_priority(SaveStateEntry * se)705f37bc036SPeter Xu static inline MigrationPriority save_state_priority(SaveStateEntry *se)
706f37bc036SPeter Xu {
707f37bc036SPeter Xu if (se->vmsd) {
708f37bc036SPeter Xu return se->vmsd->priority;
709f37bc036SPeter Xu }
710f37bc036SPeter Xu return MIG_PRI_DEFAULT;
711f37bc036SPeter Xu }
712f37bc036SPeter Xu
savevm_state_handler_insert(SaveStateEntry * nse)713f37bc036SPeter Xu static void savevm_state_handler_insert(SaveStateEntry *nse)
714f37bc036SPeter Xu {
715f37bc036SPeter Xu MigrationPriority priority = save_state_priority(nse);
716f37bc036SPeter Xu SaveStateEntry *se;
717174723ffSScott Cheloha int i;
718f37bc036SPeter Xu
719f37bc036SPeter Xu assert(priority <= MIG_PRI_MAX);
720f37bc036SPeter Xu
721caa91b3cSPeter Xu /*
722caa91b3cSPeter Xu * This should never happen otherwise migration will probably fail
723caa91b3cSPeter Xu * silently somewhere because we can be wrongly applying one
724caa91b3cSPeter Xu * object properties upon another one. Bail out ASAP.
725caa91b3cSPeter Xu */
726caa91b3cSPeter Xu if (find_se(nse->idstr, nse->instance_id)) {
727caa91b3cSPeter Xu error_report("%s: Detected duplicate SaveStateEntry: "
728caa91b3cSPeter Xu "id=%s, instance_id=0x%"PRIx32, __func__,
729caa91b3cSPeter Xu nse->idstr, nse->instance_id);
730caa91b3cSPeter Xu exit(EXIT_FAILURE);
731caa91b3cSPeter Xu }
732caa91b3cSPeter Xu
733174723ffSScott Cheloha for (i = priority - 1; i >= 0; i--) {
734174723ffSScott Cheloha se = savevm_state.handler_pri_head[i];
735174723ffSScott Cheloha if (se != NULL) {
736174723ffSScott Cheloha assert(save_state_priority(se) < priority);
737f37bc036SPeter Xu break;
738f37bc036SPeter Xu }
739f37bc036SPeter Xu }
740f37bc036SPeter Xu
741174723ffSScott Cheloha if (i >= 0) {
742f37bc036SPeter Xu QTAILQ_INSERT_BEFORE(se, nse, entry);
743f37bc036SPeter Xu } else {
744f37bc036SPeter Xu QTAILQ_INSERT_TAIL(&savevm_state.handlers, nse, entry);
745f37bc036SPeter Xu }
746174723ffSScott Cheloha
747174723ffSScott Cheloha if (savevm_state.handler_pri_head[priority] == NULL) {
748174723ffSScott Cheloha savevm_state.handler_pri_head[priority] = nse;
749174723ffSScott Cheloha }
750f37bc036SPeter Xu }
751f37bc036SPeter Xu
savevm_state_handler_remove(SaveStateEntry * se)752bd5de61eSScott Cheloha static void savevm_state_handler_remove(SaveStateEntry *se)
753bd5de61eSScott Cheloha {
754174723ffSScott Cheloha SaveStateEntry *next;
755174723ffSScott Cheloha MigrationPriority priority = save_state_priority(se);
756174723ffSScott Cheloha
757174723ffSScott Cheloha if (se == savevm_state.handler_pri_head[priority]) {
758174723ffSScott Cheloha next = QTAILQ_NEXT(se, entry);
759174723ffSScott Cheloha if (next != NULL && save_state_priority(next) == priority) {
760174723ffSScott Cheloha savevm_state.handler_pri_head[priority] = next;
761174723ffSScott Cheloha } else {
762174723ffSScott Cheloha savevm_state.handler_pri_head[priority] = NULL;
763174723ffSScott Cheloha }
764174723ffSScott Cheloha }
765bd5de61eSScott Cheloha QTAILQ_REMOVE(&savevm_state.handlers, se, entry);
766bd5de61eSScott Cheloha }
767bd5de61eSScott Cheloha
768c3049a56SJuan Quintela /* TODO: Individual devices generally have very little idea about the rest
769c3049a56SJuan Quintela of the system, so instance_id should be removed/replaced.
770c3049a56SJuan Quintela Meanwhile pass -1 as instance_id if you do not already have a clearly
771c3049a56SJuan Quintela distinguishing id for all instances of your device class. */
register_savevm_live(const char * idstr,uint32_t instance_id,int version_id,const SaveVMHandlers * ops,void * opaque)772ce62df53SDr. David Alan Gilbert int register_savevm_live(const char *idstr,
77393062e23SPeter Xu uint32_t instance_id,
774c3049a56SJuan Quintela int version_id,
775de22ded0SMarc-André Lureau const SaveVMHandlers *ops,
776c3049a56SJuan Quintela void *opaque)
777c3049a56SJuan Quintela {
778c3049a56SJuan Quintela SaveStateEntry *se;
779c3049a56SJuan Quintela
78097f3ad35SMarkus Armbruster se = g_new0(SaveStateEntry, 1);
781c3049a56SJuan Quintela se->version_id = version_id;
7820163a2e0SJuan Quintela se->section_id = savevm_state.global_section_id++;
783c3049a56SJuan Quintela se->ops = ops;
784c3049a56SJuan Quintela se->opaque = opaque;
785c3049a56SJuan Quintela se->vmsd = NULL;
786c3049a56SJuan Quintela /* if this is a live_savem then set is_ram */
7879907e842SJuan Quintela if (ops->save_setup != NULL) {
788c3049a56SJuan Quintela se->is_ram = 1;
789c3049a56SJuan Quintela }
790c3049a56SJuan Quintela
791c3049a56SJuan Quintela pstrcat(se->idstr, sizeof(se->idstr), idstr);
792c3049a56SJuan Quintela
7931df2c9a2SPeter Xu if (instance_id == VMSTATE_INSTANCE_ID_ANY) {
794c3049a56SJuan Quintela se->instance_id = calculate_new_instance_id(se->idstr);
795c3049a56SJuan Quintela } else {
796c3049a56SJuan Quintela se->instance_id = instance_id;
797c3049a56SJuan Quintela }
798c3049a56SJuan Quintela assert(!se->compat || se->instance_id == 0);
799f37bc036SPeter Xu savevm_state_handler_insert(se);
800c3049a56SJuan Quintela return 0;
801c3049a56SJuan Quintela }
802c3049a56SJuan Quintela
unregister_savevm(VMStateIf * obj,const char * idstr,void * opaque)8033cad405bSMarc-André Lureau void unregister_savevm(VMStateIf *obj, const char *idstr, void *opaque)
804c3049a56SJuan Quintela {
805c3049a56SJuan Quintela SaveStateEntry *se, *new_se;
806c3049a56SJuan Quintela char id[256] = "";
807c3049a56SJuan Quintela
8083cad405bSMarc-André Lureau if (obj) {
8093cad405bSMarc-André Lureau char *oid = vmstate_if_get_id(obj);
8103cad405bSMarc-André Lureau if (oid) {
8113cad405bSMarc-André Lureau pstrcpy(id, sizeof(id), oid);
812c3049a56SJuan Quintela pstrcat(id, sizeof(id), "/");
8133cad405bSMarc-André Lureau g_free(oid);
814c3049a56SJuan Quintela }
815c3049a56SJuan Quintela }
816c3049a56SJuan Quintela pstrcat(id, sizeof(id), idstr);
817c3049a56SJuan Quintela
8180163a2e0SJuan Quintela QTAILQ_FOREACH_SAFE(se, &savevm_state.handlers, entry, new_se) {
819c3049a56SJuan Quintela if (strcmp(se->idstr, id) == 0 && se->opaque == opaque) {
820bd5de61eSScott Cheloha savevm_state_handler_remove(se);
821c3049a56SJuan Quintela g_free(se->compat);
822c3049a56SJuan Quintela g_free(se);
823c3049a56SJuan Quintela }
824c3049a56SJuan Quintela }
825c3049a56SJuan Quintela }
826c3049a56SJuan Quintela
827bb25a728SDr. David Alan Gilbert /*
828bb25a728SDr. David Alan Gilbert * Perform some basic checks on vmsd's at registration
829bb25a728SDr. David Alan Gilbert * time.
830bb25a728SDr. David Alan Gilbert */
vmstate_check(const VMStateDescription * vmsd)831bb25a728SDr. David Alan Gilbert static void vmstate_check(const VMStateDescription *vmsd)
832bb25a728SDr. David Alan Gilbert {
833bb25a728SDr. David Alan Gilbert const VMStateField *field = vmsd->fields;
83420270019SRichard Henderson const VMStateDescription * const *subsection = vmsd->subsections;
835bb25a728SDr. David Alan Gilbert
836bb25a728SDr. David Alan Gilbert if (field) {
837bb25a728SDr. David Alan Gilbert while (field->name) {
838bb25a728SDr. David Alan Gilbert if (field->flags & (VMS_STRUCT | VMS_VSTRUCT)) {
839bb25a728SDr. David Alan Gilbert /* Recurse to sub structures */
840bb25a728SDr. David Alan Gilbert vmstate_check(field->vmsd);
841bb25a728SDr. David Alan Gilbert }
842bb25a728SDr. David Alan Gilbert /* Carry on */
843bb25a728SDr. David Alan Gilbert field++;
844bb25a728SDr. David Alan Gilbert }
845bb25a728SDr. David Alan Gilbert /* Check for the end of field list canary */
846bb25a728SDr. David Alan Gilbert if (field->flags != VMS_END) {
847bb25a728SDr. David Alan Gilbert error_report("VMSTATE not ending with VMS_END: %s", vmsd->name);
848bb25a728SDr. David Alan Gilbert g_assert_not_reached();
849bb25a728SDr. David Alan Gilbert }
850bb25a728SDr. David Alan Gilbert }
851bb25a728SDr. David Alan Gilbert
852bb25a728SDr. David Alan Gilbert while (subsection && *subsection) {
853bb25a728SDr. David Alan Gilbert /*
854bb25a728SDr. David Alan Gilbert * The name of a subsection should start with the name of the
855bb25a728SDr. David Alan Gilbert * current object.
856bb25a728SDr. David Alan Gilbert */
857bb25a728SDr. David Alan Gilbert assert(!strncmp(vmsd->name, (*subsection)->name, strlen(vmsd->name)));
858bb25a728SDr. David Alan Gilbert vmstate_check(*subsection);
859bb25a728SDr. David Alan Gilbert subsection++;
860bb25a728SDr. David Alan Gilbert }
861bb25a728SDr. David Alan Gilbert }
862bb25a728SDr. David Alan Gilbert
863485fb955SJuan Quintela /*
864485fb955SJuan Quintela * See comment in hw/intc/xics.c:icp_realize()
865485fb955SJuan Quintela *
866485fb955SJuan Quintela * This function can be removed when
867485fb955SJuan Quintela * pre_2_10_vmstate_register_dummy_icp() is removed.
868485fb955SJuan Quintela */
vmstate_replace_hack_for_ppc(VMStateIf * obj,int instance_id,const VMStateDescription * vmsd,void * opaque)869485fb955SJuan Quintela int vmstate_replace_hack_for_ppc(VMStateIf *obj, int instance_id,
870485fb955SJuan Quintela const VMStateDescription *vmsd,
871485fb955SJuan Quintela void *opaque)
872485fb955SJuan Quintela {
873485fb955SJuan Quintela SaveStateEntry *se = find_se(vmsd->name, instance_id);
874485fb955SJuan Quintela
875485fb955SJuan Quintela if (se) {
876485fb955SJuan Quintela savevm_state_handler_remove(se);
877c80e2251SAkihiko Odaki g_free(se->compat);
878c80e2251SAkihiko Odaki g_free(se);
879485fb955SJuan Quintela }
880485fb955SJuan Quintela return vmstate_register(obj, instance_id, vmsd, opaque);
881485fb955SJuan Quintela }
882485fb955SJuan Quintela
vmstate_register_with_alias_id(VMStateIf * obj,uint32_t instance_id,const VMStateDescription * vmsd,void * opaque,int alias_id,int required_for_version,Error ** errp)88393062e23SPeter Xu int vmstate_register_with_alias_id(VMStateIf *obj, uint32_t instance_id,
884c3049a56SJuan Quintela const VMStateDescription *vmsd,
885c3049a56SJuan Quintela void *opaque, int alias_id,
886bc5c4f21SDr. David Alan Gilbert int required_for_version,
887bc5c4f21SDr. David Alan Gilbert Error **errp)
888c3049a56SJuan Quintela {
889c3049a56SJuan Quintela SaveStateEntry *se;
890c3049a56SJuan Quintela
891c3049a56SJuan Quintela /* If this triggers, alias support can be dropped for the vmsd. */
892c3049a56SJuan Quintela assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
893c3049a56SJuan Quintela
89497f3ad35SMarkus Armbruster se = g_new0(SaveStateEntry, 1);
895c3049a56SJuan Quintela se->version_id = vmsd->version_id;
8960163a2e0SJuan Quintela se->section_id = savevm_state.global_section_id++;
897c3049a56SJuan Quintela se->opaque = opaque;
898c3049a56SJuan Quintela se->vmsd = vmsd;
899c3049a56SJuan Quintela se->alias_id = alias_id;
900c3049a56SJuan Quintela
9013cad405bSMarc-André Lureau if (obj) {
9023cad405bSMarc-André Lureau char *id = vmstate_if_get_id(obj);
903c3049a56SJuan Quintela if (id) {
904581f08baSDr. David Alan Gilbert if (snprintf(se->idstr, sizeof(se->idstr), "%s/", id) >=
905581f08baSDr. David Alan Gilbert sizeof(se->idstr)) {
906581f08baSDr. David Alan Gilbert error_setg(errp, "Path too long for VMState (%s)", id);
907c3049a56SJuan Quintela g_free(id);
908581f08baSDr. David Alan Gilbert g_free(se);
909581f08baSDr. David Alan Gilbert
910581f08baSDr. David Alan Gilbert return -1;
911581f08baSDr. David Alan Gilbert }
912128e4e10SMarc-André Lureau g_free(id);
913c3049a56SJuan Quintela
91497f3ad35SMarkus Armbruster se->compat = g_new0(CompatEntry, 1);
915c3049a56SJuan Quintela pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
9161df2c9a2SPeter Xu se->compat->instance_id = instance_id == VMSTATE_INSTANCE_ID_ANY ?
917c3049a56SJuan Quintela calculate_compat_instance_id(vmsd->name) : instance_id;
9181df2c9a2SPeter Xu instance_id = VMSTATE_INSTANCE_ID_ANY;
919c3049a56SJuan Quintela }
920c3049a56SJuan Quintela }
921c3049a56SJuan Quintela pstrcat(se->idstr, sizeof(se->idstr), vmsd->name);
922c3049a56SJuan Quintela
9231df2c9a2SPeter Xu if (instance_id == VMSTATE_INSTANCE_ID_ANY) {
924c3049a56SJuan Quintela se->instance_id = calculate_new_instance_id(se->idstr);
925c3049a56SJuan Quintela } else {
926c3049a56SJuan Quintela se->instance_id = instance_id;
927c3049a56SJuan Quintela }
928bb25a728SDr. David Alan Gilbert
929bb25a728SDr. David Alan Gilbert /* Perform a recursive sanity check during the test runs */
930bb25a728SDr. David Alan Gilbert if (qtest_enabled()) {
931bb25a728SDr. David Alan Gilbert vmstate_check(vmsd);
932bb25a728SDr. David Alan Gilbert }
933c3049a56SJuan Quintela assert(!se->compat || se->instance_id == 0);
934f37bc036SPeter Xu savevm_state_handler_insert(se);
935c3049a56SJuan Quintela return 0;
936c3049a56SJuan Quintela }
937c3049a56SJuan Quintela
vmstate_unregister(VMStateIf * obj,const VMStateDescription * vmsd,void * opaque)9383cad405bSMarc-André Lureau void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd,
939c3049a56SJuan Quintela void *opaque)
940c3049a56SJuan Quintela {
941c3049a56SJuan Quintela SaveStateEntry *se, *new_se;
942c3049a56SJuan Quintela
9430163a2e0SJuan Quintela QTAILQ_FOREACH_SAFE(se, &savevm_state.handlers, entry, new_se) {
944c3049a56SJuan Quintela if (se->vmsd == vmsd && se->opaque == opaque) {
945bd5de61eSScott Cheloha savevm_state_handler_remove(se);
946c3049a56SJuan Quintela g_free(se->compat);
947c3049a56SJuan Quintela g_free(se);
948c3049a56SJuan Quintela }
949c3049a56SJuan Quintela }
950c3049a56SJuan Quintela }
951c3049a56SJuan Quintela
vmstate_load(QEMUFile * f,SaveStateEntry * se)9523a011c26SJuan Quintela static int vmstate_load(QEMUFile *f, SaveStateEntry *se)
953c3049a56SJuan Quintela {
954c3049a56SJuan Quintela trace_vmstate_load(se->idstr, se->vmsd ? se->vmsd->name : "(old)");
955c3049a56SJuan Quintela if (!se->vmsd) { /* Old style */
9563a011c26SJuan Quintela return se->ops->load_state(f, se->opaque, se->load_version_id);
957c3049a56SJuan Quintela }
9583a011c26SJuan Quintela return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id);
959c3049a56SJuan Quintela }
960c3049a56SJuan Quintela
vmstate_save_old_style(QEMUFile * f,SaveStateEntry * se,JSONWriter * vmdesc)9613ddba9a9SMarkus Armbruster static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
9623ddba9a9SMarkus Armbruster JSONWriter *vmdesc)
963c3049a56SJuan Quintela {
964e9c0eed7SJuan Quintela uint64_t old_offset = qemu_file_transferred(f);
965c3049a56SJuan Quintela se->ops->save_state(f, se->opaque);
966e9c0eed7SJuan Quintela uint64_t size = qemu_file_transferred(f) - old_offset;
967c3049a56SJuan Quintela
968c3049a56SJuan Quintela if (vmdesc) {
9693ddba9a9SMarkus Armbruster json_writer_int64(vmdesc, "size", size);
9703ddba9a9SMarkus Armbruster json_writer_start_array(vmdesc, "fields");
9713ddba9a9SMarkus Armbruster json_writer_start_object(vmdesc, NULL);
9723ddba9a9SMarkus Armbruster json_writer_str(vmdesc, "name", "data");
9733ddba9a9SMarkus Armbruster json_writer_int64(vmdesc, "size", size);
9743ddba9a9SMarkus Armbruster json_writer_str(vmdesc, "type", "buffer");
9753ddba9a9SMarkus Armbruster json_writer_end_object(vmdesc);
9763ddba9a9SMarkus Armbruster json_writer_end_array(vmdesc);
977c3049a56SJuan Quintela }
978c3049a56SJuan Quintela }
979c3049a56SJuan Quintela
980ce39bfc9SDr. David Alan Gilbert /*
981ce39bfc9SDr. David Alan Gilbert * Write the header for device section (QEMU_VM_SECTION START/END/PART/FULL)
982ce39bfc9SDr. David Alan Gilbert */
save_section_header(QEMUFile * f,SaveStateEntry * se,uint8_t section_type)983ce39bfc9SDr. David Alan Gilbert static void save_section_header(QEMUFile *f, SaveStateEntry *se,
984ce39bfc9SDr. David Alan Gilbert uint8_t section_type)
985ce39bfc9SDr. David Alan Gilbert {
986ce39bfc9SDr. David Alan Gilbert qemu_put_byte(f, section_type);
987ce39bfc9SDr. David Alan Gilbert qemu_put_be32(f, se->section_id);
988ce39bfc9SDr. David Alan Gilbert
989ce39bfc9SDr. David Alan Gilbert if (section_type == QEMU_VM_SECTION_FULL ||
990ce39bfc9SDr. David Alan Gilbert section_type == QEMU_VM_SECTION_START) {
991ce39bfc9SDr. David Alan Gilbert /* ID string */
992ce39bfc9SDr. David Alan Gilbert size_t len = strlen(se->idstr);
993ce39bfc9SDr. David Alan Gilbert qemu_put_byte(f, len);
994ce39bfc9SDr. David Alan Gilbert qemu_put_buffer(f, (uint8_t *)se->idstr, len);
995ce39bfc9SDr. David Alan Gilbert
996ce39bfc9SDr. David Alan Gilbert qemu_put_be32(f, se->instance_id);
997ce39bfc9SDr. David Alan Gilbert qemu_put_be32(f, se->version_id);
998ce39bfc9SDr. David Alan Gilbert }
999ce39bfc9SDr. David Alan Gilbert }
1000ce39bfc9SDr. David Alan Gilbert
1001f68945d4SDr. David Alan Gilbert /*
1002f68945d4SDr. David Alan Gilbert * Write a footer onto device sections that catches cases misformatted device
1003f68945d4SDr. David Alan Gilbert * sections.
1004f68945d4SDr. David Alan Gilbert */
save_section_footer(QEMUFile * f,SaveStateEntry * se)1005f68945d4SDr. David Alan Gilbert static void save_section_footer(QEMUFile *f, SaveStateEntry *se)
1006f68945d4SDr. David Alan Gilbert {
100715c38503SPeter Xu if (migrate_get_current()->send_section_footer) {
1008f68945d4SDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_SECTION_FOOTER);
1009f68945d4SDr. David Alan Gilbert qemu_put_be32(f, se->section_id);
1010f68945d4SDr. David Alan Gilbert }
1011f68945d4SDr. David Alan Gilbert }
1012f68945d4SDr. David Alan Gilbert
vmstate_save(QEMUFile * f,SaveStateEntry * se,JSONWriter * vmdesc,Error ** errp)10136138d43aSCédric Le Goater static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc,
10146138d43aSCédric Le Goater Error **errp)
10155e104f24SDavid Hildenbrand {
10165e104f24SDavid Hildenbrand int ret;
10175e104f24SDavid Hildenbrand
10185e104f24SDavid Hildenbrand if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
10195e104f24SDavid Hildenbrand return 0;
10205e104f24SDavid Hildenbrand }
10214d8bdc2aSMarc-André Lureau if (se->vmsd && !vmstate_section_needed(se->vmsd, se->opaque)) {
10225e104f24SDavid Hildenbrand trace_savevm_section_skip(se->idstr, se->section_id);
10235e104f24SDavid Hildenbrand return 0;
10245e104f24SDavid Hildenbrand }
10255e104f24SDavid Hildenbrand
10265e104f24SDavid Hildenbrand trace_savevm_section_start(se->idstr, se->section_id);
10275e104f24SDavid Hildenbrand save_section_header(f, se, QEMU_VM_SECTION_FULL);
10285e104f24SDavid Hildenbrand if (vmdesc) {
10295e104f24SDavid Hildenbrand json_writer_start_object(vmdesc, NULL);
10305e104f24SDavid Hildenbrand json_writer_str(vmdesc, "name", se->idstr);
10315e104f24SDavid Hildenbrand json_writer_int64(vmdesc, "instance_id", se->instance_id);
10325e104f24SDavid Hildenbrand }
10335e104f24SDavid Hildenbrand
10345e104f24SDavid Hildenbrand trace_vmstate_save(se->idstr, se->vmsd ? se->vmsd->name : "(old)");
10355e104f24SDavid Hildenbrand if (!se->vmsd) {
10365e104f24SDavid Hildenbrand vmstate_save_old_style(f, se, vmdesc);
10375e104f24SDavid Hildenbrand } else {
10386138d43aSCédric Le Goater ret = vmstate_save_state_with_err(f, se->vmsd, se->opaque, vmdesc,
10396138d43aSCédric Le Goater errp);
10405e104f24SDavid Hildenbrand if (ret) {
10415e104f24SDavid Hildenbrand return ret;
10425e104f24SDavid Hildenbrand }
10435e104f24SDavid Hildenbrand }
10445e104f24SDavid Hildenbrand
10455e104f24SDavid Hildenbrand trace_savevm_section_end(se->idstr, se->section_id, 0);
10465e104f24SDavid Hildenbrand save_section_footer(f, se);
10475e104f24SDavid Hildenbrand if (vmdesc) {
10485e104f24SDavid Hildenbrand json_writer_end_object(vmdesc);
10495e104f24SDavid Hildenbrand }
10505e104f24SDavid Hildenbrand return 0;
10515e104f24SDavid Hildenbrand }
1052c76ca188SDr. David Alan Gilbert /**
1053c76ca188SDr. David Alan Gilbert * qemu_savevm_command_send: Send a 'QEMU_VM_COMMAND' type element with the
1054c76ca188SDr. David Alan Gilbert * command and associated data.
1055c76ca188SDr. David Alan Gilbert *
1056c76ca188SDr. David Alan Gilbert * @f: File to send command on
1057c76ca188SDr. David Alan Gilbert * @command: Command type to send
1058c76ca188SDr. David Alan Gilbert * @len: Length of associated data
1059c76ca188SDr. David Alan Gilbert * @data: Data associated with command.
1060c76ca188SDr. David Alan Gilbert */
qemu_savevm_command_send(QEMUFile * f,enum qemu_vm_cmd command,uint16_t len,uint8_t * data)106120a519a0SJuan Quintela static void qemu_savevm_command_send(QEMUFile *f,
1062c76ca188SDr. David Alan Gilbert enum qemu_vm_cmd command,
1063c76ca188SDr. David Alan Gilbert uint16_t len,
1064c76ca188SDr. David Alan Gilbert uint8_t *data)
1065c76ca188SDr. David Alan Gilbert {
1066c76ca188SDr. David Alan Gilbert trace_savevm_command_send(command, len);
1067c76ca188SDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_COMMAND);
1068c76ca188SDr. David Alan Gilbert qemu_put_be16(f, (uint16_t)command);
1069c76ca188SDr. David Alan Gilbert qemu_put_be16(f, len);
1070c76ca188SDr. David Alan Gilbert qemu_put_buffer(f, data, len);
1071c76ca188SDr. David Alan Gilbert qemu_fflush(f);
1072c76ca188SDr. David Alan Gilbert }
1073c76ca188SDr. David Alan Gilbert
qemu_savevm_send_colo_enable(QEMUFile * f)1074aad555c2SZhang Chen void qemu_savevm_send_colo_enable(QEMUFile *f)
1075aad555c2SZhang Chen {
1076aad555c2SZhang Chen trace_savevm_send_colo_enable();
1077aad555c2SZhang Chen qemu_savevm_command_send(f, MIG_CMD_ENABLE_COLO, 0, NULL);
1078aad555c2SZhang Chen }
1079aad555c2SZhang Chen
qemu_savevm_send_ping(QEMUFile * f,uint32_t value)10802e37701eSDr. David Alan Gilbert void qemu_savevm_send_ping(QEMUFile *f, uint32_t value)
10812e37701eSDr. David Alan Gilbert {
10822e37701eSDr. David Alan Gilbert uint32_t buf;
10832e37701eSDr. David Alan Gilbert
10842e37701eSDr. David Alan Gilbert trace_savevm_send_ping(value);
10852e37701eSDr. David Alan Gilbert buf = cpu_to_be32(value);
10862e37701eSDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_PING, sizeof(value), (uint8_t *)&buf);
10872e37701eSDr. David Alan Gilbert }
10882e37701eSDr. David Alan Gilbert
qemu_savevm_send_open_return_path(QEMUFile * f)10892e37701eSDr. David Alan Gilbert void qemu_savevm_send_open_return_path(QEMUFile *f)
10902e37701eSDr. David Alan Gilbert {
10912e37701eSDr. David Alan Gilbert trace_savevm_send_open_return_path();
10922e37701eSDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_OPEN_RETURN_PATH, 0, NULL);
10932e37701eSDr. David Alan Gilbert }
10942e37701eSDr. David Alan Gilbert
109511cf1d98SDr. David Alan Gilbert /* We have a buffer of data to send; we don't want that all to be loaded
109611cf1d98SDr. David Alan Gilbert * by the command itself, so the command contains just the length of the
109711cf1d98SDr. David Alan Gilbert * extra buffer that we then send straight after it.
109811cf1d98SDr. David Alan Gilbert * TODO: Must be a better way to organise that
109911cf1d98SDr. David Alan Gilbert *
110011cf1d98SDr. David Alan Gilbert * Returns:
110111cf1d98SDr. David Alan Gilbert * 0 on success
110211cf1d98SDr. David Alan Gilbert * -ve on error
110311cf1d98SDr. David Alan Gilbert */
qemu_savevm_send_packaged(QEMUFile * f,const uint8_t * buf,size_t len)110461b67d47SDaniel P. Berrange int qemu_savevm_send_packaged(QEMUFile *f, const uint8_t *buf, size_t len)
110511cf1d98SDr. David Alan Gilbert {
110611cf1d98SDr. David Alan Gilbert uint32_t tmp;
1107848a0503STejus GK MigrationState *ms = migrate_get_current();
1108848a0503STejus GK Error *local_err = NULL;
110911cf1d98SDr. David Alan Gilbert
111011cf1d98SDr. David Alan Gilbert if (len > MAX_VM_CMD_PACKAGED_SIZE) {
1111848a0503STejus GK error_setg(&local_err, "%s: Unreasonably large packaged state: %zu",
111211cf1d98SDr. David Alan Gilbert __func__, len);
1113848a0503STejus GK migrate_set_error(ms, local_err);
1114848a0503STejus GK error_report_err(local_err);
111511cf1d98SDr. David Alan Gilbert return -1;
111611cf1d98SDr. David Alan Gilbert }
111711cf1d98SDr. David Alan Gilbert
111811cf1d98SDr. David Alan Gilbert tmp = cpu_to_be32(len);
111911cf1d98SDr. David Alan Gilbert
112011cf1d98SDr. David Alan Gilbert trace_qemu_savevm_send_packaged();
112111cf1d98SDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_PACKAGED, 4, (uint8_t *)&tmp);
112211cf1d98SDr. David Alan Gilbert
112361b67d47SDaniel P. Berrange qemu_put_buffer(f, buf, len);
112411cf1d98SDr. David Alan Gilbert
112511cf1d98SDr. David Alan Gilbert return 0;
112611cf1d98SDr. David Alan Gilbert }
112711cf1d98SDr. David Alan Gilbert
1128093e3c42SDr. David Alan Gilbert /* Send prior to any postcopy transfer */
qemu_savevm_send_postcopy_advise(QEMUFile * f)1129093e3c42SDr. David Alan Gilbert void qemu_savevm_send_postcopy_advise(QEMUFile *f)
1130093e3c42SDr. David Alan Gilbert {
113158110f0aSVladimir Sementsov-Ogievskiy if (migrate_postcopy_ram()) {
1132093e3c42SDr. David Alan Gilbert uint64_t tmp[2];
1133e8ca1db2SDr. David Alan Gilbert tmp[0] = cpu_to_be64(ram_pagesize_summary());
113420afaed9SJuan Quintela tmp[1] = cpu_to_be64(qemu_target_page_size());
1135093e3c42SDr. David Alan Gilbert
1136093e3c42SDr. David Alan Gilbert trace_qemu_savevm_send_postcopy_advise();
113758110f0aSVladimir Sementsov-Ogievskiy qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_ADVISE,
113858110f0aSVladimir Sementsov-Ogievskiy 16, (uint8_t *)tmp);
113958110f0aSVladimir Sementsov-Ogievskiy } else {
114058110f0aSVladimir Sementsov-Ogievskiy qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_ADVISE, 0, NULL);
114158110f0aSVladimir Sementsov-Ogievskiy }
1142093e3c42SDr. David Alan Gilbert }
1143093e3c42SDr. David Alan Gilbert
1144093e3c42SDr. David Alan Gilbert /* Sent prior to starting the destination running in postcopy, discard pages
1145093e3c42SDr. David Alan Gilbert * that have already been sent but redirtied on the source.
1146093e3c42SDr. David Alan Gilbert * CMD_POSTCOPY_RAM_DISCARD consist of:
1147093e3c42SDr. David Alan Gilbert * byte version (0)
1148093e3c42SDr. David Alan Gilbert * byte Length of name field (not including 0)
1149093e3c42SDr. David Alan Gilbert * n x byte RAM block name
1150093e3c42SDr. David Alan Gilbert * byte 0 terminator (just for safety)
1151093e3c42SDr. David Alan Gilbert * n x Byte ranges within the named RAMBlock
1152093e3c42SDr. David Alan Gilbert * be64 Start of the range
1153093e3c42SDr. David Alan Gilbert * be64 Length
1154093e3c42SDr. David Alan Gilbert *
1155093e3c42SDr. David Alan Gilbert * name: RAMBlock name that these entries are part of
1156093e3c42SDr. David Alan Gilbert * len: Number of page entries
1157093e3c42SDr. David Alan Gilbert * start_list: 'len' addresses
1158093e3c42SDr. David Alan Gilbert * length_list: 'len' addresses
1159093e3c42SDr. David Alan Gilbert *
1160093e3c42SDr. David Alan Gilbert */
qemu_savevm_send_postcopy_ram_discard(QEMUFile * f,const char * name,uint16_t len,uint64_t * start_list,uint64_t * length_list)1161093e3c42SDr. David Alan Gilbert void qemu_savevm_send_postcopy_ram_discard(QEMUFile *f, const char *name,
1162093e3c42SDr. David Alan Gilbert uint16_t len,
1163093e3c42SDr. David Alan Gilbert uint64_t *start_list,
1164093e3c42SDr. David Alan Gilbert uint64_t *length_list)
1165093e3c42SDr. David Alan Gilbert {
1166093e3c42SDr. David Alan Gilbert uint8_t *buf;
1167093e3c42SDr. David Alan Gilbert uint16_t tmplen;
1168093e3c42SDr. David Alan Gilbert uint16_t t;
1169093e3c42SDr. David Alan Gilbert size_t name_len = strlen(name);
1170093e3c42SDr. David Alan Gilbert
1171093e3c42SDr. David Alan Gilbert trace_qemu_savevm_send_postcopy_ram_discard(name, len);
1172093e3c42SDr. David Alan Gilbert assert(name_len < 256);
1173093e3c42SDr. David Alan Gilbert buf = g_malloc0(1 + 1 + name_len + 1 + (8 + 8) * len);
1174093e3c42SDr. David Alan Gilbert buf[0] = postcopy_ram_discard_version;
1175093e3c42SDr. David Alan Gilbert buf[1] = name_len;
1176093e3c42SDr. David Alan Gilbert memcpy(buf + 2, name, name_len);
1177093e3c42SDr. David Alan Gilbert tmplen = 2 + name_len;
1178093e3c42SDr. David Alan Gilbert buf[tmplen++] = '\0';
1179093e3c42SDr. David Alan Gilbert
1180093e3c42SDr. David Alan Gilbert for (t = 0; t < len; t++) {
11814d885131SPeter Maydell stq_be_p(buf + tmplen, start_list[t]);
1182093e3c42SDr. David Alan Gilbert tmplen += 8;
11834d885131SPeter Maydell stq_be_p(buf + tmplen, length_list[t]);
1184093e3c42SDr. David Alan Gilbert tmplen += 8;
1185093e3c42SDr. David Alan Gilbert }
1186093e3c42SDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_RAM_DISCARD, tmplen, buf);
1187093e3c42SDr. David Alan Gilbert g_free(buf);
1188093e3c42SDr. David Alan Gilbert }
1189093e3c42SDr. David Alan Gilbert
1190093e3c42SDr. David Alan Gilbert /* Get the destination into a state where it can receive postcopy data. */
qemu_savevm_send_postcopy_listen(QEMUFile * f)1191093e3c42SDr. David Alan Gilbert void qemu_savevm_send_postcopy_listen(QEMUFile *f)
1192093e3c42SDr. David Alan Gilbert {
1193093e3c42SDr. David Alan Gilbert trace_savevm_send_postcopy_listen();
1194093e3c42SDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_LISTEN, 0, NULL);
1195093e3c42SDr. David Alan Gilbert }
1196093e3c42SDr. David Alan Gilbert
1197093e3c42SDr. David Alan Gilbert /* Kick the destination into running */
qemu_savevm_send_postcopy_run(QEMUFile * f)1198093e3c42SDr. David Alan Gilbert void qemu_savevm_send_postcopy_run(QEMUFile *f)
1199093e3c42SDr. David Alan Gilbert {
1200093e3c42SDr. David Alan Gilbert trace_savevm_send_postcopy_run();
1201093e3c42SDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_RUN, 0, NULL);
1202093e3c42SDr. David Alan Gilbert }
1203093e3c42SDr. David Alan Gilbert
qemu_savevm_send_postcopy_resume(QEMUFile * f)12043f5875ecSPeter Xu void qemu_savevm_send_postcopy_resume(QEMUFile *f)
12053f5875ecSPeter Xu {
12063f5875ecSPeter Xu trace_savevm_send_postcopy_resume();
12073f5875ecSPeter Xu qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_RESUME, 0, NULL);
12083f5875ecSPeter Xu }
12093f5875ecSPeter Xu
qemu_savevm_send_recv_bitmap(QEMUFile * f,char * block_name)1210f25d4225SPeter Xu void qemu_savevm_send_recv_bitmap(QEMUFile *f, char *block_name)
1211f25d4225SPeter Xu {
1212f25d4225SPeter Xu size_t len;
1213f25d4225SPeter Xu char buf[256];
1214f25d4225SPeter Xu
1215f25d4225SPeter Xu trace_savevm_send_recv_bitmap(block_name);
1216f25d4225SPeter Xu
1217f25d4225SPeter Xu buf[0] = len = strlen(block_name);
1218f25d4225SPeter Xu memcpy(buf + 1, block_name, len);
1219f25d4225SPeter Xu
1220f25d4225SPeter Xu qemu_savevm_command_send(f, MIG_CMD_RECV_BITMAP, len + 1, (uint8_t *)buf);
1221f25d4225SPeter Xu }
1222f25d4225SPeter Xu
qemu_savevm_state_blocked(Error ** errp)1223c3049a56SJuan Quintela bool qemu_savevm_state_blocked(Error **errp)
1224c3049a56SJuan Quintela {
1225c3049a56SJuan Quintela SaveStateEntry *se;
1226c3049a56SJuan Quintela
12270163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1228c3049a56SJuan Quintela if (se->vmsd && se->vmsd->unmigratable) {
1229c3049a56SJuan Quintela error_setg(errp, "State blocked by non-migratable device '%s'",
1230c3049a56SJuan Quintela se->idstr);
1231c3049a56SJuan Quintela return true;
1232c3049a56SJuan Quintela }
1233c3049a56SJuan Quintela }
1234c3049a56SJuan Quintela return false;
1235c3049a56SJuan Quintela }
1236c3049a56SJuan Quintela
qemu_savevm_non_migratable_list(strList ** reasons)12373af8554bSDr. David Alan Gilbert void qemu_savevm_non_migratable_list(strList **reasons)
12383af8554bSDr. David Alan Gilbert {
12393af8554bSDr. David Alan Gilbert SaveStateEntry *se;
12403af8554bSDr. David Alan Gilbert
12413af8554bSDr. David Alan Gilbert QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
12423af8554bSDr. David Alan Gilbert if (se->vmsd && se->vmsd->unmigratable) {
12433af8554bSDr. David Alan Gilbert QAPI_LIST_PREPEND(*reasons,
12443af8554bSDr. David Alan Gilbert g_strdup_printf("non-migratable device: %s",
12453af8554bSDr. David Alan Gilbert se->idstr));
12463af8554bSDr. David Alan Gilbert }
12473af8554bSDr. David Alan Gilbert }
12483af8554bSDr. David Alan Gilbert }
12493af8554bSDr. David Alan Gilbert
qemu_savevm_state_header(QEMUFile * f)1250f796baa1SDr. David Alan Gilbert void qemu_savevm_state_header(QEMUFile *f)
1251f796baa1SDr. David Alan Gilbert {
12522aae1eb8SNikolay Borisov MigrationState *s = migrate_get_current();
12532aae1eb8SNikolay Borisov
12542aae1eb8SNikolay Borisov s->vmdesc = json_writer_new(false);
12552aae1eb8SNikolay Borisov
1256f796baa1SDr. David Alan Gilbert trace_savevm_state_header();
1257f796baa1SDr. David Alan Gilbert qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
1258f796baa1SDr. David Alan Gilbert qemu_put_be32(f, QEMU_VM_FILE_VERSION);
1259172dfd4fSDr. David Alan Gilbert
12602aae1eb8SNikolay Borisov if (s->send_configuration) {
1261172dfd4fSDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_CONFIGURATION);
12622aae1eb8SNikolay Borisov
12632aae1eb8SNikolay Borisov /*
12642aae1eb8SNikolay Borisov * This starts the main json object and is paired with the
12652aae1eb8SNikolay Borisov * json_writer_end_object in
12662aae1eb8SNikolay Borisov * qemu_savevm_state_complete_precopy_non_iterable
12672aae1eb8SNikolay Borisov */
12682aae1eb8SNikolay Borisov json_writer_start_object(s->vmdesc, NULL);
12692aae1eb8SNikolay Borisov
12702aae1eb8SNikolay Borisov json_writer_start_object(s->vmdesc, "configuration");
12712aae1eb8SNikolay Borisov vmstate_save_state(f, &vmstate_configuration, &savevm_state, s->vmdesc);
12722aae1eb8SNikolay Borisov json_writer_end_object(s->vmdesc);
1273172dfd4fSDr. David Alan Gilbert }
1274f796baa1SDr. David Alan Gilbert }
1275f796baa1SDr. David Alan Gilbert
qemu_savevm_state_guest_unplug_pending(void)1276d05de9e3SKeqian Zhu bool qemu_savevm_state_guest_unplug_pending(void)
1277c7e0acd5SJens Freimann {
1278c7e0acd5SJens Freimann SaveStateEntry *se;
1279c7e0acd5SJens Freimann
1280c7e0acd5SJens Freimann QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1281284f42a5SJens Freimann if (se->vmsd && se->vmsd->dev_unplug_pending &&
1282284f42a5SJens Freimann se->vmsd->dev_unplug_pending(se->opaque)) {
1283d05de9e3SKeqian Zhu return true;
1284c7e0acd5SJens Freimann }
1285c7e0acd5SJens Freimann }
1286c7e0acd5SJens Freimann
1287d05de9e3SKeqian Zhu return false;
1288c7e0acd5SJens Freimann }
1289c7e0acd5SJens Freimann
qemu_savevm_state_prepare(Error ** errp)129008fc4cb5SAvihai Horon int qemu_savevm_state_prepare(Error **errp)
129108fc4cb5SAvihai Horon {
129208fc4cb5SAvihai Horon SaveStateEntry *se;
129308fc4cb5SAvihai Horon int ret;
129408fc4cb5SAvihai Horon
129508fc4cb5SAvihai Horon QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
129608fc4cb5SAvihai Horon if (!se->ops || !se->ops->save_prepare) {
129708fc4cb5SAvihai Horon continue;
129808fc4cb5SAvihai Horon }
129908fc4cb5SAvihai Horon if (se->ops->is_active) {
130008fc4cb5SAvihai Horon if (!se->ops->is_active(se->opaque)) {
130108fc4cb5SAvihai Horon continue;
130208fc4cb5SAvihai Horon }
130308fc4cb5SAvihai Horon }
130408fc4cb5SAvihai Horon
130508fc4cb5SAvihai Horon ret = se->ops->save_prepare(se->opaque, errp);
130608fc4cb5SAvihai Horon if (ret < 0) {
130708fc4cb5SAvihai Horon return ret;
130808fc4cb5SAvihai Horon }
130908fc4cb5SAvihai Horon }
131008fc4cb5SAvihai Horon
131108fc4cb5SAvihai Horon return 0;
131208fc4cb5SAvihai Horon }
131308fc4cb5SAvihai Horon
qemu_savevm_state_setup(QEMUFile * f,Error ** errp)1314057a2009SCédric Le Goater int qemu_savevm_state_setup(QEMUFile *f, Error **errp)
1315c3049a56SJuan Quintela {
1316057a2009SCédric Le Goater ERRP_GUARD();
1317e3bf5e68SDavid Hildenbrand MigrationState *ms = migrate_get_current();
1318c3049a56SJuan Quintela SaveStateEntry *se;
1319e6e08e83SCédric Le Goater int ret = 0;
1320c3049a56SJuan Quintela
1321e3bf5e68SDavid Hildenbrand json_writer_int64(ms->vmdesc, "page_size", qemu_target_page_size());
1322e3bf5e68SDavid Hildenbrand json_writer_start_array(ms->vmdesc, "devices");
1323e3bf5e68SDavid Hildenbrand
13249907e842SJuan Quintela trace_savevm_state_setup();
13250163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
132662f42625SDavid Hildenbrand if (se->vmsd && se->vmsd->early_setup) {
1327057a2009SCédric Le Goater ret = vmstate_save(f, se, ms->vmdesc, errp);
132862f42625SDavid Hildenbrand if (ret) {
1329057a2009SCédric Le Goater migrate_set_error(ms, *errp);
133062f42625SDavid Hildenbrand qemu_file_set_error(f, ret);
133162f42625SDavid Hildenbrand break;
133262f42625SDavid Hildenbrand }
133362f42625SDavid Hildenbrand continue;
133462f42625SDavid Hildenbrand }
133562f42625SDavid Hildenbrand
13369907e842SJuan Quintela if (!se->ops || !se->ops->save_setup) {
1337c3049a56SJuan Quintela continue;
1338c3049a56SJuan Quintela }
1339cea3b4c0SWei Yang if (se->ops->is_active) {
1340c3049a56SJuan Quintela if (!se->ops->is_active(se->opaque)) {
1341c3049a56SJuan Quintela continue;
1342c3049a56SJuan Quintela }
1343c3049a56SJuan Quintela }
1344ce39bfc9SDr. David Alan Gilbert save_section_header(f, se, QEMU_VM_SECTION_START);
1345c3049a56SJuan Quintela
134601c3ac68SCédric Le Goater ret = se->ops->save_setup(f, se->opaque, errp);
1347f68945d4SDr. David Alan Gilbert save_section_footer(f, se);
1348c3049a56SJuan Quintela if (ret < 0) {
1349c3049a56SJuan Quintela qemu_file_set_error(f, ret);
1350c3049a56SJuan Quintela break;
1351c3049a56SJuan Quintela }
1352c3049a56SJuan Quintela }
1353bd227060SWei Wang
1354e6e08e83SCédric Le Goater if (ret) {
1355057a2009SCédric Le Goater return ret;
1356e6e08e83SCédric Le Goater }
1357e6e08e83SCédric Le Goater
1358057a2009SCédric Le Goater /* TODO: Should we check that errp is set in case of failure ? */
1359057a2009SCédric Le Goater return precopy_notify(PRECOPY_NOTIFY_SETUP, errp);
1360c3049a56SJuan Quintela }
1361c3049a56SJuan Quintela
qemu_savevm_state_resume_prepare(MigrationState * s)1362d1b8eadbSPeter Xu int qemu_savevm_state_resume_prepare(MigrationState *s)
1363d1b8eadbSPeter Xu {
1364d1b8eadbSPeter Xu SaveStateEntry *se;
1365d1b8eadbSPeter Xu int ret;
1366d1b8eadbSPeter Xu
1367d1b8eadbSPeter Xu trace_savevm_state_resume_prepare();
1368d1b8eadbSPeter Xu
1369d1b8eadbSPeter Xu QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1370d1b8eadbSPeter Xu if (!se->ops || !se->ops->resume_prepare) {
1371d1b8eadbSPeter Xu continue;
1372d1b8eadbSPeter Xu }
1373cea3b4c0SWei Yang if (se->ops->is_active) {
1374d1b8eadbSPeter Xu if (!se->ops->is_active(se->opaque)) {
1375d1b8eadbSPeter Xu continue;
1376d1b8eadbSPeter Xu }
1377d1b8eadbSPeter Xu }
1378d1b8eadbSPeter Xu ret = se->ops->resume_prepare(s, se->opaque);
1379d1b8eadbSPeter Xu if (ret < 0) {
1380d1b8eadbSPeter Xu return ret;
1381d1b8eadbSPeter Xu }
1382d1b8eadbSPeter Xu }
1383d1b8eadbSPeter Xu
1384d1b8eadbSPeter Xu return 0;
1385d1b8eadbSPeter Xu }
1386d1b8eadbSPeter Xu
1387c3049a56SJuan Quintela /*
1388c3049a56SJuan Quintela * this function has three return values:
1389c3049a56SJuan Quintela * negative: there was one error, and we have -errno.
1390c3049a56SJuan Quintela * 0 : We haven't finished, caller have to go again
1391c3049a56SJuan Quintela * 1 : We have finished, we can go to complete phase
1392c3049a56SJuan Quintela */
qemu_savevm_state_iterate(QEMUFile * f,bool postcopy)139335ecd943SDr. David Alan Gilbert int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy)
1394c3049a56SJuan Quintela {
1395c3049a56SJuan Quintela SaveStateEntry *se;
13964e1871c4SAvihai Horon bool all_finished = true;
13974e1871c4SAvihai Horon int ret;
1398c3049a56SJuan Quintela
1399c3049a56SJuan Quintela trace_savevm_state_iterate();
14000163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1401c3049a56SJuan Quintela if (!se->ops || !se->ops->save_live_iterate) {
1402c3049a56SJuan Quintela continue;
1403c3049a56SJuan Quintela }
1404a94cd7b8SWei Yang if (se->ops->is_active &&
1405a94cd7b8SWei Yang !se->ops->is_active(se->opaque)) {
1406c3049a56SJuan Quintela continue;
1407c3049a56SJuan Quintela }
1408a94cd7b8SWei Yang if (se->ops->is_active_iterate &&
1409a94cd7b8SWei Yang !se->ops->is_active_iterate(se->opaque)) {
1410c865d848SVladimir Sementsov-Ogievskiy continue;
1411c865d848SVladimir Sementsov-Ogievskiy }
141235ecd943SDr. David Alan Gilbert /*
141335ecd943SDr. David Alan Gilbert * In the postcopy phase, any device that doesn't know how to
141435ecd943SDr. David Alan Gilbert * do postcopy should have saved it's state in the _complete
141535ecd943SDr. David Alan Gilbert * call that's already run, it might get confused if we call
141635ecd943SDr. David Alan Gilbert * iterate afterwards.
141735ecd943SDr. David Alan Gilbert */
1418c6467627SVladimir Sementsov-Ogievskiy if (postcopy &&
1419c6467627SVladimir Sementsov-Ogievskiy !(se->ops->has_postcopy && se->ops->has_postcopy(se->opaque))) {
142035ecd943SDr. David Alan Gilbert continue;
142135ecd943SDr. David Alan Gilbert }
1422e1fde0e0SJuan Quintela if (migration_rate_exceeded(f)) {
1423c3049a56SJuan Quintela return 0;
1424c3049a56SJuan Quintela }
1425c3049a56SJuan Quintela trace_savevm_section_start(se->idstr, se->section_id);
1426ce39bfc9SDr. David Alan Gilbert
1427ce39bfc9SDr. David Alan Gilbert save_section_header(f, se, QEMU_VM_SECTION_PART);
1428c3049a56SJuan Quintela
1429c3049a56SJuan Quintela ret = se->ops->save_live_iterate(f, se->opaque);
1430c3049a56SJuan Quintela trace_savevm_section_end(se->idstr, se->section_id, ret);
1431f68945d4SDr. David Alan Gilbert save_section_footer(f, se);
1432c3049a56SJuan Quintela
1433c3049a56SJuan Quintela if (ret < 0) {
143492002658SDavid Edmondson error_report("failed to save SaveStateEntry with id(name): "
143592002658SDavid Edmondson "%d(%s): %d",
143692002658SDavid Edmondson se->section_id, se->idstr, ret);
1437c3049a56SJuan Quintela qemu_file_set_error(f, ret);
1438c3049a56SJuan Quintela return ret;
14394e1871c4SAvihai Horon } else if (!ret) {
14404e1871c4SAvihai Horon all_finished = false;
14414e1871c4SAvihai Horon }
14424e1871c4SAvihai Horon }
14434e1871c4SAvihai Horon return all_finished;
1444c3049a56SJuan Quintela }
1445c3049a56SJuan Quintela
should_send_vmdesc(void)1446c3049a56SJuan Quintela static bool should_send_vmdesc(void)
1447c3049a56SJuan Quintela {
1448c3049a56SJuan Quintela MachineState *machine = MACHINE(qdev_get_machine());
14495727309dSJuan Quintela bool in_postcopy = migration_in_postcopy();
14508421b205SDr. David Alan Gilbert return !machine->suppress_vmdesc && !in_postcopy;
1451c3049a56SJuan Quintela }
1452c3049a56SJuan Quintela
1453763c906bSDr. David Alan Gilbert /*
1454763c906bSDr. David Alan Gilbert * Calls the save_live_complete_postcopy methods
1455763c906bSDr. David Alan Gilbert * causing the last few pages to be sent immediately and doing any associated
1456763c906bSDr. David Alan Gilbert * cleanup.
1457763c906bSDr. David Alan Gilbert * Note postcopy also calls qemu_savevm_state_complete_precopy to complete
1458763c906bSDr. David Alan Gilbert * all the other devices, but that happens at the point we switch to postcopy.
1459763c906bSDr. David Alan Gilbert */
qemu_savevm_state_complete_postcopy(QEMUFile * f)1460763c906bSDr. David Alan Gilbert void qemu_savevm_state_complete_postcopy(QEMUFile *f)
1461763c906bSDr. David Alan Gilbert {
1462763c906bSDr. David Alan Gilbert SaveStateEntry *se;
1463763c906bSDr. David Alan Gilbert int ret;
1464763c906bSDr. David Alan Gilbert
1465763c906bSDr. David Alan Gilbert QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1466763c906bSDr. David Alan Gilbert if (!se->ops || !se->ops->save_live_complete_postcopy) {
1467763c906bSDr. David Alan Gilbert continue;
1468763c906bSDr. David Alan Gilbert }
1469cea3b4c0SWei Yang if (se->ops->is_active) {
1470763c906bSDr. David Alan Gilbert if (!se->ops->is_active(se->opaque)) {
1471763c906bSDr. David Alan Gilbert continue;
1472763c906bSDr. David Alan Gilbert }
1473763c906bSDr. David Alan Gilbert }
1474763c906bSDr. David Alan Gilbert trace_savevm_section_start(se->idstr, se->section_id);
1475763c906bSDr. David Alan Gilbert /* Section type */
1476763c906bSDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_SECTION_END);
1477763c906bSDr. David Alan Gilbert qemu_put_be32(f, se->section_id);
1478763c906bSDr. David Alan Gilbert
1479763c906bSDr. David Alan Gilbert ret = se->ops->save_live_complete_postcopy(f, se->opaque);
1480763c906bSDr. David Alan Gilbert trace_savevm_section_end(se->idstr, se->section_id, ret);
1481763c906bSDr. David Alan Gilbert save_section_footer(f, se);
1482763c906bSDr. David Alan Gilbert if (ret < 0) {
1483763c906bSDr. David Alan Gilbert qemu_file_set_error(f, ret);
1484763c906bSDr. David Alan Gilbert return;
1485763c906bSDr. David Alan Gilbert }
1486763c906bSDr. David Alan Gilbert }
1487763c906bSDr. David Alan Gilbert
1488763c906bSDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_EOF);
1489763c906bSDr. David Alan Gilbert qemu_fflush(f);
1490763c906bSDr. David Alan Gilbert }
1491763c906bSDr. David Alan Gilbert
1492622a80c9SWei Yang static
qemu_savevm_state_complete_precopy_iterable(QEMUFile * f,bool in_postcopy)1493e326767bSWei Yang int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy)
1494c3049a56SJuan Quintela {
14953c80f142SPeter Xu int64_t start_ts_each, end_ts_each;
1496c3049a56SJuan Quintela SaveStateEntry *se;
1497c3049a56SJuan Quintela int ret;
1498c3049a56SJuan Quintela
14990163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1500763c906bSDr. David Alan Gilbert if (!se->ops ||
1501c6467627SVladimir Sementsov-Ogievskiy (in_postcopy && se->ops->has_postcopy &&
1502c6467627SVladimir Sementsov-Ogievskiy se->ops->has_postcopy(se->opaque)) ||
1503763c906bSDr. David Alan Gilbert !se->ops->save_live_complete_precopy) {
1504c3049a56SJuan Quintela continue;
1505c3049a56SJuan Quintela }
15061c0d249dSDr. David Alan Gilbert
1507cea3b4c0SWei Yang if (se->ops->is_active) {
1508c3049a56SJuan Quintela if (!se->ops->is_active(se->opaque)) {
1509c3049a56SJuan Quintela continue;
1510c3049a56SJuan Quintela }
1511c3049a56SJuan Quintela }
15123c80f142SPeter Xu
15133c80f142SPeter Xu start_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
1514c3049a56SJuan Quintela trace_savevm_section_start(se->idstr, se->section_id);
1515ce39bfc9SDr. David Alan Gilbert
1516ce39bfc9SDr. David Alan Gilbert save_section_header(f, se, QEMU_VM_SECTION_END);
1517c3049a56SJuan Quintela
1518a3e06c3dSDr. David Alan Gilbert ret = se->ops->save_live_complete_precopy(f, se->opaque);
1519c3049a56SJuan Quintela trace_savevm_section_end(se->idstr, se->section_id, ret);
1520f68945d4SDr. David Alan Gilbert save_section_footer(f, se);
1521c3049a56SJuan Quintela if (ret < 0) {
1522c3049a56SJuan Quintela qemu_file_set_error(f, ret);
1523a1fbe750SFam Zheng return -1;
1524c3049a56SJuan Quintela }
15253c80f142SPeter Xu end_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
15263c80f142SPeter Xu trace_vmstate_downtime_save("iterable", se->idstr, se->instance_id,
15273c80f142SPeter Xu end_ts_each - start_ts_each);
1528c3049a56SJuan Quintela }
1529c3049a56SJuan Quintela
15303e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("src-iterable-saved");
15313e5f3bcdSPeter Xu
1532622a80c9SWei Yang return 0;
15331c0d249dSDr. David Alan Gilbert }
15341c0d249dSDr. David Alan Gilbert
qemu_savevm_state_complete_precopy_non_iterable(QEMUFile * f,bool in_postcopy,bool inactivate_disks)1535622a80c9SWei Yang int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f,
1536622a80c9SWei Yang bool in_postcopy,
1537622a80c9SWei Yang bool inactivate_disks)
1538622a80c9SWei Yang {
1539e3bf5e68SDavid Hildenbrand MigrationState *ms = migrate_get_current();
15403c80f142SPeter Xu int64_t start_ts_each, end_ts_each;
1541e3bf5e68SDavid Hildenbrand JSONWriter *vmdesc = ms->vmdesc;
1542622a80c9SWei Yang int vmdesc_len;
1543622a80c9SWei Yang SaveStateEntry *se;
15446138d43aSCédric Le Goater Error *local_err = NULL;
1545622a80c9SWei Yang int ret;
1546622a80c9SWei Yang
15470163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
154862f42625SDavid Hildenbrand if (se->vmsd && se->vmsd->early_setup) {
154962f42625SDavid Hildenbrand /* Already saved during qemu_savevm_state_setup(). */
155062f42625SDavid Hildenbrand continue;
155162f42625SDavid Hildenbrand }
155262f42625SDavid Hildenbrand
15533c80f142SPeter Xu start_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
15543c80f142SPeter Xu
15556138d43aSCédric Le Goater ret = vmstate_save(f, se, vmdesc, &local_err);
1556687433f6SDr. David Alan Gilbert if (ret) {
15576138d43aSCédric Le Goater migrate_set_error(ms, local_err);
15586138d43aSCédric Le Goater error_report_err(local_err);
1559687433f6SDr. David Alan Gilbert qemu_file_set_error(f, ret);
1560687433f6SDr. David Alan Gilbert return ret;
1561687433f6SDr. David Alan Gilbert }
15623c80f142SPeter Xu
15633c80f142SPeter Xu end_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
15643c80f142SPeter Xu trace_vmstate_downtime_save("non-iterable", se->idstr, se->instance_id,
15653c80f142SPeter Xu end_ts_each - start_ts_each);
1566c3049a56SJuan Quintela }
1567c3049a56SJuan Quintela
1568a1fbe750SFam Zheng if (inactivate_disks) {
1569a1fbe750SFam Zheng /* Inactivate before sending QEMU_VM_EOF so that the
15703b717194SEmanuele Giuseppe Esposito * bdrv_activate_all() on the other end won't fail. */
1571a1fbe750SFam Zheng ret = bdrv_inactivate_all();
1572a1fbe750SFam Zheng if (ret) {
1573848a0503STejus GK error_setg(&local_err, "%s: bdrv_inactivate_all() failed (%d)",
1574c232bf58SDr. David Alan Gilbert __func__, ret);
1575848a0503STejus GK migrate_set_error(ms, local_err);
1576848a0503STejus GK error_report_err(local_err);
1577a1fbe750SFam Zheng qemu_file_set_error(f, ret);
1578a1fbe750SFam Zheng return ret;
1579a1fbe750SFam Zheng }
1580a1fbe750SFam Zheng }
1581763c906bSDr. David Alan Gilbert if (!in_postcopy) {
1582763c906bSDr. David Alan Gilbert /* Postcopy stream will still be going */
1583c3049a56SJuan Quintela qemu_put_byte(f, QEMU_VM_EOF);
1584763c906bSDr. David Alan Gilbert }
1585c3049a56SJuan Quintela
15863ddba9a9SMarkus Armbruster json_writer_end_array(vmdesc);
15873ddba9a9SMarkus Armbruster json_writer_end_object(vmdesc);
15883ddba9a9SMarkus Armbruster vmdesc_len = strlen(json_writer_get(vmdesc));
1589c3049a56SJuan Quintela
1590c3049a56SJuan Quintela if (should_send_vmdesc()) {
1591c3049a56SJuan Quintela qemu_put_byte(f, QEMU_VM_VMDESCRIPTION);
1592c3049a56SJuan Quintela qemu_put_be32(f, vmdesc_len);
15933ddba9a9SMarkus Armbruster qemu_put_buffer(f, (uint8_t *)json_writer_get(vmdesc), vmdesc_len);
1594c3049a56SJuan Quintela }
1595c3049a56SJuan Quintela
1596e3bf5e68SDavid Hildenbrand /* Free it now to detect any inconsistencies. */
1597e3bf5e68SDavid Hildenbrand json_writer_free(vmdesc);
1598e3bf5e68SDavid Hildenbrand ms->vmdesc = NULL;
1599e3bf5e68SDavid Hildenbrand
16003e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("src-non-iterable-saved");
16013e5f3bcdSPeter Xu
1602622a80c9SWei Yang return 0;
1603622a80c9SWei Yang }
1604622a80c9SWei Yang
qemu_savevm_state_complete_precopy(QEMUFile * f,bool iterable_only,bool inactivate_disks)1605622a80c9SWei Yang int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only,
1606622a80c9SWei Yang bool inactivate_disks)
1607622a80c9SWei Yang {
1608622a80c9SWei Yang int ret;
1609622a80c9SWei Yang Error *local_err = NULL;
1610622a80c9SWei Yang bool in_postcopy = migration_in_postcopy();
1611622a80c9SWei Yang
1612622a80c9SWei Yang if (precopy_notify(PRECOPY_NOTIFY_COMPLETE, &local_err)) {
1613622a80c9SWei Yang error_report_err(local_err);
1614622a80c9SWei Yang }
1615622a80c9SWei Yang
1616622a80c9SWei Yang trace_savevm_state_complete_precopy();
1617622a80c9SWei Yang
1618622a80c9SWei Yang cpu_synchronize_all_states();
1619622a80c9SWei Yang
1620e326767bSWei Yang if (!in_postcopy || iterable_only) {
1621e326767bSWei Yang ret = qemu_savevm_state_complete_precopy_iterable(f, in_postcopy);
1622622a80c9SWei Yang if (ret) {
1623622a80c9SWei Yang return ret;
1624622a80c9SWei Yang }
1625e326767bSWei Yang }
1626622a80c9SWei Yang
1627622a80c9SWei Yang if (iterable_only) {
1628622a80c9SWei Yang goto flush;
1629622a80c9SWei Yang }
1630622a80c9SWei Yang
1631622a80c9SWei Yang ret = qemu_savevm_state_complete_precopy_non_iterable(f, in_postcopy,
1632622a80c9SWei Yang inactivate_disks);
1633622a80c9SWei Yang if (ret) {
1634622a80c9SWei Yang return ret;
1635622a80c9SWei Yang }
1636622a80c9SWei Yang
16374e455d51SWei Yang flush:
1638be07a0edSJuan Quintela return qemu_fflush(f);
1639c3049a56SJuan Quintela }
1640c3049a56SJuan Quintela
1641c31b098fSDr. David Alan Gilbert /* Give an estimate of the amount left to be transferred,
1642c31b098fSDr. David Alan Gilbert * the result is split into the amount for units that can and
1643c31b098fSDr. David Alan Gilbert * for units that can't do postcopy.
1644c31b098fSDr. David Alan Gilbert */
qemu_savevm_state_pending_estimate(uint64_t * must_precopy,uint64_t * can_postcopy)164524beea4eSJuan Quintela void qemu_savevm_state_pending_estimate(uint64_t *must_precopy,
164624beea4eSJuan Quintela uint64_t *can_postcopy)
1647c3049a56SJuan Quintela {
1648c3049a56SJuan Quintela SaveStateEntry *se;
1649c31b098fSDr. David Alan Gilbert
165024beea4eSJuan Quintela *must_precopy = 0;
165124beea4eSJuan Quintela *can_postcopy = 0;
1652c31b098fSDr. David Alan Gilbert
16530163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1654e2647050SJuan Quintela if (!se->ops || !se->ops->state_pending_estimate) {
1655c3049a56SJuan Quintela continue;
1656c3049a56SJuan Quintela }
1657cea3b4c0SWei Yang if (se->ops->is_active) {
1658c3049a56SJuan Quintela if (!se->ops->is_active(se->opaque)) {
1659c3049a56SJuan Quintela continue;
1660c3049a56SJuan Quintela }
1661c3049a56SJuan Quintela }
166224beea4eSJuan Quintela se->ops->state_pending_estimate(se->opaque, must_precopy, can_postcopy);
1663c8df4a7aSJuan Quintela }
1664c8df4a7aSJuan Quintela }
1665c8df4a7aSJuan Quintela
qemu_savevm_state_pending_exact(uint64_t * must_precopy,uint64_t * can_postcopy)166624beea4eSJuan Quintela void qemu_savevm_state_pending_exact(uint64_t *must_precopy,
166724beea4eSJuan Quintela uint64_t *can_postcopy)
1668c8df4a7aSJuan Quintela {
1669c8df4a7aSJuan Quintela SaveStateEntry *se;
1670c8df4a7aSJuan Quintela
167124beea4eSJuan Quintela *must_precopy = 0;
167224beea4eSJuan Quintela *can_postcopy = 0;
1673c8df4a7aSJuan Quintela
1674c8df4a7aSJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1675e2647050SJuan Quintela if (!se->ops || !se->ops->state_pending_exact) {
1676c8df4a7aSJuan Quintela continue;
1677c8df4a7aSJuan Quintela }
1678c8df4a7aSJuan Quintela if (se->ops->is_active) {
1679c8df4a7aSJuan Quintela if (!se->ops->is_active(se->opaque)) {
1680c8df4a7aSJuan Quintela continue;
1681c8df4a7aSJuan Quintela }
1682c8df4a7aSJuan Quintela }
168324beea4eSJuan Quintela se->ops->state_pending_exact(se->opaque, must_precopy, can_postcopy);
1684c3049a56SJuan Quintela }
1685c3049a56SJuan Quintela }
1686c3049a56SJuan Quintela
qemu_savevm_state_cleanup(void)1687ea7415faSLiang Li void qemu_savevm_state_cleanup(void)
1688c3049a56SJuan Quintela {
1689c3049a56SJuan Quintela SaveStateEntry *se;
1690bd227060SWei Wang Error *local_err = NULL;
1691bd227060SWei Wang
1692bd227060SWei Wang if (precopy_notify(PRECOPY_NOTIFY_CLEANUP, &local_err)) {
1693bd227060SWei Wang error_report_err(local_err);
1694bd227060SWei Wang }
1695c3049a56SJuan Quintela
1696ea7415faSLiang Li trace_savevm_state_cleanup();
16970163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
169870f794fcSJuan Quintela if (se->ops && se->ops->save_cleanup) {
169970f794fcSJuan Quintela se->ops->save_cleanup(se->opaque);
1700c3049a56SJuan Quintela }
1701c3049a56SJuan Quintela }
1702c3049a56SJuan Quintela }
1703c3049a56SJuan Quintela
qemu_savevm_state(QEMUFile * f,Error ** errp)1704c3049a56SJuan Quintela static int qemu_savevm_state(QEMUFile *f, Error **errp)
1705c3049a56SJuan Quintela {
1706c3049a56SJuan Quintela int ret;
17073e0c8050SPeter Xu MigrationState *ms = migrate_get_current();
17086dcf6668SDenis V. Lunev MigrationStatus status;
17093e0c8050SPeter Xu
1710aeaafb1eSSteve Sistare if (migration_is_running()) {
171100580786SPhilippe Mathieu-Daudé error_setg(errp, "There's a migration process in progress");
17123d63da16SJia Lina return -EINVAL;
17133d63da16SJia Lina }
1714c3049a56SJuan Quintela
171508fc4cb5SAvihai Horon ret = migrate_init(ms, errp);
171608fc4cb5SAvihai Horon if (ret) {
171708fc4cb5SAvihai Horon return ret;
171808fc4cb5SAvihai Horon }
17193d63da16SJia Lina ms->to_dst_file = f;
17203d63da16SJia Lina
1721f796baa1SDr. David Alan Gilbert qemu_savevm_state_header(f);
1722057a2009SCédric Le Goater ret = qemu_savevm_state_setup(f, errp);
1723057a2009SCédric Le Goater if (ret) {
1724057a2009SCédric Le Goater goto cleanup;
1725057a2009SCédric Le Goater }
1726c3049a56SJuan Quintela
1727c3049a56SJuan Quintela while (qemu_file_get_error(f) == 0) {
172835ecd943SDr. David Alan Gilbert if (qemu_savevm_state_iterate(f, false) > 0) {
1729c3049a56SJuan Quintela break;
1730c3049a56SJuan Quintela }
1731c3049a56SJuan Quintela }
1732c3049a56SJuan Quintela
1733c3049a56SJuan Quintela ret = qemu_file_get_error(f);
1734c3049a56SJuan Quintela if (ret == 0) {
1735a1fbe750SFam Zheng qemu_savevm_state_complete_precopy(f, false, false);
1736c3049a56SJuan Quintela ret = qemu_file_get_error(f);
1737c3049a56SJuan Quintela }
173815b3b8eaSDenis V. Lunev if (ret != 0) {
1739c3049a56SJuan Quintela error_setg_errno(errp, -ret, "Error while writing VM state");
1740c3049a56SJuan Quintela }
1741057a2009SCédric Le Goater cleanup:
1742057a2009SCédric Le Goater qemu_savevm_state_cleanup();
17436dcf6668SDenis V. Lunev
17446dcf6668SDenis V. Lunev if (ret != 0) {
17456dcf6668SDenis V. Lunev status = MIGRATION_STATUS_FAILED;
17466dcf6668SDenis V. Lunev } else {
17476dcf6668SDenis V. Lunev status = MIGRATION_STATUS_COMPLETED;
17486dcf6668SDenis V. Lunev }
17496dcf6668SDenis V. Lunev migrate_set_state(&ms->state, MIGRATION_STATUS_SETUP, status);
1750f9c8caa0SVladimir Sementsov-Ogievskiy
1751f9c8caa0SVladimir Sementsov-Ogievskiy /* f is outer parameter, it should not stay in global migration state after
1752f9c8caa0SVladimir Sementsov-Ogievskiy * this function finished */
1753f9c8caa0SVladimir Sementsov-Ogievskiy ms->to_dst_file = NULL;
1754f9c8caa0SVladimir Sementsov-Ogievskiy
1755c3049a56SJuan Quintela return ret;
1756c3049a56SJuan Quintela }
1757c3049a56SJuan Quintela
qemu_savevm_live_state(QEMUFile * f)17583f6df99dSZhang Chen void qemu_savevm_live_state(QEMUFile *f)
17593f6df99dSZhang Chen {
17603f6df99dSZhang Chen /* save QEMU_VM_SECTION_END section */
17613f6df99dSZhang Chen qemu_savevm_state_complete_precopy(f, true, false);
17623f6df99dSZhang Chen qemu_put_byte(f, QEMU_VM_EOF);
17633f6df99dSZhang Chen }
17643f6df99dSZhang Chen
qemu_save_device_state(QEMUFile * f)17653f6df99dSZhang Chen int qemu_save_device_state(QEMUFile *f)
1766c3049a56SJuan Quintela {
17676138d43aSCédric Le Goater MigrationState *ms = migrate_get_current();
17686138d43aSCédric Le Goater Error *local_err = NULL;
1769c3049a56SJuan Quintela SaveStateEntry *se;
1770c3049a56SJuan Quintela
17713f6df99dSZhang Chen if (!migration_in_colo_state()) {
1772c3049a56SJuan Quintela qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
1773c3049a56SJuan Quintela qemu_put_be32(f, QEMU_VM_FILE_VERSION);
17743f6df99dSZhang Chen }
1775c3049a56SJuan Quintela cpu_synchronize_all_states();
1776c3049a56SJuan Quintela
17770163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1778687433f6SDr. David Alan Gilbert int ret;
1779687433f6SDr. David Alan Gilbert
1780c3049a56SJuan Quintela if (se->is_ram) {
1781c3049a56SJuan Quintela continue;
1782c3049a56SJuan Quintela }
17836138d43aSCédric Le Goater ret = vmstate_save(f, se, NULL, &local_err);
1784687433f6SDr. David Alan Gilbert if (ret) {
17856138d43aSCédric Le Goater migrate_set_error(ms, local_err);
17866138d43aSCédric Le Goater error_report_err(local_err);
1787687433f6SDr. David Alan Gilbert return ret;
1788687433f6SDr. David Alan Gilbert }
1789c3049a56SJuan Quintela }
1790c3049a56SJuan Quintela
1791c3049a56SJuan Quintela qemu_put_byte(f, QEMU_VM_EOF);
1792c3049a56SJuan Quintela
1793c3049a56SJuan Quintela return qemu_file_get_error(f);
1794c3049a56SJuan Quintela }
1795c3049a56SJuan Quintela
find_se(const char * idstr,uint32_t instance_id)179693062e23SPeter Xu static SaveStateEntry *find_se(const char *idstr, uint32_t instance_id)
1797c3049a56SJuan Quintela {
1798c3049a56SJuan Quintela SaveStateEntry *se;
1799c3049a56SJuan Quintela
18000163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1801c3049a56SJuan Quintela if (!strcmp(se->idstr, idstr) &&
1802c3049a56SJuan Quintela (instance_id == se->instance_id ||
1803c3049a56SJuan Quintela instance_id == se->alias_id))
1804c3049a56SJuan Quintela return se;
1805c3049a56SJuan Quintela /* Migrating from an older version? */
1806c3049a56SJuan Quintela if (strstr(se->idstr, idstr) && se->compat) {
1807c3049a56SJuan Quintela if (!strcmp(se->compat->idstr, idstr) &&
1808c3049a56SJuan Quintela (instance_id == se->compat->instance_id ||
1809c3049a56SJuan Quintela instance_id == se->alias_id))
1810c3049a56SJuan Quintela return se;
1811c3049a56SJuan Quintela }
1812c3049a56SJuan Quintela }
1813c3049a56SJuan Quintela return NULL;
1814c3049a56SJuan Quintela }
1815c3049a56SJuan Quintela
18167b89bf27SDr. David Alan Gilbert enum LoadVMExitCodes {
18177b89bf27SDr. David Alan Gilbert /* Allow a command to quit all layers of nested loadvm loops */
18187b89bf27SDr. David Alan Gilbert LOADVM_QUIT = 1,
18197b89bf27SDr. David Alan Gilbert };
18207b89bf27SDr. David Alan Gilbert
1821093e3c42SDr. David Alan Gilbert /* ------ incoming postcopy messages ------ */
1822093e3c42SDr. David Alan Gilbert /* 'advise' arrives before any transfers just to tell us that a postcopy
1823093e3c42SDr. David Alan Gilbert * *might* happen - it might be skipped if precopy transferred everything
1824093e3c42SDr. David Alan Gilbert * quickly.
1825093e3c42SDr. David Alan Gilbert */
loadvm_postcopy_handle_advise(MigrationIncomingState * mis,uint16_t len)1826875fcd01SGreg Kurz static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
1827875fcd01SGreg Kurz uint16_t len)
1828093e3c42SDr. David Alan Gilbert {
1829093e3c42SDr. David Alan Gilbert PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
1830e8ca1db2SDr. David Alan Gilbert uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps;
1831144fa06bSJuan Quintela size_t page_size = qemu_target_page_size();
1832d3dff7a5SDr. David Alan Gilbert Error *local_err = NULL;
1833093e3c42SDr. David Alan Gilbert
1834093e3c42SDr. David Alan Gilbert trace_loadvm_postcopy_handle_advise();
1835093e3c42SDr. David Alan Gilbert if (ps != POSTCOPY_INCOMING_NONE) {
1836093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_ADVISE in wrong postcopy state (%d)", ps);
1837093e3c42SDr. David Alan Gilbert return -1;
1838093e3c42SDr. David Alan Gilbert }
1839093e3c42SDr. David Alan Gilbert
1840875fcd01SGreg Kurz switch (len) {
1841875fcd01SGreg Kurz case 0:
1842875fcd01SGreg Kurz if (migrate_postcopy_ram()) {
1843875fcd01SGreg Kurz error_report("RAM postcopy is enabled but have 0 byte advise");
1844875fcd01SGreg Kurz return -EINVAL;
1845875fcd01SGreg Kurz }
184658110f0aSVladimir Sementsov-Ogievskiy return 0;
1847875fcd01SGreg Kurz case 8 + 8:
1848875fcd01SGreg Kurz if (!migrate_postcopy_ram()) {
1849875fcd01SGreg Kurz error_report("RAM postcopy is disabled but have 16 byte advise");
1850875fcd01SGreg Kurz return -EINVAL;
1851875fcd01SGreg Kurz }
1852875fcd01SGreg Kurz break;
1853875fcd01SGreg Kurz default:
1854875fcd01SGreg Kurz error_report("CMD_POSTCOPY_ADVISE invalid length (%d)", len);
1855875fcd01SGreg Kurz return -EINVAL;
185658110f0aSVladimir Sementsov-Ogievskiy }
185758110f0aSVladimir Sementsov-Ogievskiy
185874c38cf7SPeter Xu if (!postcopy_ram_supported_by_host(mis, &local_err)) {
185974c38cf7SPeter Xu error_report_err(local_err);
1860328d4d85SDr. David Alan Gilbert postcopy_state_set(POSTCOPY_INCOMING_NONE);
1861eb59db53SDr. David Alan Gilbert return -1;
1862eb59db53SDr. David Alan Gilbert }
1863eb59db53SDr. David Alan Gilbert
1864e8ca1db2SDr. David Alan Gilbert remote_pagesize_summary = qemu_get_be64(mis->from_src_file);
1865e8ca1db2SDr. David Alan Gilbert local_pagesize_summary = ram_pagesize_summary();
1866e8ca1db2SDr. David Alan Gilbert
1867e8ca1db2SDr. David Alan Gilbert if (remote_pagesize_summary != local_pagesize_summary) {
1868093e3c42SDr. David Alan Gilbert /*
1869e8ca1db2SDr. David Alan Gilbert * This detects two potential causes of mismatch:
1870e8ca1db2SDr. David Alan Gilbert * a) A mismatch in host page sizes
1871093e3c42SDr. David Alan Gilbert * Some combinations of mismatch are probably possible but it gets
1872093e3c42SDr. David Alan Gilbert * a bit more complicated. In particular we need to place whole
1873093e3c42SDr. David Alan Gilbert * host pages on the dest at once, and we need to ensure that we
1874093e3c42SDr. David Alan Gilbert * handle dirtying to make sure we never end up sending part of
1875093e3c42SDr. David Alan Gilbert * a hostpage on it's own.
1876e8ca1db2SDr. David Alan Gilbert * b) The use of different huge page sizes on source/destination
1877e8ca1db2SDr. David Alan Gilbert * a more fine grain test is performed during RAM block migration
1878e8ca1db2SDr. David Alan Gilbert * but this test here causes a nice early clear failure, and
1879e8ca1db2SDr. David Alan Gilbert * also fails when passed to an older qemu that doesn't
1880e8ca1db2SDr. David Alan Gilbert * do huge pages.
1881093e3c42SDr. David Alan Gilbert */
1882e8ca1db2SDr. David Alan Gilbert error_report("Postcopy needs matching RAM page sizes (s=%" PRIx64
1883e8ca1db2SDr. David Alan Gilbert " d=%" PRIx64 ")",
1884e8ca1db2SDr. David Alan Gilbert remote_pagesize_summary, local_pagesize_summary);
1885093e3c42SDr. David Alan Gilbert return -1;
1886093e3c42SDr. David Alan Gilbert }
1887093e3c42SDr. David Alan Gilbert
1888093e3c42SDr. David Alan Gilbert remote_tps = qemu_get_be64(mis->from_src_file);
1889144fa06bSJuan Quintela if (remote_tps != page_size) {
1890093e3c42SDr. David Alan Gilbert /*
1891093e3c42SDr. David Alan Gilbert * Again, some differences could be dealt with, but for now keep it
1892093e3c42SDr. David Alan Gilbert * simple.
1893093e3c42SDr. David Alan Gilbert */
189420afaed9SJuan Quintela error_report("Postcopy needs matching target page sizes (s=%d d=%zd)",
1895144fa06bSJuan Quintela (int)remote_tps, page_size);
1896093e3c42SDr. David Alan Gilbert return -1;
1897093e3c42SDr. David Alan Gilbert }
1898093e3c42SDr. David Alan Gilbert
1899d3dff7a5SDr. David Alan Gilbert if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, &local_err)) {
1900d3dff7a5SDr. David Alan Gilbert error_report_err(local_err);
1901d3dff7a5SDr. David Alan Gilbert return -1;
1902d3dff7a5SDr. David Alan Gilbert }
1903d3dff7a5SDr. David Alan Gilbert
19041caddf8aSDr. David Alan Gilbert if (ram_postcopy_incoming_init(mis)) {
19051caddf8aSDr. David Alan Gilbert return -1;
19061caddf8aSDr. David Alan Gilbert }
19071caddf8aSDr. David Alan Gilbert
1908093e3c42SDr. David Alan Gilbert return 0;
1909093e3c42SDr. David Alan Gilbert }
1910093e3c42SDr. David Alan Gilbert
1911093e3c42SDr. David Alan Gilbert /* After postcopy we will be told to throw some pages away since they're
1912093e3c42SDr. David Alan Gilbert * dirty and will have to be demand fetched. Must happen before CPU is
1913093e3c42SDr. David Alan Gilbert * started.
1914093e3c42SDr. David Alan Gilbert * There can be 0..many of these messages, each encoding multiple pages.
1915093e3c42SDr. David Alan Gilbert */
loadvm_postcopy_ram_handle_discard(MigrationIncomingState * mis,uint16_t len)1916093e3c42SDr. David Alan Gilbert static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis,
1917093e3c42SDr. David Alan Gilbert uint16_t len)
1918093e3c42SDr. David Alan Gilbert {
1919093e3c42SDr. David Alan Gilbert int tmp;
1920093e3c42SDr. David Alan Gilbert char ramid[256];
1921093e3c42SDr. David Alan Gilbert PostcopyState ps = postcopy_state_get();
1922093e3c42SDr. David Alan Gilbert
1923093e3c42SDr. David Alan Gilbert trace_loadvm_postcopy_ram_handle_discard();
1924093e3c42SDr. David Alan Gilbert
1925093e3c42SDr. David Alan Gilbert switch (ps) {
1926093e3c42SDr. David Alan Gilbert case POSTCOPY_INCOMING_ADVISE:
1927093e3c42SDr. David Alan Gilbert /* 1st discard */
1928f9527107SDr. David Alan Gilbert tmp = postcopy_ram_prepare_discard(mis);
1929093e3c42SDr. David Alan Gilbert if (tmp) {
1930093e3c42SDr. David Alan Gilbert return tmp;
1931093e3c42SDr. David Alan Gilbert }
1932093e3c42SDr. David Alan Gilbert break;
1933093e3c42SDr. David Alan Gilbert
1934093e3c42SDr. David Alan Gilbert case POSTCOPY_INCOMING_DISCARD:
1935093e3c42SDr. David Alan Gilbert /* Expected state */
1936093e3c42SDr. David Alan Gilbert break;
1937093e3c42SDr. David Alan Gilbert
1938093e3c42SDr. David Alan Gilbert default:
1939093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD in wrong postcopy state (%d)",
1940093e3c42SDr. David Alan Gilbert ps);
1941093e3c42SDr. David Alan Gilbert return -1;
1942093e3c42SDr. David Alan Gilbert }
1943093e3c42SDr. David Alan Gilbert /* We're expecting a
1944093e3c42SDr. David Alan Gilbert * Version (0)
1945093e3c42SDr. David Alan Gilbert * a RAM ID string (length byte, name, 0 term)
1946093e3c42SDr. David Alan Gilbert * then at least 1 16 byte chunk
1947093e3c42SDr. David Alan Gilbert */
1948093e3c42SDr. David Alan Gilbert if (len < (1 + 1 + 1 + 1 + 2 * 8)) {
1949093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len);
1950093e3c42SDr. David Alan Gilbert return -1;
1951093e3c42SDr. David Alan Gilbert }
1952093e3c42SDr. David Alan Gilbert
1953093e3c42SDr. David Alan Gilbert tmp = qemu_get_byte(mis->from_src_file);
1954093e3c42SDr. David Alan Gilbert if (tmp != postcopy_ram_discard_version) {
1955093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD invalid version (%d)", tmp);
1956093e3c42SDr. David Alan Gilbert return -1;
1957093e3c42SDr. David Alan Gilbert }
1958093e3c42SDr. David Alan Gilbert
1959093e3c42SDr. David Alan Gilbert if (!qemu_get_counted_string(mis->from_src_file, ramid)) {
1960093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD Failed to read RAMBlock ID");
1961093e3c42SDr. David Alan Gilbert return -1;
1962093e3c42SDr. David Alan Gilbert }
1963093e3c42SDr. David Alan Gilbert tmp = qemu_get_byte(mis->from_src_file);
1964093e3c42SDr. David Alan Gilbert if (tmp != 0) {
1965093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD missing nil (%d)", tmp);
1966093e3c42SDr. David Alan Gilbert return -1;
1967093e3c42SDr. David Alan Gilbert }
1968093e3c42SDr. David Alan Gilbert
1969093e3c42SDr. David Alan Gilbert len -= 3 + strlen(ramid);
1970093e3c42SDr. David Alan Gilbert if (len % 16) {
1971093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len);
1972093e3c42SDr. David Alan Gilbert return -1;
1973093e3c42SDr. David Alan Gilbert }
1974093e3c42SDr. David Alan Gilbert trace_loadvm_postcopy_ram_handle_discard_header(ramid, len);
1975093e3c42SDr. David Alan Gilbert while (len) {
1976093e3c42SDr. David Alan Gilbert uint64_t start_addr, block_length;
1977093e3c42SDr. David Alan Gilbert start_addr = qemu_get_be64(mis->from_src_file);
1978093e3c42SDr. David Alan Gilbert block_length = qemu_get_be64(mis->from_src_file);
1979093e3c42SDr. David Alan Gilbert
1980093e3c42SDr. David Alan Gilbert len -= 16;
1981aaa2064cSJuan Quintela int ret = ram_discard_range(ramid, start_addr, block_length);
1982093e3c42SDr. David Alan Gilbert if (ret) {
1983093e3c42SDr. David Alan Gilbert return ret;
1984093e3c42SDr. David Alan Gilbert }
1985093e3c42SDr. David Alan Gilbert }
1986093e3c42SDr. David Alan Gilbert trace_loadvm_postcopy_ram_handle_discard_end();
1987093e3c42SDr. David Alan Gilbert
1988093e3c42SDr. David Alan Gilbert return 0;
1989093e3c42SDr. David Alan Gilbert }
1990093e3c42SDr. David Alan Gilbert
1991c76201abSDr. David Alan Gilbert /*
1992c76201abSDr. David Alan Gilbert * Triggered by a postcopy_listen command; this thread takes over reading
1993c76201abSDr. David Alan Gilbert * the input stream, leaving the main thread free to carry on loading the rest
1994c76201abSDr. David Alan Gilbert * of the device state (from RAM).
1995c76201abSDr. David Alan Gilbert * (TODO:This could do with being in a postcopy file - but there again it's
1996c76201abSDr. David Alan Gilbert * just another input loop, not that postcopy specific)
1997c76201abSDr. David Alan Gilbert */
postcopy_ram_listen_thread(void * opaque)1998c76201abSDr. David Alan Gilbert static void *postcopy_ram_listen_thread(void *opaque)
1999c76201abSDr. David Alan Gilbert {
2000c76201abSDr. David Alan Gilbert MigrationIncomingState *mis = migration_incoming_get_current();
2001b411b844SPeter Xu QEMUFile *f = mis->from_src_file;
2002c76201abSDr. David Alan Gilbert int load_res;
2003ee647225SVladimir Sementsov-Ogievskiy MigrationState *migr = migrate_get_current();
2004ee647225SVladimir Sementsov-Ogievskiy
2005ee647225SVladimir Sementsov-Ogievskiy object_ref(OBJECT(migr));
2006c76201abSDr. David Alan Gilbert
20076ba996bbSDr. David Alan Gilbert migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
20086ba996bbSDr. David Alan Gilbert MIGRATION_STATUS_POSTCOPY_ACTIVE);
2009095c12a4SPeter Xu qemu_sem_post(&mis->thread_sync_sem);
2010c76201abSDr. David Alan Gilbert trace_postcopy_ram_listen_thread_start();
2011c76201abSDr. David Alan Gilbert
201274637e6fSLidong Chen rcu_register_thread();
2013c76201abSDr. David Alan Gilbert /*
2014c76201abSDr. David Alan Gilbert * Because we're a thread and not a coroutine we can't yield
2015c76201abSDr. David Alan Gilbert * in qemu_file, and thus we must be blocking now.
2016c76201abSDr. David Alan Gilbert */
2017c76201abSDr. David Alan Gilbert qemu_file_set_blocking(f, true);
2018c76201abSDr. David Alan Gilbert load_res = qemu_loadvm_state_main(f, mis);
2019b411b844SPeter Xu
2020b411b844SPeter Xu /*
2021b411b844SPeter Xu * This is tricky, but, mis->from_src_file can change after it
2022b411b844SPeter Xu * returns, when postcopy recovery happened. In the future, we may
2023b411b844SPeter Xu * want a wrapper for the QEMUFile handle.
2024b411b844SPeter Xu */
2025b411b844SPeter Xu f = mis->from_src_file;
2026b411b844SPeter Xu
2027c76201abSDr. David Alan Gilbert /* And non-blocking again so we don't block in any cleanup */
2028c76201abSDr. David Alan Gilbert qemu_file_set_blocking(f, false);
2029c76201abSDr. David Alan Gilbert
2030c76201abSDr. David Alan Gilbert trace_postcopy_ram_listen_thread_exit();
2031c76201abSDr. David Alan Gilbert if (load_res < 0) {
2032c76201abSDr. David Alan Gilbert qemu_file_set_error(f, load_res);
2033ee647225SVladimir Sementsov-Ogievskiy dirty_bitmap_mig_cancel_incoming();
2034ee647225SVladimir Sementsov-Ogievskiy if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING &&
2035ee647225SVladimir Sementsov-Ogievskiy !migrate_postcopy_ram() && migrate_dirty_bitmaps())
2036ee647225SVladimir Sementsov-Ogievskiy {
2037ee647225SVladimir Sementsov-Ogievskiy error_report("%s: loadvm failed during postcopy: %d. All states "
2038ee647225SVladimir Sementsov-Ogievskiy "are migrated except dirty bitmaps. Some dirty "
2039ee647225SVladimir Sementsov-Ogievskiy "bitmaps may be lost, and present migrated dirty "
2040ee647225SVladimir Sementsov-Ogievskiy "bitmaps are correctly migrated and valid.",
2041ee647225SVladimir Sementsov-Ogievskiy __func__, load_res);
2042ee647225SVladimir Sementsov-Ogievskiy load_res = 0; /* prevent further exit() */
2043ee647225SVladimir Sementsov-Ogievskiy } else {
2044ee647225SVladimir Sementsov-Ogievskiy error_report("%s: loadvm failed: %d", __func__, load_res);
20456ba996bbSDr. David Alan Gilbert migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
20466ba996bbSDr. David Alan Gilbert MIGRATION_STATUS_FAILED);
2047ee647225SVladimir Sementsov-Ogievskiy }
2048ee647225SVladimir Sementsov-Ogievskiy }
2049ee647225SVladimir Sementsov-Ogievskiy if (load_res >= 0) {
2050c76201abSDr. David Alan Gilbert /*
2051c76201abSDr. David Alan Gilbert * This looks good, but it's possible that the device loading in the
2052c76201abSDr. David Alan Gilbert * main thread hasn't finished yet, and so we might not be in 'RUN'
2053c76201abSDr. David Alan Gilbert * state yet; wait for the end of the main thread.
2054c76201abSDr. David Alan Gilbert */
2055c76201abSDr. David Alan Gilbert qemu_event_wait(&mis->main_thread_load_event);
2056c76201abSDr. David Alan Gilbert }
2057c76201abSDr. David Alan Gilbert postcopy_ram_incoming_cleanup(mis);
2058c76201abSDr. David Alan Gilbert
2059c76201abSDr. David Alan Gilbert if (load_res < 0) {
2060c76201abSDr. David Alan Gilbert /*
2061c76201abSDr. David Alan Gilbert * If something went wrong then we have a bad state so exit;
2062c76201abSDr. David Alan Gilbert * depending how far we got it might be possible at this point
2063c76201abSDr. David Alan Gilbert * to leave the guest running and fire MCEs for pages that never
2064c76201abSDr. David Alan Gilbert * arrived as a desperate recovery step.
2065c76201abSDr. David Alan Gilbert */
206674637e6fSLidong Chen rcu_unregister_thread();
2067c76201abSDr. David Alan Gilbert exit(EXIT_FAILURE);
2068c76201abSDr. David Alan Gilbert }
2069c76201abSDr. David Alan Gilbert
20706ba996bbSDr. David Alan Gilbert migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
20716ba996bbSDr. David Alan Gilbert MIGRATION_STATUS_COMPLETED);
20726ba996bbSDr. David Alan Gilbert /*
20736ba996bbSDr. David Alan Gilbert * If everything has worked fine, then the main thread has waited
20746ba996bbSDr. David Alan Gilbert * for us to start, and we're the last use of the mis.
20756ba996bbSDr. David Alan Gilbert * (If something broke then qemu will have to exit anyway since it's
20766ba996bbSDr. David Alan Gilbert * got a bad migration state).
20776ba996bbSDr. David Alan Gilbert */
20786ba996bbSDr. David Alan Gilbert migration_incoming_state_destroy();
2079acb5ea86SJuan Quintela qemu_loadvm_state_cleanup();
20806ba996bbSDr. David Alan Gilbert
208174637e6fSLidong Chen rcu_unregister_thread();
20829cf4bb87SDr. David Alan Gilbert mis->have_listen_thread = false;
20832d49bacdSWei Yang postcopy_state_set(POSTCOPY_INCOMING_END);
20842d49bacdSWei Yang
2085ee647225SVladimir Sementsov-Ogievskiy object_unref(OBJECT(migr));
2086ee647225SVladimir Sementsov-Ogievskiy
2087c76201abSDr. David Alan Gilbert return NULL;
2088c76201abSDr. David Alan Gilbert }
2089c76201abSDr. David Alan Gilbert
2090093e3c42SDr. David Alan Gilbert /* After this message we must be able to immediately receive postcopy data */
loadvm_postcopy_handle_listen(MigrationIncomingState * mis)2091093e3c42SDr. David Alan Gilbert static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)
2092093e3c42SDr. David Alan Gilbert {
2093093e3c42SDr. David Alan Gilbert PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_LISTENING);
20946864a7b5SDr. David Alan Gilbert Error *local_err = NULL;
20956864a7b5SDr. David Alan Gilbert
2096c84f976eSPeter Xu trace_loadvm_postcopy_handle_listen("enter");
2097c84f976eSPeter Xu
2098093e3c42SDr. David Alan Gilbert if (ps != POSTCOPY_INCOMING_ADVISE && ps != POSTCOPY_INCOMING_DISCARD) {
2099093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_LISTEN in wrong postcopy state (%d)", ps);
2100093e3c42SDr. David Alan Gilbert return -1;
2101093e3c42SDr. David Alan Gilbert }
2102f9527107SDr. David Alan Gilbert if (ps == POSTCOPY_INCOMING_ADVISE) {
2103f9527107SDr. David Alan Gilbert /*
2104f9527107SDr. David Alan Gilbert * A rare case, we entered listen without having to do any discards,
2105f9527107SDr. David Alan Gilbert * so do the setup that's normally done at the time of the 1st discard.
2106f9527107SDr. David Alan Gilbert */
210758110f0aSVladimir Sementsov-Ogievskiy if (migrate_postcopy_ram()) {
2108f9527107SDr. David Alan Gilbert postcopy_ram_prepare_discard(mis);
2109f9527107SDr. David Alan Gilbert }
211058110f0aSVladimir Sementsov-Ogievskiy }
2111093e3c42SDr. David Alan Gilbert
2112c84f976eSPeter Xu trace_loadvm_postcopy_handle_listen("after discard");
2113c84f976eSPeter Xu
2114f0a227adSDr. David Alan Gilbert /*
2115f0a227adSDr. David Alan Gilbert * Sensitise RAM - can now generate requests for blocks that don't exist
2116f0a227adSDr. David Alan Gilbert * However, at this point the CPU shouldn't be running, and the IO
2117f0a227adSDr. David Alan Gilbert * shouldn't be doing anything yet so don't actually expect requests
2118f0a227adSDr. David Alan Gilbert */
211958110f0aSVladimir Sementsov-Ogievskiy if (migrate_postcopy_ram()) {
21202a7eb148SWei Yang if (postcopy_ram_incoming_setup(mis)) {
212191b02dc7SFei Li postcopy_ram_incoming_cleanup(mis);
2122f0a227adSDr. David Alan Gilbert return -1;
2123f0a227adSDr. David Alan Gilbert }
212458110f0aSVladimir Sementsov-Ogievskiy }
2125f0a227adSDr. David Alan Gilbert
2126c84f976eSPeter Xu trace_loadvm_postcopy_handle_listen("after uffd");
2127c84f976eSPeter Xu
21286864a7b5SDr. David Alan Gilbert if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_LISTEN, &local_err)) {
21296864a7b5SDr. David Alan Gilbert error_report_err(local_err);
21306864a7b5SDr. David Alan Gilbert return -1;
21316864a7b5SDr. David Alan Gilbert }
21326864a7b5SDr. David Alan Gilbert
2133c76201abSDr. David Alan Gilbert mis->have_listen_thread = true;
213460ce4767SPeter Xu postcopy_thread_create(mis, &mis->listen_thread, "mig/dst/listen",
2135095c12a4SPeter Xu postcopy_ram_listen_thread, QEMU_THREAD_DETACHED);
2136c84f976eSPeter Xu trace_loadvm_postcopy_handle_listen("return");
2137c84f976eSPeter Xu
2138093e3c42SDr. David Alan Gilbert return 0;
2139093e3c42SDr. David Alan Gilbert }
2140093e3c42SDr. David Alan Gilbert
loadvm_postcopy_handle_run_bh(void * opaque)2141ea6a55bcSDenis V. Lunev static void loadvm_postcopy_handle_run_bh(void *opaque)
2142093e3c42SDr. David Alan Gilbert {
214327c6825bSDr. David Alan Gilbert Error *local_err = NULL;
21441ce54262SWei Yang MigrationIncomingState *mis = opaque;
2145093e3c42SDr. David Alan Gilbert
21463e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-enter");
2147b9a040b9SPeter Xu
214827c6825bSDr. David Alan Gilbert /* TODO we should move all of this lot into postcopy_ram.c or a shared code
214927c6825bSDr. David Alan Gilbert * in migration.c
215027c6825bSDr. David Alan Gilbert */
215127c6825bSDr. David Alan Gilbert cpu_synchronize_all_post_init();
215227c6825bSDr. David Alan Gilbert
21533e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-cpu-synced");
2154b9a040b9SPeter Xu
21557659505cSDr. David Alan Gilbert qemu_announce_self(&mis->announce_timer, migrate_announce_params());
215627c6825bSDr. David Alan Gilbert
21573e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-announced");
2158b9a040b9SPeter Xu
21593b717194SEmanuele Giuseppe Esposito /* Make sure all file formats throw away their mutable metadata.
2160ace21a58SKevin Wolf * If we get an error here, just don't restart the VM yet. */
21613b717194SEmanuele Giuseppe Esposito bdrv_activate_all(&local_err);
216227c6825bSDr. David Alan Gilbert if (local_err) {
216327c6825bSDr. David Alan Gilbert error_report_err(local_err);
21640042fd36SKevin Wolf local_err = NULL;
21650042fd36SKevin Wolf autostart = false;
21660042fd36SKevin Wolf }
21670042fd36SKevin Wolf
21683e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-cache-invalidated");
216927c6825bSDr. David Alan Gilbert
2170b35ebdf0SVladimir Sementsov-Ogievskiy dirty_bitmap_mig_before_vm_start();
2171b35ebdf0SVladimir Sementsov-Ogievskiy
2172093e3c42SDr. David Alan Gilbert if (autostart) {
2173093e3c42SDr. David Alan Gilbert /* Hold onto your hats, starting the CPU */
2174093e3c42SDr. David Alan Gilbert vm_start();
2175093e3c42SDr. David Alan Gilbert } else {
2176093e3c42SDr. David Alan Gilbert /* leave it paused and let management decide when to start the CPU */
2177093e3c42SDr. David Alan Gilbert runstate_set(RUN_STATE_PAUSED);
2178093e3c42SDr. David Alan Gilbert }
2179093e3c42SDr. David Alan Gilbert
21803e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-vm-started");
2181ea6a55bcSDenis V. Lunev }
2182ea6a55bcSDenis V. Lunev
2183ea6a55bcSDenis V. Lunev /* After all discards we can start running and asking for pages */
loadvm_postcopy_handle_run(MigrationIncomingState * mis)2184ea6a55bcSDenis V. Lunev static int loadvm_postcopy_handle_run(MigrationIncomingState *mis)
2185ea6a55bcSDenis V. Lunev {
21860197d890SWei Yang PostcopyState ps = postcopy_state_get();
2187ea6a55bcSDenis V. Lunev
2188ea6a55bcSDenis V. Lunev trace_loadvm_postcopy_handle_run();
2189ea6a55bcSDenis V. Lunev if (ps != POSTCOPY_INCOMING_LISTENING) {
2190ea6a55bcSDenis V. Lunev error_report("CMD_POSTCOPY_RUN in wrong postcopy state (%d)", ps);
2191ea6a55bcSDenis V. Lunev return -1;
2192ea6a55bcSDenis V. Lunev }
2193ea6a55bcSDenis V. Lunev
21940197d890SWei Yang postcopy_state_set(POSTCOPY_INCOMING_RUNNING);
219544d0d456SFabiano Rosas migration_bh_schedule(loadvm_postcopy_handle_run_bh, mis);
2196ea6a55bcSDenis V. Lunev
219727c6825bSDr. David Alan Gilbert /* We need to finish reading the stream from the package
219827c6825bSDr. David Alan Gilbert * and also stop reading anything more from the stream that loaded the
219927c6825bSDr. David Alan Gilbert * package (since it's now being read by the listener thread).
220027c6825bSDr. David Alan Gilbert * LOADVM_QUIT will quit all the layers of nested loadvm loops.
220127c6825bSDr. David Alan Gilbert */
220227c6825bSDr. David Alan Gilbert return LOADVM_QUIT;
2203093e3c42SDr. David Alan Gilbert }
2204093e3c42SDr. David Alan Gilbert
22050c26781cSPeter Xu /* We must be with page_request_mutex held */
postcopy_sync_page_req(gpointer key,gpointer value,gpointer data)22060c26781cSPeter Xu static gboolean postcopy_sync_page_req(gpointer key, gpointer value,
22070c26781cSPeter Xu gpointer data)
22080c26781cSPeter Xu {
22090c26781cSPeter Xu MigrationIncomingState *mis = data;
22100c26781cSPeter Xu void *host_addr = (void *) key;
22110c26781cSPeter Xu ram_addr_t rb_offset;
22120c26781cSPeter Xu RAMBlock *rb;
22130c26781cSPeter Xu int ret;
22140c26781cSPeter Xu
22150c26781cSPeter Xu rb = qemu_ram_block_from_host(host_addr, true, &rb_offset);
22160c26781cSPeter Xu if (!rb) {
22170c26781cSPeter Xu /*
22180c26781cSPeter Xu * This should _never_ happen. However be nice for a migrating VM to
22190c26781cSPeter Xu * not crash/assert. Post an error (note: intended to not use *_once
22200c26781cSPeter Xu * because we do want to see all the illegal addresses; and this can
22210c26781cSPeter Xu * never be triggered by the guest so we're safe) and move on next.
22220c26781cSPeter Xu */
22230c26781cSPeter Xu error_report("%s: illegal host addr %p", __func__, host_addr);
22240c26781cSPeter Xu /* Try the next entry */
22250c26781cSPeter Xu return FALSE;
22260c26781cSPeter Xu }
22270c26781cSPeter Xu
22280c26781cSPeter Xu ret = migrate_send_rp_message_req_pages(mis, rb, rb_offset);
22290c26781cSPeter Xu if (ret) {
22300c26781cSPeter Xu /* Please refer to above comment. */
22310c26781cSPeter Xu error_report("%s: send rp message failed for addr %p",
22320c26781cSPeter Xu __func__, host_addr);
22330c26781cSPeter Xu return FALSE;
22340c26781cSPeter Xu }
22350c26781cSPeter Xu
22360c26781cSPeter Xu trace_postcopy_page_req_sync(host_addr);
22370c26781cSPeter Xu
22380c26781cSPeter Xu return FALSE;
22390c26781cSPeter Xu }
22400c26781cSPeter Xu
migrate_send_rp_req_pages_pending(MigrationIncomingState * mis)22410c26781cSPeter Xu static void migrate_send_rp_req_pages_pending(MigrationIncomingState *mis)
22420c26781cSPeter Xu {
22430c26781cSPeter Xu WITH_QEMU_LOCK_GUARD(&mis->page_request_mutex) {
22440c26781cSPeter Xu g_tree_foreach(mis->page_requested, postcopy_sync_page_req, mis);
22450c26781cSPeter Xu }
22460c26781cSPeter Xu }
22470c26781cSPeter Xu
loadvm_postcopy_handle_resume(MigrationIncomingState * mis)22483f5875ecSPeter Xu static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
22493f5875ecSPeter Xu {
22503f5875ecSPeter Xu if (mis->state != MIGRATION_STATUS_POSTCOPY_RECOVER) {
22513f5875ecSPeter Xu error_report("%s: illegal resume received", __func__);
22523f5875ecSPeter Xu /* Don't fail the load, only for this. */
22533f5875ecSPeter Xu return 0;
22543f5875ecSPeter Xu }
22553f5875ecSPeter Xu
22563f5875ecSPeter Xu /*
2257cc5ab872SPeter Xu * Reset the last_rb before we resend any page req to source again, since
2258cc5ab872SPeter Xu * the source should have it reset already.
2259cc5ab872SPeter Xu */
2260cc5ab872SPeter Xu mis->last_rb = NULL;
2261cc5ab872SPeter Xu
2262cc5ab872SPeter Xu /*
22633f5875ecSPeter Xu * This means source VM is ready to resume the postcopy migration.
22643f5875ecSPeter Xu */
22653f5875ecSPeter Xu migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_RECOVER,
22663f5875ecSPeter Xu MIGRATION_STATUS_POSTCOPY_ACTIVE);
22673f5875ecSPeter Xu
22683f5875ecSPeter Xu trace_loadvm_postcopy_handle_resume();
22693f5875ecSPeter Xu
227013955b89SPeter Xu /* Tell source that "we are ready" */
227113955b89SPeter Xu migrate_send_rp_resume_ack(mis, MIGRATION_RESUME_ACK_VALUE);
22723f5875ecSPeter Xu
22730c26781cSPeter Xu /*
22740c26781cSPeter Xu * After a postcopy recovery, the source should have lost the postcopy
22750c26781cSPeter Xu * queue, or potentially the requested pages could have been lost during
22760c26781cSPeter Xu * the network down phase. Let's re-sync with the source VM by re-sending
22770c26781cSPeter Xu * all the pending pages that we eagerly need, so these threads won't get
22780c26781cSPeter Xu * blocked too long due to the recovery.
22790c26781cSPeter Xu *
22800c26781cSPeter Xu * Without this procedure, the faulted destination VM threads (waiting for
22810c26781cSPeter Xu * page requests right before the postcopy is interrupted) can keep hanging
22820c26781cSPeter Xu * until the pages are sent by the source during the background copying of
22830c26781cSPeter Xu * pages, or another thread faulted on the same address accidentally.
22840c26781cSPeter Xu */
22850c26781cSPeter Xu migrate_send_rp_req_pages_pending(mis);
22860c26781cSPeter Xu
22875e773431SPeter Xu /*
22885e773431SPeter Xu * It's time to switch state and release the fault thread to continue
22895e773431SPeter Xu * service page faults. Note that this should be explicitly after the
22905e773431SPeter Xu * above call to migrate_send_rp_req_pages_pending(). In short:
22915e773431SPeter Xu * migrate_send_rp_message_req_pages() is not thread safe, yet.
22925e773431SPeter Xu */
22935e773431SPeter Xu qemu_sem_post(&mis->postcopy_pause_sem_fault);
22945e773431SPeter Xu
229560bb3c58SPeter Xu if (migrate_postcopy_preempt()) {
22965655aab0SPeter Xu /*
22975655aab0SPeter Xu * The preempt channel will be created in async manner, now let's
22985655aab0SPeter Xu * wait for it and make sure it's created.
22995655aab0SPeter Xu */
23005655aab0SPeter Xu qemu_sem_wait(&mis->postcopy_qemufile_dst_done);
230160bb3c58SPeter Xu assert(mis->postcopy_qemufile_dst);
230260bb3c58SPeter Xu /* Kick the fast ram load thread too */
230360bb3c58SPeter Xu qemu_sem_post(&mis->postcopy_pause_sem_fast_load);
230460bb3c58SPeter Xu }
230560bb3c58SPeter Xu
23063f5875ecSPeter Xu return 0;
23073f5875ecSPeter Xu }
23083f5875ecSPeter Xu
2309c76ca188SDr. David Alan Gilbert /**
231011cf1d98SDr. David Alan Gilbert * Immediately following this command is a blob of data containing an embedded
231111cf1d98SDr. David Alan Gilbert * chunk of migration stream; read it and load it.
2312c76ca188SDr. David Alan Gilbert *
231311cf1d98SDr. David Alan Gilbert * @mis: Incoming state
231411cf1d98SDr. David Alan Gilbert * @length: Length of packaged data to read
231511cf1d98SDr. David Alan Gilbert *
231611cf1d98SDr. David Alan Gilbert * Returns: Negative values on error
231711cf1d98SDr. David Alan Gilbert *
231811cf1d98SDr. David Alan Gilbert */
loadvm_handle_cmd_packaged(MigrationIncomingState * mis)231911cf1d98SDr. David Alan Gilbert static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
232011cf1d98SDr. David Alan Gilbert {
232111cf1d98SDr. David Alan Gilbert int ret;
232261b67d47SDaniel P. Berrange size_t length;
232361b67d47SDaniel P. Berrange QIOChannelBuffer *bioc;
232411cf1d98SDr. David Alan Gilbert
232511cf1d98SDr. David Alan Gilbert length = qemu_get_be32(mis->from_src_file);
232611cf1d98SDr. David Alan Gilbert trace_loadvm_handle_cmd_packaged(length);
232711cf1d98SDr. David Alan Gilbert
232811cf1d98SDr. David Alan Gilbert if (length > MAX_VM_CMD_PACKAGED_SIZE) {
232961b67d47SDaniel P. Berrange error_report("Unreasonably large packaged state: %zu", length);
233011cf1d98SDr. David Alan Gilbert return -1;
233111cf1d98SDr. David Alan Gilbert }
233261b67d47SDaniel P. Berrange
233361b67d47SDaniel P. Berrange bioc = qio_channel_buffer_new(length);
23346f01f136SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(bioc), "migration-loadvm-buffer");
233561b67d47SDaniel P. Berrange ret = qemu_get_buffer(mis->from_src_file,
233661b67d47SDaniel P. Berrange bioc->data,
233761b67d47SDaniel P. Berrange length);
233811cf1d98SDr. David Alan Gilbert if (ret != length) {
233961b67d47SDaniel P. Berrange object_unref(OBJECT(bioc));
234061b67d47SDaniel P. Berrange error_report("CMD_PACKAGED: Buffer receive fail ret=%d length=%zu",
234111cf1d98SDr. David Alan Gilbert ret, length);
234211cf1d98SDr. David Alan Gilbert return (ret < 0) ? ret : -EAGAIN;
234311cf1d98SDr. David Alan Gilbert }
234461b67d47SDaniel P. Berrange bioc->usage += length;
234511cf1d98SDr. David Alan Gilbert trace_loadvm_handle_cmd_packaged_received(ret);
234611cf1d98SDr. David Alan Gilbert
234777ef2dc1SDaniel P. Berrangé QEMUFile *packf = qemu_file_new_input(QIO_CHANNEL(bioc));
234811cf1d98SDr. David Alan Gilbert
23497afbdadaSWei Wang /*
23507afbdadaSWei Wang * Before loading the guest states, ensure that the preempt channel has
23517afbdadaSWei Wang * been ready to use, as some of the states (e.g. via virtio_load) might
23527afbdadaSWei Wang * trigger page faults that will be handled through the preempt channel.
23537afbdadaSWei Wang * So yield to the main thread in the case that the channel create event
23547afbdadaSWei Wang * hasn't been dispatched.
23557afbdadaSWei Wang *
23567afbdadaSWei Wang * TODO: if we can move migration loadvm out of main thread, then we
23577afbdadaSWei Wang * won't block main thread from polling the accept() fds. We can drop
23587afbdadaSWei Wang * this as a whole when that is done.
23597afbdadaSWei Wang */
23607afbdadaSWei Wang do {
23617afbdadaSWei Wang if (!migrate_postcopy_preempt() || !qemu_in_coroutine() ||
23627afbdadaSWei Wang mis->postcopy_qemufile_dst) {
23637afbdadaSWei Wang break;
23647afbdadaSWei Wang }
23657afbdadaSWei Wang
23667afbdadaSWei Wang aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
23677afbdadaSWei Wang qemu_coroutine_yield();
23687afbdadaSWei Wang } while (1);
23697afbdadaSWei Wang
237011cf1d98SDr. David Alan Gilbert ret = qemu_loadvm_state_main(packf, mis);
237111cf1d98SDr. David Alan Gilbert trace_loadvm_handle_cmd_packaged_main(ret);
237211cf1d98SDr. David Alan Gilbert qemu_fclose(packf);
237361b67d47SDaniel P. Berrange object_unref(OBJECT(bioc));
237411cf1d98SDr. David Alan Gilbert
237511cf1d98SDr. David Alan Gilbert return ret;
237611cf1d98SDr. David Alan Gilbert }
237711cf1d98SDr. David Alan Gilbert
237811cf1d98SDr. David Alan Gilbert /*
2379f25d4225SPeter Xu * Handle request that source requests for recved_bitmap on
2380f25d4225SPeter Xu * destination. Payload format:
2381f25d4225SPeter Xu *
2382f25d4225SPeter Xu * len (1 byte) + ramblock_name (<255 bytes)
2383f25d4225SPeter Xu */
loadvm_handle_recv_bitmap(MigrationIncomingState * mis,uint16_t len)2384f25d4225SPeter Xu static int loadvm_handle_recv_bitmap(MigrationIncomingState *mis,
2385f25d4225SPeter Xu uint16_t len)
2386f25d4225SPeter Xu {
2387f25d4225SPeter Xu QEMUFile *file = mis->from_src_file;
2388f25d4225SPeter Xu RAMBlock *rb;
2389f25d4225SPeter Xu char block_name[256];
2390f25d4225SPeter Xu size_t cnt;
2391f25d4225SPeter Xu
2392f25d4225SPeter Xu cnt = qemu_get_counted_string(file, block_name);
2393f25d4225SPeter Xu if (!cnt) {
2394f25d4225SPeter Xu error_report("%s: failed to read block name", __func__);
2395f25d4225SPeter Xu return -EINVAL;
2396f25d4225SPeter Xu }
2397f25d4225SPeter Xu
2398f25d4225SPeter Xu /* Validate before using the data */
2399f25d4225SPeter Xu if (qemu_file_get_error(file)) {
2400f25d4225SPeter Xu return qemu_file_get_error(file);
2401f25d4225SPeter Xu }
2402f25d4225SPeter Xu
2403f25d4225SPeter Xu if (len != cnt + 1) {
2404f25d4225SPeter Xu error_report("%s: invalid payload length (%d)", __func__, len);
2405f25d4225SPeter Xu return -EINVAL;
2406f25d4225SPeter Xu }
2407f25d4225SPeter Xu
2408f25d4225SPeter Xu rb = qemu_ram_block_by_name(block_name);
2409f25d4225SPeter Xu if (!rb) {
2410f25d4225SPeter Xu error_report("%s: block '%s' not found", __func__, block_name);
2411f25d4225SPeter Xu return -EINVAL;
2412f25d4225SPeter Xu }
2413f25d4225SPeter Xu
2414a335debbSPeter Xu migrate_send_rp_recv_bitmap(mis, block_name);
2415f25d4225SPeter Xu
2416f25d4225SPeter Xu trace_loadvm_handle_recv_bitmap(block_name);
2417f25d4225SPeter Xu
2418f25d4225SPeter Xu return 0;
2419f25d4225SPeter Xu }
2420f25d4225SPeter Xu
loadvm_process_enable_colo(MigrationIncomingState * mis)2421aad555c2SZhang Chen static int loadvm_process_enable_colo(MigrationIncomingState *mis)
2422aad555c2SZhang Chen {
242318b1d3c9SDavid Hildenbrand int ret = migration_incoming_enable_colo();
242418b1d3c9SDavid Hildenbrand
242518b1d3c9SDavid Hildenbrand if (!ret) {
242618b1d3c9SDavid Hildenbrand ret = colo_init_ram_cache();
242718b1d3c9SDavid Hildenbrand if (ret) {
242818b1d3c9SDavid Hildenbrand migration_incoming_disable_colo();
242918b1d3c9SDavid Hildenbrand }
243018b1d3c9SDavid Hildenbrand }
243118b1d3c9SDavid Hildenbrand return ret;
2432aad555c2SZhang Chen }
2433aad555c2SZhang Chen
2434f25d4225SPeter Xu /*
243511cf1d98SDr. David Alan Gilbert * Process an incoming 'QEMU_VM_COMMAND'
243611cf1d98SDr. David Alan Gilbert * 0 just a normal return
24377b89bf27SDr. David Alan Gilbert * LOADVM_QUIT All good, but exit the loop
243811cf1d98SDr. David Alan Gilbert * <0 Error
2439c76ca188SDr. David Alan Gilbert */
loadvm_process_command(QEMUFile * f)2440c76ca188SDr. David Alan Gilbert static int loadvm_process_command(QEMUFile *f)
2441c76ca188SDr. David Alan Gilbert {
24422e37701eSDr. David Alan Gilbert MigrationIncomingState *mis = migration_incoming_get_current();
2443c76ca188SDr. David Alan Gilbert uint16_t cmd;
2444c76ca188SDr. David Alan Gilbert uint16_t len;
24452e37701eSDr. David Alan Gilbert uint32_t tmp32;
2446c76ca188SDr. David Alan Gilbert
2447c76ca188SDr. David Alan Gilbert cmd = qemu_get_be16(f);
2448c76ca188SDr. David Alan Gilbert len = qemu_get_be16(f);
2449c76ca188SDr. David Alan Gilbert
24507a9ddfbfSPeter Xu /* Check validity before continue processing of cmds */
24517a9ddfbfSPeter Xu if (qemu_file_get_error(f)) {
24527a9ddfbfSPeter Xu return qemu_file_get_error(f);
24537a9ddfbfSPeter Xu }
24547a9ddfbfSPeter Xu
2455c76ca188SDr. David Alan Gilbert if (cmd >= MIG_CMD_MAX || cmd == MIG_CMD_INVALID) {
2456c76ca188SDr. David Alan Gilbert error_report("MIG_CMD 0x%x unknown (len 0x%x)", cmd, len);
2457c76ca188SDr. David Alan Gilbert return -EINVAL;
2458c76ca188SDr. David Alan Gilbert }
2459c76ca188SDr. David Alan Gilbert
2460a7060ba3SPeter Xu trace_loadvm_process_command(mig_cmd_args[cmd].name, len);
2461a7060ba3SPeter Xu
2462c76ca188SDr. David Alan Gilbert if (mig_cmd_args[cmd].len != -1 && mig_cmd_args[cmd].len != len) {
2463c76ca188SDr. David Alan Gilbert error_report("%s received with bad length - expecting %zu, got %d",
2464c76ca188SDr. David Alan Gilbert mig_cmd_args[cmd].name,
2465c76ca188SDr. David Alan Gilbert (size_t)mig_cmd_args[cmd].len, len);
2466c76ca188SDr. David Alan Gilbert return -ERANGE;
2467c76ca188SDr. David Alan Gilbert }
2468c76ca188SDr. David Alan Gilbert
2469c76ca188SDr. David Alan Gilbert switch (cmd) {
24702e37701eSDr. David Alan Gilbert case MIG_CMD_OPEN_RETURN_PATH:
24712e37701eSDr. David Alan Gilbert if (mis->to_src_file) {
24722e37701eSDr. David Alan Gilbert error_report("CMD_OPEN_RETURN_PATH called when RP already open");
24732e37701eSDr. David Alan Gilbert /* Not really a problem, so don't give up */
24742e37701eSDr. David Alan Gilbert return 0;
24752e37701eSDr. David Alan Gilbert }
24762e37701eSDr. David Alan Gilbert mis->to_src_file = qemu_file_get_return_path(f);
24772e37701eSDr. David Alan Gilbert if (!mis->to_src_file) {
24782e37701eSDr. David Alan Gilbert error_report("CMD_OPEN_RETURN_PATH failed");
24792e37701eSDr. David Alan Gilbert return -1;
24802e37701eSDr. David Alan Gilbert }
24811b4adb10SAvihai Horon
24821b4adb10SAvihai Horon /*
24831b4adb10SAvihai Horon * Switchover ack is enabled but no device uses it, so send an ACK to
24841b4adb10SAvihai Horon * source that it's OK to switchover. Do it here, after return path has
24851b4adb10SAvihai Horon * been created.
24861b4adb10SAvihai Horon */
24871b4adb10SAvihai Horon if (migrate_switchover_ack() && !mis->switchover_ack_pending_num) {
24881b4adb10SAvihai Horon int ret = migrate_send_rp_switchover_ack(mis);
24891b4adb10SAvihai Horon if (ret) {
24901b4adb10SAvihai Horon error_report(
24911b4adb10SAvihai Horon "Could not send switchover ack RP MSG, err %d (%s)", ret,
24921b4adb10SAvihai Horon strerror(-ret));
24931b4adb10SAvihai Horon return ret;
24941b4adb10SAvihai Horon }
24951b4adb10SAvihai Horon }
24962e37701eSDr. David Alan Gilbert break;
24972e37701eSDr. David Alan Gilbert
24982e37701eSDr. David Alan Gilbert case MIG_CMD_PING:
24992e37701eSDr. David Alan Gilbert tmp32 = qemu_get_be32(f);
25002e37701eSDr. David Alan Gilbert trace_loadvm_process_command_ping(tmp32);
25012e37701eSDr. David Alan Gilbert if (!mis->to_src_file) {
25022e37701eSDr. David Alan Gilbert error_report("CMD_PING (0x%x) received with no return path",
25032e37701eSDr. David Alan Gilbert tmp32);
25042e37701eSDr. David Alan Gilbert return -1;
25052e37701eSDr. David Alan Gilbert }
25066decec93SDr. David Alan Gilbert migrate_send_rp_pong(mis, tmp32);
25072e37701eSDr. David Alan Gilbert break;
2508093e3c42SDr. David Alan Gilbert
250911cf1d98SDr. David Alan Gilbert case MIG_CMD_PACKAGED:
251011cf1d98SDr. David Alan Gilbert return loadvm_handle_cmd_packaged(mis);
251111cf1d98SDr. David Alan Gilbert
2512093e3c42SDr. David Alan Gilbert case MIG_CMD_POSTCOPY_ADVISE:
2513875fcd01SGreg Kurz return loadvm_postcopy_handle_advise(mis, len);
2514093e3c42SDr. David Alan Gilbert
2515093e3c42SDr. David Alan Gilbert case MIG_CMD_POSTCOPY_LISTEN:
2516093e3c42SDr. David Alan Gilbert return loadvm_postcopy_handle_listen(mis);
2517093e3c42SDr. David Alan Gilbert
2518093e3c42SDr. David Alan Gilbert case MIG_CMD_POSTCOPY_RUN:
2519093e3c42SDr. David Alan Gilbert return loadvm_postcopy_handle_run(mis);
2520093e3c42SDr. David Alan Gilbert
2521093e3c42SDr. David Alan Gilbert case MIG_CMD_POSTCOPY_RAM_DISCARD:
2522093e3c42SDr. David Alan Gilbert return loadvm_postcopy_ram_handle_discard(mis, len);
2523f25d4225SPeter Xu
25243f5875ecSPeter Xu case MIG_CMD_POSTCOPY_RESUME:
25253f5875ecSPeter Xu return loadvm_postcopy_handle_resume(mis);
25263f5875ecSPeter Xu
2527f25d4225SPeter Xu case MIG_CMD_RECV_BITMAP:
2528f25d4225SPeter Xu return loadvm_handle_recv_bitmap(mis, len);
2529aad555c2SZhang Chen
2530aad555c2SZhang Chen case MIG_CMD_ENABLE_COLO:
2531aad555c2SZhang Chen return loadvm_process_enable_colo(mis);
2532c76ca188SDr. David Alan Gilbert }
2533c76ca188SDr. David Alan Gilbert
2534c76ca188SDr. David Alan Gilbert return 0;
2535c76ca188SDr. David Alan Gilbert }
2536c76ca188SDr. David Alan Gilbert
253759f39a47SDr. David Alan Gilbert /*
253859f39a47SDr. David Alan Gilbert * Read a footer off the wire and check that it matches the expected section
253959f39a47SDr. David Alan Gilbert *
254059f39a47SDr. David Alan Gilbert * Returns: true if the footer was good
254159f39a47SDr. David Alan Gilbert * false if there is a problem (and calls error_report to say why)
254259f39a47SDr. David Alan Gilbert */
check_section_footer(QEMUFile * f,SaveStateEntry * se)25430f42f657SJuan Quintela static bool check_section_footer(QEMUFile *f, SaveStateEntry *se)
254459f39a47SDr. David Alan Gilbert {
25457a9ddfbfSPeter Xu int ret;
254659f39a47SDr. David Alan Gilbert uint8_t read_mark;
254759f39a47SDr. David Alan Gilbert uint32_t read_section_id;
254859f39a47SDr. David Alan Gilbert
254915c38503SPeter Xu if (!migrate_get_current()->send_section_footer) {
255059f39a47SDr. David Alan Gilbert /* No footer to check */
255159f39a47SDr. David Alan Gilbert return true;
255259f39a47SDr. David Alan Gilbert }
255359f39a47SDr. David Alan Gilbert
255459f39a47SDr. David Alan Gilbert read_mark = qemu_get_byte(f);
255559f39a47SDr. David Alan Gilbert
25567a9ddfbfSPeter Xu ret = qemu_file_get_error(f);
25577a9ddfbfSPeter Xu if (ret) {
25587a9ddfbfSPeter Xu error_report("%s: Read section footer failed: %d",
25597a9ddfbfSPeter Xu __func__, ret);
25607a9ddfbfSPeter Xu return false;
25617a9ddfbfSPeter Xu }
25627a9ddfbfSPeter Xu
256359f39a47SDr. David Alan Gilbert if (read_mark != QEMU_VM_SECTION_FOOTER) {
25640f42f657SJuan Quintela error_report("Missing section footer for %s", se->idstr);
256559f39a47SDr. David Alan Gilbert return false;
256659f39a47SDr. David Alan Gilbert }
256759f39a47SDr. David Alan Gilbert
256859f39a47SDr. David Alan Gilbert read_section_id = qemu_get_be32(f);
25690f42f657SJuan Quintela if (read_section_id != se->load_section_id) {
257059f39a47SDr. David Alan Gilbert error_report("Mismatched section id in footer for %s -"
257159f39a47SDr. David Alan Gilbert " read 0x%x expected 0x%x",
25720f42f657SJuan Quintela se->idstr, read_section_id, se->load_section_id);
257359f39a47SDr. David Alan Gilbert return false;
257459f39a47SDr. David Alan Gilbert }
257559f39a47SDr. David Alan Gilbert
257659f39a47SDr. David Alan Gilbert /* All good */
257759f39a47SDr. David Alan Gilbert return true;
257859f39a47SDr. David Alan Gilbert }
257959f39a47SDr. David Alan Gilbert
2580fb3520a8Szhanghailiang static int
qemu_loadvm_section_start_full(QEMUFile * f,MigrationIncomingState * mis,uint8_t type)25813c80f142SPeter Xu qemu_loadvm_section_start_full(QEMUFile *f, MigrationIncomingState *mis,
25823c80f142SPeter Xu uint8_t type)
25837b89bf27SDr. David Alan Gilbert {
25843c80f142SPeter Xu bool trace_downtime = (type == QEMU_VM_SECTION_FULL);
25857b89bf27SDr. David Alan Gilbert uint32_t instance_id, version_id, section_id;
25863c80f142SPeter Xu int64_t start_ts, end_ts;
25877b89bf27SDr. David Alan Gilbert SaveStateEntry *se;
25887b89bf27SDr. David Alan Gilbert char idstr[256];
2589fb3520a8Szhanghailiang int ret;
25907b89bf27SDr. David Alan Gilbert
25917b89bf27SDr. David Alan Gilbert /* Read section start */
25927b89bf27SDr. David Alan Gilbert section_id = qemu_get_be32(f);
25937b89bf27SDr. David Alan Gilbert if (!qemu_get_counted_string(f, idstr)) {
25947b89bf27SDr. David Alan Gilbert error_report("Unable to read ID string for section %u",
25957b89bf27SDr. David Alan Gilbert section_id);
25967b89bf27SDr. David Alan Gilbert return -EINVAL;
25977b89bf27SDr. David Alan Gilbert }
25987b89bf27SDr. David Alan Gilbert instance_id = qemu_get_be32(f);
25997b89bf27SDr. David Alan Gilbert version_id = qemu_get_be32(f);
26007b89bf27SDr. David Alan Gilbert
26017a9ddfbfSPeter Xu ret = qemu_file_get_error(f);
26027a9ddfbfSPeter Xu if (ret) {
26037a9ddfbfSPeter Xu error_report("%s: Failed to read instance/version ID: %d",
26047a9ddfbfSPeter Xu __func__, ret);
26057a9ddfbfSPeter Xu return ret;
26067a9ddfbfSPeter Xu }
26077a9ddfbfSPeter Xu
26087b89bf27SDr. David Alan Gilbert trace_qemu_loadvm_state_section_startfull(section_id, idstr,
26097b89bf27SDr. David Alan Gilbert instance_id, version_id);
26107b89bf27SDr. David Alan Gilbert /* Find savevm section */
26117b89bf27SDr. David Alan Gilbert se = find_se(idstr, instance_id);
26127b89bf27SDr. David Alan Gilbert if (se == NULL) {
261393062e23SPeter Xu error_report("Unknown savevm section or instance '%s' %"PRIu32". "
2614827beacbSJose Ricardo Ziviani "Make sure that your current VM setup matches your "
2615827beacbSJose Ricardo Ziviani "saved VM setup, including any hotplugged devices",
26167b89bf27SDr. David Alan Gilbert idstr, instance_id);
26177b89bf27SDr. David Alan Gilbert return -EINVAL;
26187b89bf27SDr. David Alan Gilbert }
26197b89bf27SDr. David Alan Gilbert
26207b89bf27SDr. David Alan Gilbert /* Validate version */
26217b89bf27SDr. David Alan Gilbert if (version_id > se->version_id) {
26227b89bf27SDr. David Alan Gilbert error_report("savevm: unsupported version %d for '%s' v%d",
26237b89bf27SDr. David Alan Gilbert version_id, idstr, se->version_id);
26247b89bf27SDr. David Alan Gilbert return -EINVAL;
26257b89bf27SDr. David Alan Gilbert }
26260f42f657SJuan Quintela se->load_version_id = version_id;
26270f42f657SJuan Quintela se->load_section_id = section_id;
26287b89bf27SDr. David Alan Gilbert
262988c16567SWen Congyang /* Validate if it is a device's state */
263088c16567SWen Congyang if (xen_enabled() && se->is_ram) {
263188c16567SWen Congyang error_report("loadvm: %s RAM loading not allowed on Xen", idstr);
263288c16567SWen Congyang return -EINVAL;
263388c16567SWen Congyang }
263488c16567SWen Congyang
26353c80f142SPeter Xu if (trace_downtime) {
26363c80f142SPeter Xu start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
26373c80f142SPeter Xu }
26383c80f142SPeter Xu
26393a011c26SJuan Quintela ret = vmstate_load(f, se);
26407b89bf27SDr. David Alan Gilbert if (ret < 0) {
264193062e23SPeter Xu error_report("error while loading state for instance 0x%"PRIx32" of"
26427b89bf27SDr. David Alan Gilbert " device '%s'", instance_id, idstr);
26437b89bf27SDr. David Alan Gilbert return ret;
26447b89bf27SDr. David Alan Gilbert }
26453c80f142SPeter Xu
26463c80f142SPeter Xu if (trace_downtime) {
26473c80f142SPeter Xu end_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
26483c80f142SPeter Xu trace_vmstate_downtime_load("non-iterable", se->idstr,
26493c80f142SPeter Xu se->instance_id, end_ts - start_ts);
26503c80f142SPeter Xu }
26513c80f142SPeter Xu
26520f42f657SJuan Quintela if (!check_section_footer(f, se)) {
26537b89bf27SDr. David Alan Gilbert return -EINVAL;
26547b89bf27SDr. David Alan Gilbert }
2655fb3520a8Szhanghailiang
2656fb3520a8Szhanghailiang return 0;
2657fb3520a8Szhanghailiang }
2658fb3520a8Szhanghailiang
2659fb3520a8Szhanghailiang static int
qemu_loadvm_section_part_end(QEMUFile * f,MigrationIncomingState * mis,uint8_t type)26603c80f142SPeter Xu qemu_loadvm_section_part_end(QEMUFile *f, MigrationIncomingState *mis,
26613c80f142SPeter Xu uint8_t type)
2662fb3520a8Szhanghailiang {
26633c80f142SPeter Xu bool trace_downtime = (type == QEMU_VM_SECTION_END);
26643c80f142SPeter Xu int64_t start_ts, end_ts;
2665fb3520a8Szhanghailiang uint32_t section_id;
26660f42f657SJuan Quintela SaveStateEntry *se;
2667fb3520a8Szhanghailiang int ret;
2668fb3520a8Szhanghailiang
26697b89bf27SDr. David Alan Gilbert section_id = qemu_get_be32(f);
26707b89bf27SDr. David Alan Gilbert
26717a9ddfbfSPeter Xu ret = qemu_file_get_error(f);
26727a9ddfbfSPeter Xu if (ret) {
26737a9ddfbfSPeter Xu error_report("%s: Failed to read section ID: %d",
26747a9ddfbfSPeter Xu __func__, ret);
26757a9ddfbfSPeter Xu return ret;
26767a9ddfbfSPeter Xu }
26777a9ddfbfSPeter Xu
26787b89bf27SDr. David Alan Gilbert trace_qemu_loadvm_state_section_partend(section_id);
26790f42f657SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
26800f42f657SJuan Quintela if (se->load_section_id == section_id) {
26817b89bf27SDr. David Alan Gilbert break;
26827b89bf27SDr. David Alan Gilbert }
26837b89bf27SDr. David Alan Gilbert }
26840f42f657SJuan Quintela if (se == NULL) {
26857b89bf27SDr. David Alan Gilbert error_report("Unknown savevm section %d", section_id);
26867b89bf27SDr. David Alan Gilbert return -EINVAL;
26877b89bf27SDr. David Alan Gilbert }
26887b89bf27SDr. David Alan Gilbert
26893c80f142SPeter Xu if (trace_downtime) {
26903c80f142SPeter Xu start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
26913c80f142SPeter Xu }
26923c80f142SPeter Xu
26933a011c26SJuan Quintela ret = vmstate_load(f, se);
26947b89bf27SDr. David Alan Gilbert if (ret < 0) {
26957b89bf27SDr. David Alan Gilbert error_report("error while loading state section id %d(%s)",
26960f42f657SJuan Quintela section_id, se->idstr);
26977b89bf27SDr. David Alan Gilbert return ret;
26987b89bf27SDr. David Alan Gilbert }
26993c80f142SPeter Xu
27003c80f142SPeter Xu if (trace_downtime) {
27013c80f142SPeter Xu end_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
27023c80f142SPeter Xu trace_vmstate_downtime_load("iterable", se->idstr,
27033c80f142SPeter Xu se->instance_id, end_ts - start_ts);
27043c80f142SPeter Xu }
27053c80f142SPeter Xu
27060f42f657SJuan Quintela if (!check_section_footer(f, se)) {
27077b89bf27SDr. David Alan Gilbert return -EINVAL;
27087b89bf27SDr. David Alan Gilbert }
2709fb3520a8Szhanghailiang
2710fb3520a8Szhanghailiang return 0;
2711fb3520a8Szhanghailiang }
2712fb3520a8Szhanghailiang
qemu_loadvm_state_header(QEMUFile * f)271316015d32SWei Yang static int qemu_loadvm_state_header(QEMUFile *f)
271416015d32SWei Yang {
271516015d32SWei Yang unsigned int v;
271616015d32SWei Yang int ret;
271716015d32SWei Yang
271816015d32SWei Yang v = qemu_get_be32(f);
271916015d32SWei Yang if (v != QEMU_VM_FILE_MAGIC) {
272016015d32SWei Yang error_report("Not a migration stream");
272116015d32SWei Yang return -EINVAL;
272216015d32SWei Yang }
272316015d32SWei Yang
272416015d32SWei Yang v = qemu_get_be32(f);
272516015d32SWei Yang if (v == QEMU_VM_FILE_VERSION_COMPAT) {
272616015d32SWei Yang error_report("SaveVM v2 format is obsolete and don't work anymore");
272716015d32SWei Yang return -ENOTSUP;
272816015d32SWei Yang }
272916015d32SWei Yang if (v != QEMU_VM_FILE_VERSION) {
273016015d32SWei Yang error_report("Unsupported migration stream version");
273116015d32SWei Yang return -ENOTSUP;
273216015d32SWei Yang }
273316015d32SWei Yang
273416015d32SWei Yang if (migrate_get_current()->send_configuration) {
273516015d32SWei Yang if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) {
273616015d32SWei Yang error_report("Configuration section missing");
273716015d32SWei Yang qemu_loadvm_state_cleanup();
273816015d32SWei Yang return -EINVAL;
273916015d32SWei Yang }
274016015d32SWei Yang ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0);
274116015d32SWei Yang
274216015d32SWei Yang if (ret) {
274316015d32SWei Yang qemu_loadvm_state_cleanup();
274416015d32SWei Yang return ret;
274516015d32SWei Yang }
274616015d32SWei Yang }
274716015d32SWei Yang return 0;
274816015d32SWei Yang }
274916015d32SWei Yang
qemu_loadvm_state_switchover_ack_needed(MigrationIncomingState * mis)27501b4adb10SAvihai Horon static void qemu_loadvm_state_switchover_ack_needed(MigrationIncomingState *mis)
27511b4adb10SAvihai Horon {
27521b4adb10SAvihai Horon SaveStateEntry *se;
27531b4adb10SAvihai Horon
27541b4adb10SAvihai Horon QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
27551b4adb10SAvihai Horon if (!se->ops || !se->ops->switchover_ack_needed) {
27561b4adb10SAvihai Horon continue;
27571b4adb10SAvihai Horon }
27581b4adb10SAvihai Horon
27591b4adb10SAvihai Horon if (se->ops->switchover_ack_needed(se->opaque)) {
27601b4adb10SAvihai Horon mis->switchover_ack_pending_num++;
27611b4adb10SAvihai Horon }
27621b4adb10SAvihai Horon }
27631b4adb10SAvihai Horon
27641b4adb10SAvihai Horon trace_loadvm_state_switchover_ack_needed(mis->switchover_ack_pending_num);
27651b4adb10SAvihai Horon }
27661b4adb10SAvihai Horon
qemu_loadvm_state_setup(QEMUFile * f,Error ** errp)2767e4fa064dSCédric Le Goater static int qemu_loadvm_state_setup(QEMUFile *f, Error **errp)
2768acb5ea86SJuan Quintela {
2769e4fa064dSCédric Le Goater ERRP_GUARD();
2770acb5ea86SJuan Quintela SaveStateEntry *se;
2771acb5ea86SJuan Quintela int ret;
2772acb5ea86SJuan Quintela
2773acb5ea86SJuan Quintela trace_loadvm_state_setup();
2774acb5ea86SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
2775acb5ea86SJuan Quintela if (!se->ops || !se->ops->load_setup) {
2776acb5ea86SJuan Quintela continue;
2777acb5ea86SJuan Quintela }
2778cea3b4c0SWei Yang if (se->ops->is_active) {
2779acb5ea86SJuan Quintela if (!se->ops->is_active(se->opaque)) {
2780acb5ea86SJuan Quintela continue;
2781acb5ea86SJuan Quintela }
2782acb5ea86SJuan Quintela }
2783acb5ea86SJuan Quintela
2784e4fa064dSCédric Le Goater ret = se->ops->load_setup(f, se->opaque, errp);
2785acb5ea86SJuan Quintela if (ret < 0) {
2786e4fa064dSCédric Le Goater error_prepend(errp, "Load state of device %s failed: ",
2787e4fa064dSCédric Le Goater se->idstr);
2788acb5ea86SJuan Quintela qemu_file_set_error(f, ret);
2789acb5ea86SJuan Quintela return ret;
2790acb5ea86SJuan Quintela }
2791acb5ea86SJuan Quintela }
2792acb5ea86SJuan Quintela return 0;
2793acb5ea86SJuan Quintela }
2794acb5ea86SJuan Quintela
qemu_loadvm_state_cleanup(void)2795acb5ea86SJuan Quintela void qemu_loadvm_state_cleanup(void)
2796acb5ea86SJuan Quintela {
2797acb5ea86SJuan Quintela SaveStateEntry *se;
2798acb5ea86SJuan Quintela
2799acb5ea86SJuan Quintela trace_loadvm_state_cleanup();
2800acb5ea86SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
2801acb5ea86SJuan Quintela if (se->ops && se->ops->load_cleanup) {
2802acb5ea86SJuan Quintela se->ops->load_cleanup(se->opaque);
2803acb5ea86SJuan Quintela }
2804acb5ea86SJuan Quintela }
2805acb5ea86SJuan Quintela }
2806acb5ea86SJuan Quintela
2807b411b844SPeter Xu /* Return true if we should continue the migration, or false. */
postcopy_pause_incoming(MigrationIncomingState * mis)2808b411b844SPeter Xu static bool postcopy_pause_incoming(MigrationIncomingState *mis)
2809b411b844SPeter Xu {
281077dadc3fSPeter Xu int i;
281177dadc3fSPeter Xu
2812b411b844SPeter Xu trace_postcopy_pause_incoming();
2813b411b844SPeter Xu
2814ee647225SVladimir Sementsov-Ogievskiy assert(migrate_postcopy_ram());
2815ee647225SVladimir Sementsov-Ogievskiy
281639675fffSPeter Xu /*
281739675fffSPeter Xu * Unregister yank with either from/to src would work, since ioc behind it
281839675fffSPeter Xu * is the same
281939675fffSPeter Xu */
282039675fffSPeter Xu migration_ioc_unregister_yank_from_file(mis->from_src_file);
282139675fffSPeter Xu
2822b411b844SPeter Xu assert(mis->from_src_file);
2823b411b844SPeter Xu qemu_file_shutdown(mis->from_src_file);
2824b411b844SPeter Xu qemu_fclose(mis->from_src_file);
2825b411b844SPeter Xu mis->from_src_file = NULL;
2826b411b844SPeter Xu
2827b411b844SPeter Xu assert(mis->to_src_file);
2828b411b844SPeter Xu qemu_file_shutdown(mis->to_src_file);
2829b411b844SPeter Xu qemu_mutex_lock(&mis->rp_mutex);
2830b411b844SPeter Xu qemu_fclose(mis->to_src_file);
2831b411b844SPeter Xu mis->to_src_file = NULL;
2832b411b844SPeter Xu qemu_mutex_unlock(&mis->rp_mutex);
2833b411b844SPeter Xu
283460bb3c58SPeter Xu /*
283560bb3c58SPeter Xu * NOTE: this must happen before reset the PostcopyTmpPages below,
283660bb3c58SPeter Xu * otherwise it's racy to reset those fields when the fast load thread
283760bb3c58SPeter Xu * can be accessing it in parallel.
283860bb3c58SPeter Xu */
283960bb3c58SPeter Xu if (mis->postcopy_qemufile_dst) {
284060bb3c58SPeter Xu qemu_file_shutdown(mis->postcopy_qemufile_dst);
284160bb3c58SPeter Xu /* Take the mutex to make sure the fast ram load thread halted */
284260bb3c58SPeter Xu qemu_mutex_lock(&mis->postcopy_prio_thread_mutex);
284360bb3c58SPeter Xu migration_ioc_unregister_yank_from_file(mis->postcopy_qemufile_dst);
284460bb3c58SPeter Xu qemu_fclose(mis->postcopy_qemufile_dst);
284560bb3c58SPeter Xu mis->postcopy_qemufile_dst = NULL;
284660bb3c58SPeter Xu qemu_mutex_unlock(&mis->postcopy_prio_thread_mutex);
284760bb3c58SPeter Xu }
284860bb3c58SPeter Xu
28490e99bb8fSPeter Xu /* Current state can be either ACTIVE or RECOVER */
28500e99bb8fSPeter Xu migrate_set_state(&mis->state, mis->state,
2851eed1cc78SPeter Xu MIGRATION_STATUS_POSTCOPY_PAUSED);
2852eed1cc78SPeter Xu
28533a7804c3SPeter Xu /* Notify the fault thread for the invalidated file handle */
28543a7804c3SPeter Xu postcopy_fault_thread_notify(mis);
28553a7804c3SPeter Xu
285636f62f11SPeter Xu /*
285736f62f11SPeter Xu * If network is interrupted, any temp page we received will be useless
285836f62f11SPeter Xu * because we didn't mark them as "received" in receivedmap. After a
285936f62f11SPeter Xu * proper recovery later (which will sync src dirty bitmap with receivedmap
286036f62f11SPeter Xu * on dest) these cached small pages will be resent again.
286136f62f11SPeter Xu */
286236f62f11SPeter Xu for (i = 0; i < mis->postcopy_channels; i++) {
286336f62f11SPeter Xu postcopy_temp_page_reset(&mis->postcopy_tmp_pages[i]);
286436f62f11SPeter Xu }
286536f62f11SPeter Xu
2866b411b844SPeter Xu error_report("Detected IO failure for postcopy. "
2867b411b844SPeter Xu "Migration paused.");
2868b411b844SPeter Xu
28694146b77eSPeter Xu do {
2870b411b844SPeter Xu qemu_sem_wait(&mis->postcopy_pause_sem_dst);
28714146b77eSPeter Xu } while (postcopy_is_paused(mis->state));
2872b411b844SPeter Xu
2873b411b844SPeter Xu trace_postcopy_pause_incoming_continued();
2874b411b844SPeter Xu
2875b411b844SPeter Xu return true;
2876b411b844SPeter Xu }
2877b411b844SPeter Xu
qemu_loadvm_state_main(QEMUFile * f,MigrationIncomingState * mis)28783f6df99dSZhang Chen int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis)
2879fb3520a8Szhanghailiang {
2880fb3520a8Szhanghailiang uint8_t section_type;
2881ccb783c3SDr. David Alan Gilbert int ret = 0;
2882fb3520a8Szhanghailiang
2883b411b844SPeter Xu retry:
28847a9ddfbfSPeter Xu while (true) {
28857a9ddfbfSPeter Xu section_type = qemu_get_byte(f);
28867a9ddfbfSPeter Xu
288760bb3c58SPeter Xu ret = qemu_file_get_error_obj_any(f, mis->postcopy_qemufile_dst, NULL);
288860bb3c58SPeter Xu if (ret) {
28897a9ddfbfSPeter Xu break;
28907a9ddfbfSPeter Xu }
28917a9ddfbfSPeter Xu
2892fb3520a8Szhanghailiang trace_qemu_loadvm_state_section(section_type);
2893fb3520a8Szhanghailiang switch (section_type) {
2894fb3520a8Szhanghailiang case QEMU_VM_SECTION_START:
2895fb3520a8Szhanghailiang case QEMU_VM_SECTION_FULL:
28963c80f142SPeter Xu ret = qemu_loadvm_section_start_full(f, mis, section_type);
2897fb3520a8Szhanghailiang if (ret < 0) {
2898ccb783c3SDr. David Alan Gilbert goto out;
2899fb3520a8Szhanghailiang }
2900fb3520a8Szhanghailiang break;
2901fb3520a8Szhanghailiang case QEMU_VM_SECTION_PART:
2902fb3520a8Szhanghailiang case QEMU_VM_SECTION_END:
29033c80f142SPeter Xu ret = qemu_loadvm_section_part_end(f, mis, section_type);
2904fb3520a8Szhanghailiang if (ret < 0) {
2905ccb783c3SDr. David Alan Gilbert goto out;
2906fb3520a8Szhanghailiang }
29077b89bf27SDr. David Alan Gilbert break;
29087b89bf27SDr. David Alan Gilbert case QEMU_VM_COMMAND:
29097b89bf27SDr. David Alan Gilbert ret = loadvm_process_command(f);
29107b89bf27SDr. David Alan Gilbert trace_qemu_loadvm_state_section_command(ret);
29114695ce3fSWei Yang if ((ret < 0) || (ret == LOADVM_QUIT)) {
2912ccb783c3SDr. David Alan Gilbert goto out;
29137b89bf27SDr. David Alan Gilbert }
29147b89bf27SDr. David Alan Gilbert break;
29157a9ddfbfSPeter Xu case QEMU_VM_EOF:
29167a9ddfbfSPeter Xu /* This is the end of migration */
29177a9ddfbfSPeter Xu goto out;
29187b89bf27SDr. David Alan Gilbert default:
29197b89bf27SDr. David Alan Gilbert error_report("Unknown savevm section type %d", section_type);
2920ccb783c3SDr. David Alan Gilbert ret = -EINVAL;
2921ccb783c3SDr. David Alan Gilbert goto out;
29227b89bf27SDr. David Alan Gilbert }
29237b89bf27SDr. David Alan Gilbert }
29247b89bf27SDr. David Alan Gilbert
2925ccb783c3SDr. David Alan Gilbert out:
2926ccb783c3SDr. David Alan Gilbert if (ret < 0) {
2927ccb783c3SDr. David Alan Gilbert qemu_file_set_error(f, ret);
2928b411b844SPeter Xu
2929ee647225SVladimir Sementsov-Ogievskiy /* Cancel bitmaps incoming regardless of recovery */
2930ee647225SVladimir Sementsov-Ogievskiy dirty_bitmap_mig_cancel_incoming();
2931ee647225SVladimir Sementsov-Ogievskiy
2932b411b844SPeter Xu /*
2933fd037a65SPeter Xu * If we are during an active postcopy, then we pause instead
2934fd037a65SPeter Xu * of bail out to at least keep the VM's dirty data. Note
2935fd037a65SPeter Xu * that POSTCOPY_INCOMING_LISTENING stage is still not enough,
2936fd037a65SPeter Xu * during which we're still receiving device states and we
2937fd037a65SPeter Xu * still haven't yet started the VM on destination.
2938ee647225SVladimir Sementsov-Ogievskiy *
2939ee647225SVladimir Sementsov-Ogievskiy * Only RAM postcopy supports recovery. Still, if RAM postcopy is
2940ee647225SVladimir Sementsov-Ogievskiy * enabled, canceled bitmaps postcopy will not affect RAM postcopy
2941ee647225SVladimir Sementsov-Ogievskiy * recovering.
2942b411b844SPeter Xu */
2943b411b844SPeter Xu if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING &&
2944ee647225SVladimir Sementsov-Ogievskiy migrate_postcopy_ram() && postcopy_pause_incoming(mis)) {
2945b411b844SPeter Xu /* Reset f to point to the newly created channel */
2946b411b844SPeter Xu f = mis->from_src_file;
2947b411b844SPeter Xu goto retry;
2948b411b844SPeter Xu }
2949ccb783c3SDr. David Alan Gilbert }
2950ccb783c3SDr. David Alan Gilbert return ret;
29517b89bf27SDr. David Alan Gilbert }
29527b89bf27SDr. David Alan Gilbert
qemu_loadvm_state(QEMUFile * f)2953c3049a56SJuan Quintela int qemu_loadvm_state(QEMUFile *f)
2954c3049a56SJuan Quintela {
29551a8f46f8SDr. David Alan Gilbert MigrationIncomingState *mis = migration_incoming_get_current();
2956c3049a56SJuan Quintela Error *local_err = NULL;
2957c3049a56SJuan Quintela int ret;
2958c3049a56SJuan Quintela
2959c3049a56SJuan Quintela if (qemu_savevm_state_blocked(&local_err)) {
2960c3049a56SJuan Quintela error_report_err(local_err);
2961c3049a56SJuan Quintela return -EINVAL;
2962c3049a56SJuan Quintela }
2963c3049a56SJuan Quintela
296416015d32SWei Yang ret = qemu_loadvm_state_header(f);
296561964c23SJuan Quintela if (ret) {
296661964c23SJuan Quintela return ret;
296761964c23SJuan Quintela }
296861964c23SJuan Quintela
2969e4fa064dSCédric Le Goater if (qemu_loadvm_state_setup(f, &local_err) != 0) {
2970e4fa064dSCédric Le Goater error_report_err(local_err);
29719e14b849SWei Yang return -EINVAL;
29729e14b849SWei Yang }
29739e14b849SWei Yang
29741b4adb10SAvihai Horon if (migrate_switchover_ack()) {
29751b4adb10SAvihai Horon qemu_loadvm_state_switchover_ack_needed(mis);
29761b4adb10SAvihai Horon }
29771b4adb10SAvihai Horon
297875e972daSDavid Gibson cpu_synchronize_all_pre_loadvm();
297975e972daSDavid Gibson
29807b89bf27SDr. David Alan Gilbert ret = qemu_loadvm_state_main(f, mis);
29817b89bf27SDr. David Alan Gilbert qemu_event_set(&mis->main_thread_load_event);
2982c3049a56SJuan Quintela
29837b89bf27SDr. David Alan Gilbert trace_qemu_loadvm_state_post_main(ret);
2984c3049a56SJuan Quintela
2985c76201abSDr. David Alan Gilbert if (mis->have_listen_thread) {
2986c76201abSDr. David Alan Gilbert /* Listen thread still going, can't clean up yet */
2987c76201abSDr. David Alan Gilbert return ret;
2988c76201abSDr. David Alan Gilbert }
2989c76201abSDr. David Alan Gilbert
29907b89bf27SDr. David Alan Gilbert if (ret == 0) {
29917b89bf27SDr. David Alan Gilbert ret = qemu_file_get_error(f);
2992c3049a56SJuan Quintela }
2993c3049a56SJuan Quintela
2994c3049a56SJuan Quintela /*
2995c3049a56SJuan Quintela * Try to read in the VMDESC section as well, so that dumping tools that
2996c3049a56SJuan Quintela * intercept our migration stream have the chance to see it.
2997c3049a56SJuan Quintela */
29981aca9a5fSDr. David Alan Gilbert
29991aca9a5fSDr. David Alan Gilbert /* We've got to be careful; if we don't read the data and just shut the fd
30001aca9a5fSDr. David Alan Gilbert * then the sender can error if we close while it's still sending.
30011aca9a5fSDr. David Alan Gilbert * We also mustn't read data that isn't there; some transports (RDMA)
30021aca9a5fSDr. David Alan Gilbert * will stall waiting for that data when the source has already closed.
30031aca9a5fSDr. David Alan Gilbert */
30047b89bf27SDr. David Alan Gilbert if (ret == 0 && should_send_vmdesc()) {
30051aca9a5fSDr. David Alan Gilbert uint8_t *buf;
30061aca9a5fSDr. David Alan Gilbert uint32_t size;
30077b89bf27SDr. David Alan Gilbert uint8_t section_type = qemu_get_byte(f);
30081aca9a5fSDr. David Alan Gilbert
30091aca9a5fSDr. David Alan Gilbert if (section_type != QEMU_VM_VMDESCRIPTION) {
30101aca9a5fSDr. David Alan Gilbert error_report("Expected vmdescription section, but got %d",
30111aca9a5fSDr. David Alan Gilbert section_type);
30121aca9a5fSDr. David Alan Gilbert /*
30131aca9a5fSDr. David Alan Gilbert * It doesn't seem worth failing at this point since
30141aca9a5fSDr. David Alan Gilbert * we apparently have an otherwise valid VM state
30151aca9a5fSDr. David Alan Gilbert */
30161aca9a5fSDr. David Alan Gilbert } else {
30171aca9a5fSDr. David Alan Gilbert buf = g_malloc(0x1000);
30181aca9a5fSDr. David Alan Gilbert size = qemu_get_be32(f);
3019c3049a56SJuan Quintela
3020c3049a56SJuan Quintela while (size > 0) {
3021c3049a56SJuan Quintela uint32_t read_chunk = MIN(size, 0x1000);
3022c3049a56SJuan Quintela qemu_get_buffer(f, buf, read_chunk);
3023c3049a56SJuan Quintela size -= read_chunk;
3024c3049a56SJuan Quintela }
3025c3049a56SJuan Quintela g_free(buf);
3026c3049a56SJuan Quintela }
30271aca9a5fSDr. David Alan Gilbert }
3028c3049a56SJuan Quintela
3029acb5ea86SJuan Quintela qemu_loadvm_state_cleanup();
3030c3049a56SJuan Quintela cpu_synchronize_all_post_init();
3031c3049a56SJuan Quintela
3032c3049a56SJuan Quintela return ret;
3033c3049a56SJuan Quintela }
3034c3049a56SJuan Quintela
qemu_load_device_state(QEMUFile * f)30353f6df99dSZhang Chen int qemu_load_device_state(QEMUFile *f)
30363f6df99dSZhang Chen {
30373f6df99dSZhang Chen MigrationIncomingState *mis = migration_incoming_get_current();
30383f6df99dSZhang Chen int ret;
30393f6df99dSZhang Chen
30403f6df99dSZhang Chen /* Load QEMU_VM_SECTION_FULL section */
30413f6df99dSZhang Chen ret = qemu_loadvm_state_main(f, mis);
30423f6df99dSZhang Chen if (ret < 0) {
30433f6df99dSZhang Chen error_report("Failed to load device state: %d", ret);
30443f6df99dSZhang Chen return ret;
30453f6df99dSZhang Chen }
30463f6df99dSZhang Chen
30473f6df99dSZhang Chen cpu_synchronize_all_post_init();
30483f6df99dSZhang Chen return 0;
30493f6df99dSZhang Chen }
30503f6df99dSZhang Chen
qemu_loadvm_approve_switchover(void)30511b4adb10SAvihai Horon int qemu_loadvm_approve_switchover(void)
30521b4adb10SAvihai Horon {
30531b4adb10SAvihai Horon MigrationIncomingState *mis = migration_incoming_get_current();
30541b4adb10SAvihai Horon
30551b4adb10SAvihai Horon if (!mis->switchover_ack_pending_num) {
30561b4adb10SAvihai Horon return -EINVAL;
30571b4adb10SAvihai Horon }
30581b4adb10SAvihai Horon
30591b4adb10SAvihai Horon mis->switchover_ack_pending_num--;
30601b4adb10SAvihai Horon trace_loadvm_approve_switchover(mis->switchover_ack_pending_num);
30611b4adb10SAvihai Horon
30621b4adb10SAvihai Horon if (mis->switchover_ack_pending_num) {
30631b4adb10SAvihai Horon return 0;
30641b4adb10SAvihai Horon }
30651b4adb10SAvihai Horon
30661b4adb10SAvihai Horon return migrate_send_rp_switchover_ack(mis);
30671b4adb10SAvihai Horon }
30681b4adb10SAvihai Horon
save_snapshot(const char * name,bool overwrite,const char * vmstate,bool has_devices,strList * devices,Error ** errp)3069f1a9fcddSDaniel P. Berrangé bool save_snapshot(const char *name, bool overwrite, const char *vmstate,
3070f1a9fcddSDaniel P. Berrangé bool has_devices, strList *devices, Error **errp)
3071c3049a56SJuan Quintela {
3072e26f98e2SDaniel P. Berrangé BlockDriverState *bs;
307380ef0586STuguoyi QEMUSnapshotInfo sn1, *sn = &sn1;
307466270a47SDenis V. Lunev int ret = -1, ret2;
3075c3049a56SJuan Quintela QEMUFile *f;
307658b10570SSteve Sistare RunState saved_state = runstate_get();
3077c3049a56SJuan Quintela uint64_t vm_state_size;
307885cd1cc6SDaniel P. Berrangé g_autoptr(GDateTime) now = g_date_time_new_now_local();
3079c3049a56SJuan Quintela
30806b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
30816b573efeSEmanuele Giuseppe Esposito
30825aaac467SPaolo Bonzini if (migration_is_blocked(errp)) {
30837ea14df2SPhilippe Mathieu-Daudé return false;
30845aaac467SPaolo Bonzini }
30855aaac467SPaolo Bonzini
3086377b21ccSPavel Dovgalyuk if (!replay_can_snapshot()) {
30874dd32b3dSMarkus Armbruster error_setg(errp, "Record/replay does not allow making snapshot "
3088377b21ccSPavel Dovgalyuk "right now. Try once more later.");
30897ea14df2SPhilippe Mathieu-Daudé return false;
3090377b21ccSPavel Dovgalyuk }
3091377b21ccSPavel Dovgalyuk
3092f1a9fcddSDaniel P. Berrangé if (!bdrv_all_can_snapshot(has_devices, devices, errp)) {
30937ea14df2SPhilippe Mathieu-Daudé return false;
3094c3049a56SJuan Quintela }
3095c3049a56SJuan Quintela
30960b461605SDenis V. Lunev /* Delete old snapshots of the same name */
3097ac8c19baSPavel Dovgalyuk if (name) {
3098f781f841SDaniel P. Berrangé if (overwrite) {
3099f1a9fcddSDaniel P. Berrangé if (bdrv_all_delete_snapshot(name, has_devices,
3100f1a9fcddSDaniel P. Berrangé devices, errp) < 0) {
31017ea14df2SPhilippe Mathieu-Daudé return false;
3102ac8c19baSPavel Dovgalyuk }
3103f781f841SDaniel P. Berrangé } else {
3104f1a9fcddSDaniel P. Berrangé ret2 = bdrv_all_has_snapshot(name, has_devices, devices, errp);
3105f781f841SDaniel P. Berrangé if (ret2 < 0) {
3106f781f841SDaniel P. Berrangé return false;
3107f781f841SDaniel P. Berrangé }
3108f781f841SDaniel P. Berrangé if (ret2 == 1) {
3109f781f841SDaniel P. Berrangé error_setg(errp,
3110f781f841SDaniel P. Berrangé "Snapshot '%s' already exists in one or more devices",
3111f781f841SDaniel P. Berrangé name);
3112f781f841SDaniel P. Berrangé return false;
3113f781f841SDaniel P. Berrangé }
3114f781f841SDaniel P. Berrangé }
31150b461605SDenis V. Lunev }
31160b461605SDenis V. Lunev
3117f1a9fcddSDaniel P. Berrangé bs = bdrv_all_find_vmstate_bs(vmstate, has_devices, devices, errp);
31187cb14481SDenis V. Lunev if (bs == NULL) {
31197ea14df2SPhilippe Mathieu-Daudé return false;
3120c3049a56SJuan Quintela }
3121c3049a56SJuan Quintela
3122c33f1829SVladimir Sementsov-Ogievskiy global_state_store();
3123c3049a56SJuan Quintela vm_stop(RUN_STATE_SAVE_VM);
3124c3049a56SJuan Quintela
31258649f2f9SStefan Hajnoczi bdrv_drain_all_begin();
31268649f2f9SStefan Hajnoczi
3127c3049a56SJuan Quintela memset(sn, 0, sizeof(*sn));
3128c3049a56SJuan Quintela
3129c3049a56SJuan Quintela /* fill auxiliary fields */
313085cd1cc6SDaniel P. Berrangé sn->date_sec = g_date_time_to_unix(now);
313185cd1cc6SDaniel P. Berrangé sn->date_nsec = g_date_time_get_microsecond(now) * 1000;
3132c3049a56SJuan Quintela sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3133b39847a5SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) {
3134b39847a5SPavel Dovgalyuk sn->icount = replay_get_current_icount();
3135b39847a5SPavel Dovgalyuk } else {
3136b39847a5SPavel Dovgalyuk sn->icount = -1ULL;
3137b39847a5SPavel Dovgalyuk }
3138c3049a56SJuan Quintela
3139c3049a56SJuan Quintela if (name) {
3140c3049a56SJuan Quintela pstrcpy(sn->name, sizeof(sn->name), name);
3141c3049a56SJuan Quintela } else {
314285cd1cc6SDaniel P. Berrangé g_autofree char *autoname = g_date_time_format(now, "vm-%Y%m%d%H%M%S");
314385cd1cc6SDaniel P. Berrangé pstrcpy(sn->name, sizeof(sn->name), autoname);
3144c3049a56SJuan Quintela }
3145c3049a56SJuan Quintela
3146c3049a56SJuan Quintela /* save the VM state */
3147c3049a56SJuan Quintela f = qemu_fopen_bdrv(bs, 1);
3148c3049a56SJuan Quintela if (!f) {
3149927d6638SJuan Quintela error_setg(errp, "Could not open VM state file");
3150c3049a56SJuan Quintela goto the_end;
3151c3049a56SJuan Quintela }
3152927d6638SJuan Quintela ret = qemu_savevm_state(f, errp);
3153e9c0eed7SJuan Quintela vm_state_size = qemu_file_transferred(f);
315466270a47SDenis V. Lunev ret2 = qemu_fclose(f);
3155c3049a56SJuan Quintela if (ret < 0) {
3156c3049a56SJuan Quintela goto the_end;
3157c3049a56SJuan Quintela }
315866270a47SDenis V. Lunev if (ret2 < 0) {
315966270a47SDenis V. Lunev ret = ret2;
316066270a47SDenis V. Lunev goto the_end;
316166270a47SDenis V. Lunev }
3162c3049a56SJuan Quintela
3163f1a9fcddSDaniel P. Berrangé ret = bdrv_all_create_snapshot(sn, bs, vm_state_size,
3164f1a9fcddSDaniel P. Berrangé has_devices, devices, errp);
3165c3049a56SJuan Quintela if (ret < 0) {
3166f1a9fcddSDaniel P. Berrangé bdrv_all_delete_snapshot(sn->name, has_devices, devices, NULL);
3167ac8c19baSPavel Dovgalyuk goto the_end;
3168c3049a56SJuan Quintela }
3169c3049a56SJuan Quintela
3170ac8c19baSPavel Dovgalyuk ret = 0;
3171ac8c19baSPavel Dovgalyuk
3172c3049a56SJuan Quintela the_end:
31738649f2f9SStefan Hajnoczi bdrv_drain_all_end();
31748649f2f9SStefan Hajnoczi
317558b10570SSteve Sistare vm_resume(saved_state);
31767ea14df2SPhilippe Mathieu-Daudé return ret == 0;
3177ac8c19baSPavel Dovgalyuk }
3178ac8c19baSPavel Dovgalyuk
qmp_xen_save_devices_state(const char * filename,bool has_live,bool live,Error ** errp)31795d6c599fSAnthony PERARD void qmp_xen_save_devices_state(const char *filename, bool has_live, bool live,
31805d6c599fSAnthony PERARD Error **errp)
3181c3049a56SJuan Quintela {
3182c3049a56SJuan Quintela QEMUFile *f;
31838925839fSDaniel P. Berrange QIOChannelFile *ioc;
3184c3049a56SJuan Quintela int saved_vm_running;
3185c3049a56SJuan Quintela int ret;
3186c3049a56SJuan Quintela
31875d6c599fSAnthony PERARD if (!has_live) {
31885d6c599fSAnthony PERARD /* live default to true so old version of Xen tool stack can have a
31893a4452d8Szhaolichang * successful live migration */
31905d6c599fSAnthony PERARD live = true;
31915d6c599fSAnthony PERARD }
31925d6c599fSAnthony PERARD
3193c3049a56SJuan Quintela saved_vm_running = runstate_is_running();
3194c3049a56SJuan Quintela vm_stop(RUN_STATE_SAVE_VM);
3195c69adea4SAnthony PERARD global_state_store_running();
3196c3049a56SJuan Quintela
3197b4deb9bfSDov Murik ioc = qio_channel_file_new_path(filename, O_WRONLY | O_CREAT | O_TRUNC,
3198b4deb9bfSDov Murik 0660, errp);
31998925839fSDaniel P. Berrange if (!ioc) {
3200c3049a56SJuan Quintela goto the_end;
3201c3049a56SJuan Quintela }
32026f01f136SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-save-state");
320377ef2dc1SDaniel P. Berrangé f = qemu_file_new_output(QIO_CHANNEL(ioc));
3204032b79f7SRoss Lagerwall object_unref(OBJECT(ioc));
3205c3049a56SJuan Quintela ret = qemu_save_device_state(f);
320696994fd1SRoss Lagerwall if (ret < 0 || qemu_fclose(f) < 0) {
3207fdac62dbSMarkus Armbruster error_setg(errp, "saving Xen device state failed");
32085d6c599fSAnthony PERARD } else {
32095d6c599fSAnthony PERARD /* libxl calls the QMP command "stop" before calling
32105d6c599fSAnthony PERARD * "xen-save-devices-state" and in case of migration failure, libxl
32115d6c599fSAnthony PERARD * would call "cont".
32125d6c599fSAnthony PERARD * So call bdrv_inactivate_all (release locks) here to let the other
32133a4452d8Szhaolichang * side of the migration take control of the images.
32145d6c599fSAnthony PERARD */
32155d6c599fSAnthony PERARD if (live && !saved_vm_running) {
32165d6c599fSAnthony PERARD ret = bdrv_inactivate_all();
32175d6c599fSAnthony PERARD if (ret) {
32185d6c599fSAnthony PERARD error_setg(errp, "%s: bdrv_inactivate_all() failed (%d)",
32195d6c599fSAnthony PERARD __func__, ret);
32205d6c599fSAnthony PERARD }
32215d6c599fSAnthony PERARD }
3222c3049a56SJuan Quintela }
3223c3049a56SJuan Quintela
3224c3049a56SJuan Quintela the_end:
3225c3049a56SJuan Quintela if (saved_vm_running) {
3226c3049a56SJuan Quintela vm_start();
3227c3049a56SJuan Quintela }
3228c3049a56SJuan Quintela }
3229c3049a56SJuan Quintela
qmp_xen_load_devices_state(const char * filename,Error ** errp)323088c16567SWen Congyang void qmp_xen_load_devices_state(const char *filename, Error **errp)
323188c16567SWen Congyang {
323288c16567SWen Congyang QEMUFile *f;
323388c16567SWen Congyang QIOChannelFile *ioc;
323488c16567SWen Congyang int ret;
323588c16567SWen Congyang
323688c16567SWen Congyang /* Guest must be paused before loading the device state; the RAM state
323788c16567SWen Congyang * will already have been loaded by xc
323888c16567SWen Congyang */
323988c16567SWen Congyang if (runstate_is_running()) {
324088c16567SWen Congyang error_setg(errp, "Cannot update device state while vm is running");
324188c16567SWen Congyang return;
324288c16567SWen Congyang }
324388c16567SWen Congyang vm_stop(RUN_STATE_RESTORE_VM);
324488c16567SWen Congyang
324588c16567SWen Congyang ioc = qio_channel_file_new_path(filename, O_RDONLY | O_BINARY, 0, errp);
324688c16567SWen Congyang if (!ioc) {
324788c16567SWen Congyang return;
324888c16567SWen Congyang }
32496f01f136SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-load-state");
325077ef2dc1SDaniel P. Berrangé f = qemu_file_new_input(QIO_CHANNEL(ioc));
3251032b79f7SRoss Lagerwall object_unref(OBJECT(ioc));
325288c16567SWen Congyang
325388c16567SWen Congyang ret = qemu_loadvm_state(f);
325488c16567SWen Congyang qemu_fclose(f);
325588c16567SWen Congyang if (ret < 0) {
3256fdac62dbSMarkus Armbruster error_setg(errp, "loading Xen device state failed");
325788c16567SWen Congyang }
325888c16567SWen Congyang migration_incoming_state_destroy();
325988c16567SWen Congyang }
326088c16567SWen Congyang
load_snapshot(const char * name,const char * vmstate,bool has_devices,strList * devices,Error ** errp)3261f1a9fcddSDaniel P. Berrangé bool load_snapshot(const char *name, const char *vmstate,
3262f1a9fcddSDaniel P. Berrangé bool has_devices, strList *devices, Error **errp)
3263c3049a56SJuan Quintela {
3264e26f98e2SDaniel P. Berrangé BlockDriverState *bs_vm_state;
3265c3049a56SJuan Quintela QEMUSnapshotInfo sn;
3266c3049a56SJuan Quintela QEMUFile *f;
3267c3049a56SJuan Quintela int ret;
3268b4b076daSJuan Quintela MigrationIncomingState *mis = migration_incoming_get_current();
3269c3049a56SJuan Quintela
3270f1a9fcddSDaniel P. Berrangé if (!bdrv_all_can_snapshot(has_devices, devices, errp)) {
3271f61fe11aSDaniel P. Berrangé return false;
3272849f96e2SDenis V. Lunev }
3273f1a9fcddSDaniel P. Berrangé ret = bdrv_all_has_snapshot(name, has_devices, devices, errp);
3274723ccda1SDenis V. Lunev if (ret < 0) {
3275f61fe11aSDaniel P. Berrangé return false;
3276723ccda1SDenis V. Lunev }
32773d3e9b1fSDaniel P. Berrangé if (ret == 0) {
32783d3e9b1fSDaniel P. Berrangé error_setg(errp, "Snapshot '%s' does not exist in one or more devices",
32793d3e9b1fSDaniel P. Berrangé name);
32803d3e9b1fSDaniel P. Berrangé return false;
32813d3e9b1fSDaniel P. Berrangé }
3282849f96e2SDenis V. Lunev
3283f1a9fcddSDaniel P. Berrangé bs_vm_state = bdrv_all_find_vmstate_bs(vmstate, has_devices, devices, errp);
3284c3049a56SJuan Quintela if (!bs_vm_state) {
3285f61fe11aSDaniel P. Berrangé return false;
3286c3049a56SJuan Quintela }
3287c3049a56SJuan Quintela
3288c3049a56SJuan Quintela /* Don't even try to load empty VM states */
3289c3049a56SJuan Quintela ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
3290c3049a56SJuan Quintela if (ret < 0) {
3291*97d2b66dSNicholas Piggin error_setg(errp, "Snapshot can not be found");
3292f61fe11aSDaniel P. Berrangé return false;
3293c3049a56SJuan Quintela } else if (sn.vm_state_size == 0) {
3294927d6638SJuan Quintela error_setg(errp, "This is a disk-only snapshot. Revert to it "
3295927d6638SJuan Quintela " offline using qemu-img");
3296f61fe11aSDaniel P. Berrangé return false;
3297c3049a56SJuan Quintela }
3298c3049a56SJuan Quintela
3299f9a9fb65SPavel Dovgalyuk /*
3300f9a9fb65SPavel Dovgalyuk * Flush the record/replay queue. Now the VM state is going
3301f9a9fb65SPavel Dovgalyuk * to change. Therefore we don't need to preserve its consistency
3302f9a9fb65SPavel Dovgalyuk */
3303f9a9fb65SPavel Dovgalyuk replay_flush_events();
3304f9a9fb65SPavel Dovgalyuk
3305c3049a56SJuan Quintela /* Flush all IO requests so they don't interfere with the new state. */
33068649f2f9SStefan Hajnoczi bdrv_drain_all_begin();
3307c3049a56SJuan Quintela
3308f1a9fcddSDaniel P. Berrangé ret = bdrv_all_goto_snapshot(name, has_devices, devices, errp);
3309c3049a56SJuan Quintela if (ret < 0) {
33108649f2f9SStefan Hajnoczi goto err_drain;
3311c3049a56SJuan Quintela }
3312c3049a56SJuan Quintela
3313c3049a56SJuan Quintela /* restore the VM state */
3314c3049a56SJuan Quintela f = qemu_fopen_bdrv(bs_vm_state, 0);
3315c3049a56SJuan Quintela if (!f) {
3316927d6638SJuan Quintela error_setg(errp, "Could not open VM state file");
33178649f2f9SStefan Hajnoczi goto err_drain;
3318c3049a56SJuan Quintela }
3319c3049a56SJuan Quintela
33207966d70fSJason A. Donenfeld qemu_system_reset(SHUTDOWN_CAUSE_SNAPSHOT_LOAD);
3321b4b076daSJuan Quintela mis->from_src_file = f;
3322c3049a56SJuan Quintela
3323b5eea99eSLukas Straub if (!yank_register_instance(MIGRATION_YANK_INSTANCE, errp)) {
3324b5eea99eSLukas Straub ret = -EINVAL;
3325b5eea99eSLukas Straub goto err_drain;
3326b5eea99eSLukas Straub }
332779b3c12aSDenis V. Lunev ret = qemu_loadvm_state(f);
33281575829dSStefan Hajnoczi migration_incoming_state_destroy();
332979b3c12aSDenis V. Lunev
33308649f2f9SStefan Hajnoczi bdrv_drain_all_end();
33318649f2f9SStefan Hajnoczi
3332c3049a56SJuan Quintela if (ret < 0) {
3333927d6638SJuan Quintela error_setg(errp, "Error %d while loading VM state", ret);
3334f61fe11aSDaniel P. Berrangé return false;
3335c3049a56SJuan Quintela }
3336c3049a56SJuan Quintela
3337f61fe11aSDaniel P. Berrangé return true;
33388649f2f9SStefan Hajnoczi
33398649f2f9SStefan Hajnoczi err_drain:
33408649f2f9SStefan Hajnoczi bdrv_drain_all_end();
3341f61fe11aSDaniel P. Berrangé return false;
3342c3049a56SJuan Quintela }
3343c3049a56SJuan Quintela
load_snapshot_resume(RunState state)334458b10570SSteve Sistare void load_snapshot_resume(RunState state)
334558b10570SSteve Sistare {
334658b10570SSteve Sistare vm_resume(state);
334758b10570SSteve Sistare if (state == RUN_STATE_RUNNING && runstate_get() == RUN_STATE_SUSPENDED) {
334858b10570SSteve Sistare qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, &error_abort);
334958b10570SSteve Sistare }
335058b10570SSteve Sistare }
335158b10570SSteve Sistare
delete_snapshot(const char * name,bool has_devices,strList * devices,Error ** errp)3352bef7e9e2SDaniel P. Berrangé bool delete_snapshot(const char *name, bool has_devices,
3353bef7e9e2SDaniel P. Berrangé strList *devices, Error **errp)
3354bef7e9e2SDaniel P. Berrangé {
3355bef7e9e2SDaniel P. Berrangé if (!bdrv_all_can_snapshot(has_devices, devices, errp)) {
3356bef7e9e2SDaniel P. Berrangé return false;
3357bef7e9e2SDaniel P. Berrangé }
3358bef7e9e2SDaniel P. Berrangé
3359bef7e9e2SDaniel P. Berrangé if (bdrv_all_delete_snapshot(name, has_devices, devices, errp) < 0) {
3360bef7e9e2SDaniel P. Berrangé return false;
3361bef7e9e2SDaniel P. Berrangé }
3362bef7e9e2SDaniel P. Berrangé
3363bef7e9e2SDaniel P. Berrangé return true;
3364bef7e9e2SDaniel P. Berrangé }
3365bef7e9e2SDaniel P. Berrangé
vmstate_register_ram(MemoryRegion * mr,DeviceState * dev)3366c3049a56SJuan Quintela void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev)
3367c3049a56SJuan Quintela {
3368fa53a0e5SGonglei qemu_ram_set_idstr(mr->ram_block,
3369c3049a56SJuan Quintela memory_region_name(mr), dev);
3370b895de50SCédric Le Goater qemu_ram_set_migratable(mr->ram_block);
3371c3049a56SJuan Quintela }
3372c3049a56SJuan Quintela
vmstate_unregister_ram(MemoryRegion * mr,DeviceState * dev)3373c3049a56SJuan Quintela void vmstate_unregister_ram(MemoryRegion *mr, DeviceState *dev)
3374c3049a56SJuan Quintela {
3375fa53a0e5SGonglei qemu_ram_unset_idstr(mr->ram_block);
3376b895de50SCédric Le Goater qemu_ram_unset_migratable(mr->ram_block);
3377c3049a56SJuan Quintela }
3378c3049a56SJuan Quintela
vmstate_register_ram_global(MemoryRegion * mr)3379c3049a56SJuan Quintela void vmstate_register_ram_global(MemoryRegion *mr)
3380c3049a56SJuan Quintela {
3381c3049a56SJuan Quintela vmstate_register_ram(mr, NULL);
3382c3049a56SJuan Quintela }
33831bfe5f05SJuan Quintela
vmstate_check_only_migratable(const VMStateDescription * vmsd)33841bfe5f05SJuan Quintela bool vmstate_check_only_migratable(const VMStateDescription *vmsd)
33851bfe5f05SJuan Quintela {
33861bfe5f05SJuan Quintela /* check needed if --only-migratable is specified */
3387811f8652SMarkus Armbruster if (!only_migratable) {
33881bfe5f05SJuan Quintela return true;
33891bfe5f05SJuan Quintela }
33901bfe5f05SJuan Quintela
33911bfe5f05SJuan Quintela return !(vmsd && vmsd->unmigratable);
33921bfe5f05SJuan Quintela }
33930f0d83a4SDaniel P. Berrangé
33940f0d83a4SDaniel P. Berrangé typedef struct SnapshotJob {
33950f0d83a4SDaniel P. Berrangé Job common;
33960f0d83a4SDaniel P. Berrangé char *tag;
33970f0d83a4SDaniel P. Berrangé char *vmstate;
33980f0d83a4SDaniel P. Berrangé strList *devices;
33990f0d83a4SDaniel P. Berrangé Coroutine *co;
34000f0d83a4SDaniel P. Berrangé Error **errp;
34010f0d83a4SDaniel P. Berrangé bool ret;
34020f0d83a4SDaniel P. Berrangé } SnapshotJob;
34030f0d83a4SDaniel P. Berrangé
qmp_snapshot_job_free(SnapshotJob * s)34040f0d83a4SDaniel P. Berrangé static void qmp_snapshot_job_free(SnapshotJob *s)
34050f0d83a4SDaniel P. Berrangé {
34060f0d83a4SDaniel P. Berrangé g_free(s->tag);
34070f0d83a4SDaniel P. Berrangé g_free(s->vmstate);
34080f0d83a4SDaniel P. Berrangé qapi_free_strList(s->devices);
34090f0d83a4SDaniel P. Berrangé }
34100f0d83a4SDaniel P. Berrangé
34110f0d83a4SDaniel P. Berrangé
snapshot_load_job_bh(void * opaque)34120f0d83a4SDaniel P. Berrangé static void snapshot_load_job_bh(void *opaque)
34130f0d83a4SDaniel P. Berrangé {
34140f0d83a4SDaniel P. Berrangé Job *job = opaque;
34150f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
341658b10570SSteve Sistare RunState orig_state = runstate_get();
34170f0d83a4SDaniel P. Berrangé
34180f0d83a4SDaniel P. Berrangé job_progress_set_remaining(&s->common, 1);
34190f0d83a4SDaniel P. Berrangé
34200f0d83a4SDaniel P. Berrangé vm_stop(RUN_STATE_RESTORE_VM);
34210f0d83a4SDaniel P. Berrangé
34220f0d83a4SDaniel P. Berrangé s->ret = load_snapshot(s->tag, s->vmstate, true, s->devices, s->errp);
342358b10570SSteve Sistare if (s->ret) {
342458b10570SSteve Sistare load_snapshot_resume(orig_state);
34250f0d83a4SDaniel P. Berrangé }
34260f0d83a4SDaniel P. Berrangé
34270f0d83a4SDaniel P. Berrangé job_progress_update(&s->common, 1);
34280f0d83a4SDaniel P. Berrangé
34290f0d83a4SDaniel P. Berrangé qmp_snapshot_job_free(s);
34300f0d83a4SDaniel P. Berrangé aio_co_wake(s->co);
34310f0d83a4SDaniel P. Berrangé }
34320f0d83a4SDaniel P. Berrangé
snapshot_save_job_bh(void * opaque)34330f0d83a4SDaniel P. Berrangé static void snapshot_save_job_bh(void *opaque)
34340f0d83a4SDaniel P. Berrangé {
34350f0d83a4SDaniel P. Berrangé Job *job = opaque;
34360f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34370f0d83a4SDaniel P. Berrangé
34380f0d83a4SDaniel P. Berrangé job_progress_set_remaining(&s->common, 1);
34390f0d83a4SDaniel P. Berrangé s->ret = save_snapshot(s->tag, false, s->vmstate,
34400f0d83a4SDaniel P. Berrangé true, s->devices, s->errp);
34410f0d83a4SDaniel P. Berrangé job_progress_update(&s->common, 1);
34420f0d83a4SDaniel P. Berrangé
34430f0d83a4SDaniel P. Berrangé qmp_snapshot_job_free(s);
34440f0d83a4SDaniel P. Berrangé aio_co_wake(s->co);
34450f0d83a4SDaniel P. Berrangé }
34460f0d83a4SDaniel P. Berrangé
snapshot_delete_job_bh(void * opaque)34470f0d83a4SDaniel P. Berrangé static void snapshot_delete_job_bh(void *opaque)
34480f0d83a4SDaniel P. Berrangé {
34490f0d83a4SDaniel P. Berrangé Job *job = opaque;
34500f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34510f0d83a4SDaniel P. Berrangé
34520f0d83a4SDaniel P. Berrangé job_progress_set_remaining(&s->common, 1);
34530f0d83a4SDaniel P. Berrangé s->ret = delete_snapshot(s->tag, true, s->devices, s->errp);
34540f0d83a4SDaniel P. Berrangé job_progress_update(&s->common, 1);
34550f0d83a4SDaniel P. Berrangé
34560f0d83a4SDaniel P. Berrangé qmp_snapshot_job_free(s);
34570f0d83a4SDaniel P. Berrangé aio_co_wake(s->co);
34580f0d83a4SDaniel P. Berrangé }
34590f0d83a4SDaniel P. Berrangé
snapshot_save_job_run(Job * job,Error ** errp)34600f0d83a4SDaniel P. Berrangé static int coroutine_fn snapshot_save_job_run(Job *job, Error **errp)
34610f0d83a4SDaniel P. Berrangé {
34620f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34630f0d83a4SDaniel P. Berrangé s->errp = errp;
34640f0d83a4SDaniel P. Berrangé s->co = qemu_coroutine_self();
34650f0d83a4SDaniel P. Berrangé aio_bh_schedule_oneshot(qemu_get_aio_context(),
34660f0d83a4SDaniel P. Berrangé snapshot_save_job_bh, job);
34670f0d83a4SDaniel P. Berrangé qemu_coroutine_yield();
34680f0d83a4SDaniel P. Berrangé return s->ret ? 0 : -1;
34690f0d83a4SDaniel P. Berrangé }
34700f0d83a4SDaniel P. Berrangé
snapshot_load_job_run(Job * job,Error ** errp)34710f0d83a4SDaniel P. Berrangé static int coroutine_fn snapshot_load_job_run(Job *job, Error **errp)
34720f0d83a4SDaniel P. Berrangé {
34730f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34740f0d83a4SDaniel P. Berrangé s->errp = errp;
34750f0d83a4SDaniel P. Berrangé s->co = qemu_coroutine_self();
34760f0d83a4SDaniel P. Berrangé aio_bh_schedule_oneshot(qemu_get_aio_context(),
34770f0d83a4SDaniel P. Berrangé snapshot_load_job_bh, job);
34780f0d83a4SDaniel P. Berrangé qemu_coroutine_yield();
34790f0d83a4SDaniel P. Berrangé return s->ret ? 0 : -1;
34800f0d83a4SDaniel P. Berrangé }
34810f0d83a4SDaniel P. Berrangé
snapshot_delete_job_run(Job * job,Error ** errp)34820f0d83a4SDaniel P. Berrangé static int coroutine_fn snapshot_delete_job_run(Job *job, Error **errp)
34830f0d83a4SDaniel P. Berrangé {
34840f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34850f0d83a4SDaniel P. Berrangé s->errp = errp;
34860f0d83a4SDaniel P. Berrangé s->co = qemu_coroutine_self();
34870f0d83a4SDaniel P. Berrangé aio_bh_schedule_oneshot(qemu_get_aio_context(),
34880f0d83a4SDaniel P. Berrangé snapshot_delete_job_bh, job);
34890f0d83a4SDaniel P. Berrangé qemu_coroutine_yield();
34900f0d83a4SDaniel P. Berrangé return s->ret ? 0 : -1;
34910f0d83a4SDaniel P. Berrangé }
34920f0d83a4SDaniel P. Berrangé
34930f0d83a4SDaniel P. Berrangé
34940f0d83a4SDaniel P. Berrangé static const JobDriver snapshot_load_job_driver = {
34950f0d83a4SDaniel P. Berrangé .instance_size = sizeof(SnapshotJob),
34960f0d83a4SDaniel P. Berrangé .job_type = JOB_TYPE_SNAPSHOT_LOAD,
34970f0d83a4SDaniel P. Berrangé .run = snapshot_load_job_run,
34980f0d83a4SDaniel P. Berrangé };
34990f0d83a4SDaniel P. Berrangé
35000f0d83a4SDaniel P. Berrangé static const JobDriver snapshot_save_job_driver = {
35010f0d83a4SDaniel P. Berrangé .instance_size = sizeof(SnapshotJob),
35020f0d83a4SDaniel P. Berrangé .job_type = JOB_TYPE_SNAPSHOT_SAVE,
35030f0d83a4SDaniel P. Berrangé .run = snapshot_save_job_run,
35040f0d83a4SDaniel P. Berrangé };
35050f0d83a4SDaniel P. Berrangé
35060f0d83a4SDaniel P. Berrangé static const JobDriver snapshot_delete_job_driver = {
35070f0d83a4SDaniel P. Berrangé .instance_size = sizeof(SnapshotJob),
35080f0d83a4SDaniel P. Berrangé .job_type = JOB_TYPE_SNAPSHOT_DELETE,
35090f0d83a4SDaniel P. Berrangé .run = snapshot_delete_job_run,
35100f0d83a4SDaniel P. Berrangé };
35110f0d83a4SDaniel P. Berrangé
35120f0d83a4SDaniel P. Berrangé
qmp_snapshot_save(const char * job_id,const char * tag,const char * vmstate,strList * devices,Error ** errp)35130f0d83a4SDaniel P. Berrangé void qmp_snapshot_save(const char *job_id,
35140f0d83a4SDaniel P. Berrangé const char *tag,
35150f0d83a4SDaniel P. Berrangé const char *vmstate,
35160f0d83a4SDaniel P. Berrangé strList *devices,
35170f0d83a4SDaniel P. Berrangé Error **errp)
35180f0d83a4SDaniel P. Berrangé {
35190f0d83a4SDaniel P. Berrangé SnapshotJob *s;
35200f0d83a4SDaniel P. Berrangé
35210f0d83a4SDaniel P. Berrangé s = job_create(job_id, &snapshot_save_job_driver, NULL,
35220f0d83a4SDaniel P. Berrangé qemu_get_aio_context(), JOB_MANUAL_DISMISS,
35230f0d83a4SDaniel P. Berrangé NULL, NULL, errp);
35240f0d83a4SDaniel P. Berrangé if (!s) {
35250f0d83a4SDaniel P. Berrangé return;
35260f0d83a4SDaniel P. Berrangé }
35270f0d83a4SDaniel P. Berrangé
35280f0d83a4SDaniel P. Berrangé s->tag = g_strdup(tag);
35290f0d83a4SDaniel P. Berrangé s->vmstate = g_strdup(vmstate);
35300f0d83a4SDaniel P. Berrangé s->devices = QAPI_CLONE(strList, devices);
35310f0d83a4SDaniel P. Berrangé
35320f0d83a4SDaniel P. Berrangé job_start(&s->common);
35330f0d83a4SDaniel P. Berrangé }
35340f0d83a4SDaniel P. Berrangé
qmp_snapshot_load(const char * job_id,const char * tag,const char * vmstate,strList * devices,Error ** errp)35350f0d83a4SDaniel P. Berrangé void qmp_snapshot_load(const char *job_id,
35360f0d83a4SDaniel P. Berrangé const char *tag,
35370f0d83a4SDaniel P. Berrangé const char *vmstate,
35380f0d83a4SDaniel P. Berrangé strList *devices,
35390f0d83a4SDaniel P. Berrangé Error **errp)
35400f0d83a4SDaniel P. Berrangé {
35410f0d83a4SDaniel P. Berrangé SnapshotJob *s;
35420f0d83a4SDaniel P. Berrangé
35430f0d83a4SDaniel P. Berrangé s = job_create(job_id, &snapshot_load_job_driver, NULL,
35440f0d83a4SDaniel P. Berrangé qemu_get_aio_context(), JOB_MANUAL_DISMISS,
35450f0d83a4SDaniel P. Berrangé NULL, NULL, errp);
35460f0d83a4SDaniel P. Berrangé if (!s) {
35470f0d83a4SDaniel P. Berrangé return;
35480f0d83a4SDaniel P. Berrangé }
35490f0d83a4SDaniel P. Berrangé
35500f0d83a4SDaniel P. Berrangé s->tag = g_strdup(tag);
35510f0d83a4SDaniel P. Berrangé s->vmstate = g_strdup(vmstate);
35520f0d83a4SDaniel P. Berrangé s->devices = QAPI_CLONE(strList, devices);
35530f0d83a4SDaniel P. Berrangé
35540f0d83a4SDaniel P. Berrangé job_start(&s->common);
35550f0d83a4SDaniel P. Berrangé }
35560f0d83a4SDaniel P. Berrangé
qmp_snapshot_delete(const char * job_id,const char * tag,strList * devices,Error ** errp)35570f0d83a4SDaniel P. Berrangé void qmp_snapshot_delete(const char *job_id,
35580f0d83a4SDaniel P. Berrangé const char *tag,
35590f0d83a4SDaniel P. Berrangé strList *devices,
35600f0d83a4SDaniel P. Berrangé Error **errp)
35610f0d83a4SDaniel P. Berrangé {
35620f0d83a4SDaniel P. Berrangé SnapshotJob *s;
35630f0d83a4SDaniel P. Berrangé
35640f0d83a4SDaniel P. Berrangé s = job_create(job_id, &snapshot_delete_job_driver, NULL,
35650f0d83a4SDaniel P. Berrangé qemu_get_aio_context(), JOB_MANUAL_DISMISS,
35660f0d83a4SDaniel P. Berrangé NULL, NULL, errp);
35670f0d83a4SDaniel P. Berrangé if (!s) {
35680f0d83a4SDaniel P. Berrangé return;
35690f0d83a4SDaniel P. Berrangé }
35700f0d83a4SDaniel P. Berrangé
35710f0d83a4SDaniel P. Berrangé s->tag = g_strdup(tag);
35720f0d83a4SDaniel P. Berrangé s->devices = QAPI_CLONE(strList, devices);
35730f0d83a4SDaniel P. Berrangé
35740f0d83a4SDaniel P. Berrangé job_start(&s->common);
35750f0d83a4SDaniel P. Berrangé }
3576