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
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)86493062e23SPeter Xu int vmstate_register_with_alias_id(VMStateIf *obj, uint32_t instance_id,
865c3049a56SJuan Quintela const VMStateDescription *vmsd,
866c3049a56SJuan Quintela void *opaque, int alias_id,
867bc5c4f21SDr. David Alan Gilbert int required_for_version,
868bc5c4f21SDr. David Alan Gilbert Error **errp)
869c3049a56SJuan Quintela {
870c3049a56SJuan Quintela SaveStateEntry *se;
871c3049a56SJuan Quintela
872c3049a56SJuan Quintela /* If this triggers, alias support can be dropped for the vmsd. */
873c3049a56SJuan Quintela assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
874c3049a56SJuan Quintela
87597f3ad35SMarkus Armbruster se = g_new0(SaveStateEntry, 1);
876c3049a56SJuan Quintela se->version_id = vmsd->version_id;
8770163a2e0SJuan Quintela se->section_id = savevm_state.global_section_id++;
878c3049a56SJuan Quintela se->opaque = opaque;
879c3049a56SJuan Quintela se->vmsd = vmsd;
880c3049a56SJuan Quintela se->alias_id = alias_id;
881c3049a56SJuan Quintela
8823cad405bSMarc-André Lureau if (obj) {
8833cad405bSMarc-André Lureau char *id = vmstate_if_get_id(obj);
884c3049a56SJuan Quintela if (id) {
885581f08baSDr. David Alan Gilbert if (snprintf(se->idstr, sizeof(se->idstr), "%s/", id) >=
886581f08baSDr. David Alan Gilbert sizeof(se->idstr)) {
887581f08baSDr. David Alan Gilbert error_setg(errp, "Path too long for VMState (%s)", id);
888c3049a56SJuan Quintela g_free(id);
889581f08baSDr. David Alan Gilbert g_free(se);
890581f08baSDr. David Alan Gilbert
891581f08baSDr. David Alan Gilbert return -1;
892581f08baSDr. David Alan Gilbert }
893128e4e10SMarc-André Lureau g_free(id);
894c3049a56SJuan Quintela
89597f3ad35SMarkus Armbruster se->compat = g_new0(CompatEntry, 1);
896c3049a56SJuan Quintela pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name);
8971df2c9a2SPeter Xu se->compat->instance_id = instance_id == VMSTATE_INSTANCE_ID_ANY ?
898c3049a56SJuan Quintela calculate_compat_instance_id(vmsd->name) : instance_id;
8991df2c9a2SPeter Xu instance_id = VMSTATE_INSTANCE_ID_ANY;
900c3049a56SJuan Quintela }
901c3049a56SJuan Quintela }
902c3049a56SJuan Quintela pstrcat(se->idstr, sizeof(se->idstr), vmsd->name);
903c3049a56SJuan Quintela
9041df2c9a2SPeter Xu if (instance_id == VMSTATE_INSTANCE_ID_ANY) {
905c3049a56SJuan Quintela se->instance_id = calculate_new_instance_id(se->idstr);
906c3049a56SJuan Quintela } else {
907c3049a56SJuan Quintela se->instance_id = instance_id;
908c3049a56SJuan Quintela }
909bb25a728SDr. David Alan Gilbert
910bb25a728SDr. David Alan Gilbert /* Perform a recursive sanity check during the test runs */
911bb25a728SDr. David Alan Gilbert if (qtest_enabled()) {
912bb25a728SDr. David Alan Gilbert vmstate_check(vmsd);
913bb25a728SDr. David Alan Gilbert }
914c3049a56SJuan Quintela assert(!se->compat || se->instance_id == 0);
915f37bc036SPeter Xu savevm_state_handler_insert(se);
916c3049a56SJuan Quintela return 0;
917c3049a56SJuan Quintela }
918c3049a56SJuan Quintela
vmstate_unregister(VMStateIf * obj,const VMStateDescription * vmsd,void * opaque)9193cad405bSMarc-André Lureau void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd,
920c3049a56SJuan Quintela void *opaque)
921c3049a56SJuan Quintela {
922c3049a56SJuan Quintela SaveStateEntry *se, *new_se;
923c3049a56SJuan Quintela
9240163a2e0SJuan Quintela QTAILQ_FOREACH_SAFE(se, &savevm_state.handlers, entry, new_se) {
925c3049a56SJuan Quintela if (se->vmsd == vmsd && se->opaque == opaque) {
926bd5de61eSScott Cheloha savevm_state_handler_remove(se);
927c3049a56SJuan Quintela g_free(se->compat);
928c3049a56SJuan Quintela g_free(se);
929c3049a56SJuan Quintela }
930c3049a56SJuan Quintela }
931c3049a56SJuan Quintela }
932c3049a56SJuan Quintela
vmstate_load(QEMUFile * f,SaveStateEntry * se)9333a011c26SJuan Quintela static int vmstate_load(QEMUFile *f, SaveStateEntry *se)
934c3049a56SJuan Quintela {
935c3049a56SJuan Quintela trace_vmstate_load(se->idstr, se->vmsd ? se->vmsd->name : "(old)");
936c3049a56SJuan Quintela if (!se->vmsd) { /* Old style */
9373a011c26SJuan Quintela return se->ops->load_state(f, se->opaque, se->load_version_id);
938c3049a56SJuan Quintela }
9393a011c26SJuan Quintela return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id);
940c3049a56SJuan Quintela }
941c3049a56SJuan Quintela
vmstate_save_old_style(QEMUFile * f,SaveStateEntry * se,JSONWriter * vmdesc)9423ddba9a9SMarkus Armbruster static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se,
9433ddba9a9SMarkus Armbruster JSONWriter *vmdesc)
944c3049a56SJuan Quintela {
945e9c0eed7SJuan Quintela uint64_t old_offset = qemu_file_transferred(f);
946c3049a56SJuan Quintela se->ops->save_state(f, se->opaque);
947e9c0eed7SJuan Quintela uint64_t size = qemu_file_transferred(f) - old_offset;
948c3049a56SJuan Quintela
949c3049a56SJuan Quintela if (vmdesc) {
9503ddba9a9SMarkus Armbruster json_writer_int64(vmdesc, "size", size);
9513ddba9a9SMarkus Armbruster json_writer_start_array(vmdesc, "fields");
9523ddba9a9SMarkus Armbruster json_writer_start_object(vmdesc, NULL);
9533ddba9a9SMarkus Armbruster json_writer_str(vmdesc, "name", "data");
9543ddba9a9SMarkus Armbruster json_writer_int64(vmdesc, "size", size);
9553ddba9a9SMarkus Armbruster json_writer_str(vmdesc, "type", "buffer");
9563ddba9a9SMarkus Armbruster json_writer_end_object(vmdesc);
9573ddba9a9SMarkus Armbruster json_writer_end_array(vmdesc);
958c3049a56SJuan Quintela }
959c3049a56SJuan Quintela }
960c3049a56SJuan Quintela
961ce39bfc9SDr. David Alan Gilbert /*
962ce39bfc9SDr. David Alan Gilbert * Write the header for device section (QEMU_VM_SECTION START/END/PART/FULL)
963ce39bfc9SDr. David Alan Gilbert */
save_section_header(QEMUFile * f,SaveStateEntry * se,uint8_t section_type)964ce39bfc9SDr. David Alan Gilbert static void save_section_header(QEMUFile *f, SaveStateEntry *se,
965ce39bfc9SDr. David Alan Gilbert uint8_t section_type)
966ce39bfc9SDr. David Alan Gilbert {
967ce39bfc9SDr. David Alan Gilbert qemu_put_byte(f, section_type);
968ce39bfc9SDr. David Alan Gilbert qemu_put_be32(f, se->section_id);
969ce39bfc9SDr. David Alan Gilbert
970ce39bfc9SDr. David Alan Gilbert if (section_type == QEMU_VM_SECTION_FULL ||
971ce39bfc9SDr. David Alan Gilbert section_type == QEMU_VM_SECTION_START) {
972ce39bfc9SDr. David Alan Gilbert /* ID string */
973ce39bfc9SDr. David Alan Gilbert size_t len = strlen(se->idstr);
974ce39bfc9SDr. David Alan Gilbert qemu_put_byte(f, len);
975ce39bfc9SDr. David Alan Gilbert qemu_put_buffer(f, (uint8_t *)se->idstr, len);
976ce39bfc9SDr. David Alan Gilbert
977ce39bfc9SDr. David Alan Gilbert qemu_put_be32(f, se->instance_id);
978ce39bfc9SDr. David Alan Gilbert qemu_put_be32(f, se->version_id);
979ce39bfc9SDr. David Alan Gilbert }
980ce39bfc9SDr. David Alan Gilbert }
981ce39bfc9SDr. David Alan Gilbert
982f68945d4SDr. David Alan Gilbert /*
983f68945d4SDr. David Alan Gilbert * Write a footer onto device sections that catches cases misformatted device
984f68945d4SDr. David Alan Gilbert * sections.
985f68945d4SDr. David Alan Gilbert */
save_section_footer(QEMUFile * f,SaveStateEntry * se)986f68945d4SDr. David Alan Gilbert static void save_section_footer(QEMUFile *f, SaveStateEntry *se)
987f68945d4SDr. David Alan Gilbert {
98815c38503SPeter Xu if (migrate_get_current()->send_section_footer) {
989f68945d4SDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_SECTION_FOOTER);
990f68945d4SDr. David Alan Gilbert qemu_put_be32(f, se->section_id);
991f68945d4SDr. David Alan Gilbert }
992f68945d4SDr. David Alan Gilbert }
993f68945d4SDr. David Alan Gilbert
vmstate_save(QEMUFile * f,SaveStateEntry * se,JSONWriter * vmdesc,Error ** errp)9946138d43aSCédric Le Goater static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc,
9956138d43aSCédric Le Goater Error **errp)
9965e104f24SDavid Hildenbrand {
9975e104f24SDavid Hildenbrand int ret;
9985e104f24SDavid Hildenbrand
9995e104f24SDavid Hildenbrand if ((!se->ops || !se->ops->save_state) && !se->vmsd) {
10005e104f24SDavid Hildenbrand return 0;
10015e104f24SDavid Hildenbrand }
10024d8bdc2aSMarc-André Lureau if (se->vmsd && !vmstate_section_needed(se->vmsd, se->opaque)) {
10035e104f24SDavid Hildenbrand trace_savevm_section_skip(se->idstr, se->section_id);
10045e104f24SDavid Hildenbrand return 0;
10055e104f24SDavid Hildenbrand }
10065e104f24SDavid Hildenbrand
10075e104f24SDavid Hildenbrand trace_savevm_section_start(se->idstr, se->section_id);
10085e104f24SDavid Hildenbrand save_section_header(f, se, QEMU_VM_SECTION_FULL);
10095e104f24SDavid Hildenbrand if (vmdesc) {
10105e104f24SDavid Hildenbrand json_writer_start_object(vmdesc, NULL);
10115e104f24SDavid Hildenbrand json_writer_str(vmdesc, "name", se->idstr);
10125e104f24SDavid Hildenbrand json_writer_int64(vmdesc, "instance_id", se->instance_id);
10135e104f24SDavid Hildenbrand }
10145e104f24SDavid Hildenbrand
10155e104f24SDavid Hildenbrand trace_vmstate_save(se->idstr, se->vmsd ? se->vmsd->name : "(old)");
10165e104f24SDavid Hildenbrand if (!se->vmsd) {
10175e104f24SDavid Hildenbrand vmstate_save_old_style(f, se, vmdesc);
10185e104f24SDavid Hildenbrand } else {
10196138d43aSCédric Le Goater ret = vmstate_save_state_with_err(f, se->vmsd, se->opaque, vmdesc,
10206138d43aSCédric Le Goater errp);
10215e104f24SDavid Hildenbrand if (ret) {
10225e104f24SDavid Hildenbrand return ret;
10235e104f24SDavid Hildenbrand }
10245e104f24SDavid Hildenbrand }
10255e104f24SDavid Hildenbrand
10265e104f24SDavid Hildenbrand trace_savevm_section_end(se->idstr, se->section_id, 0);
10275e104f24SDavid Hildenbrand save_section_footer(f, se);
10285e104f24SDavid Hildenbrand if (vmdesc) {
10295e104f24SDavid Hildenbrand json_writer_end_object(vmdesc);
10305e104f24SDavid Hildenbrand }
10315e104f24SDavid Hildenbrand return 0;
10325e104f24SDavid Hildenbrand }
1033c76ca188SDr. David Alan Gilbert /**
1034c76ca188SDr. David Alan Gilbert * qemu_savevm_command_send: Send a 'QEMU_VM_COMMAND' type element with the
1035c76ca188SDr. David Alan Gilbert * command and associated data.
1036c76ca188SDr. David Alan Gilbert *
1037c76ca188SDr. David Alan Gilbert * @f: File to send command on
1038c76ca188SDr. David Alan Gilbert * @command: Command type to send
1039c76ca188SDr. David Alan Gilbert * @len: Length of associated data
1040c76ca188SDr. David Alan Gilbert * @data: Data associated with command.
1041c76ca188SDr. David Alan Gilbert */
qemu_savevm_command_send(QEMUFile * f,enum qemu_vm_cmd command,uint16_t len,uint8_t * data)104220a519a0SJuan Quintela static void qemu_savevm_command_send(QEMUFile *f,
1043c76ca188SDr. David Alan Gilbert enum qemu_vm_cmd command,
1044c76ca188SDr. David Alan Gilbert uint16_t len,
1045c76ca188SDr. David Alan Gilbert uint8_t *data)
1046c76ca188SDr. David Alan Gilbert {
1047c76ca188SDr. David Alan Gilbert trace_savevm_command_send(command, len);
1048c76ca188SDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_COMMAND);
1049c76ca188SDr. David Alan Gilbert qemu_put_be16(f, (uint16_t)command);
1050c76ca188SDr. David Alan Gilbert qemu_put_be16(f, len);
1051c76ca188SDr. David Alan Gilbert qemu_put_buffer(f, data, len);
1052c76ca188SDr. David Alan Gilbert qemu_fflush(f);
1053c76ca188SDr. David Alan Gilbert }
1054c76ca188SDr. David Alan Gilbert
qemu_savevm_send_colo_enable(QEMUFile * f)1055aad555c2SZhang Chen void qemu_savevm_send_colo_enable(QEMUFile *f)
1056aad555c2SZhang Chen {
1057aad555c2SZhang Chen trace_savevm_send_colo_enable();
1058aad555c2SZhang Chen qemu_savevm_command_send(f, MIG_CMD_ENABLE_COLO, 0, NULL);
1059aad555c2SZhang Chen }
1060aad555c2SZhang Chen
qemu_savevm_send_ping(QEMUFile * f,uint32_t value)10612e37701eSDr. David Alan Gilbert void qemu_savevm_send_ping(QEMUFile *f, uint32_t value)
10622e37701eSDr. David Alan Gilbert {
10632e37701eSDr. David Alan Gilbert uint32_t buf;
10642e37701eSDr. David Alan Gilbert
10652e37701eSDr. David Alan Gilbert trace_savevm_send_ping(value);
10662e37701eSDr. David Alan Gilbert buf = cpu_to_be32(value);
10672e37701eSDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_PING, sizeof(value), (uint8_t *)&buf);
10682e37701eSDr. David Alan Gilbert }
10692e37701eSDr. David Alan Gilbert
qemu_savevm_send_open_return_path(QEMUFile * f)10702e37701eSDr. David Alan Gilbert void qemu_savevm_send_open_return_path(QEMUFile *f)
10712e37701eSDr. David Alan Gilbert {
10722e37701eSDr. David Alan Gilbert trace_savevm_send_open_return_path();
10732e37701eSDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_OPEN_RETURN_PATH, 0, NULL);
10742e37701eSDr. David Alan Gilbert }
10752e37701eSDr. David Alan Gilbert
107611cf1d98SDr. David Alan Gilbert /* We have a buffer of data to send; we don't want that all to be loaded
107711cf1d98SDr. David Alan Gilbert * by the command itself, so the command contains just the length of the
107811cf1d98SDr. David Alan Gilbert * extra buffer that we then send straight after it.
107911cf1d98SDr. David Alan Gilbert * TODO: Must be a better way to organise that
108011cf1d98SDr. David Alan Gilbert *
108111cf1d98SDr. David Alan Gilbert * Returns:
108211cf1d98SDr. David Alan Gilbert * 0 on success
108311cf1d98SDr. David Alan Gilbert * -ve on error
108411cf1d98SDr. David Alan Gilbert */
qemu_savevm_send_packaged(QEMUFile * f,const uint8_t * buf,size_t len)108561b67d47SDaniel P. Berrange int qemu_savevm_send_packaged(QEMUFile *f, const uint8_t *buf, size_t len)
108611cf1d98SDr. David Alan Gilbert {
108711cf1d98SDr. David Alan Gilbert uint32_t tmp;
1088848a0503STejus GK MigrationState *ms = migrate_get_current();
1089848a0503STejus GK Error *local_err = NULL;
109011cf1d98SDr. David Alan Gilbert
109111cf1d98SDr. David Alan Gilbert if (len > MAX_VM_CMD_PACKAGED_SIZE) {
1092848a0503STejus GK error_setg(&local_err, "%s: Unreasonably large packaged state: %zu",
109311cf1d98SDr. David Alan Gilbert __func__, len);
1094848a0503STejus GK migrate_set_error(ms, local_err);
1095848a0503STejus GK error_report_err(local_err);
109611cf1d98SDr. David Alan Gilbert return -1;
109711cf1d98SDr. David Alan Gilbert }
109811cf1d98SDr. David Alan Gilbert
109911cf1d98SDr. David Alan Gilbert tmp = cpu_to_be32(len);
110011cf1d98SDr. David Alan Gilbert
110111cf1d98SDr. David Alan Gilbert trace_qemu_savevm_send_packaged();
110211cf1d98SDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_PACKAGED, 4, (uint8_t *)&tmp);
110311cf1d98SDr. David Alan Gilbert
110461b67d47SDaniel P. Berrange qemu_put_buffer(f, buf, len);
110511cf1d98SDr. David Alan Gilbert
110611cf1d98SDr. David Alan Gilbert return 0;
110711cf1d98SDr. David Alan Gilbert }
110811cf1d98SDr. David Alan Gilbert
1109093e3c42SDr. David Alan Gilbert /* Send prior to any postcopy transfer */
qemu_savevm_send_postcopy_advise(QEMUFile * f)1110093e3c42SDr. David Alan Gilbert void qemu_savevm_send_postcopy_advise(QEMUFile *f)
1111093e3c42SDr. David Alan Gilbert {
111258110f0aSVladimir Sementsov-Ogievskiy if (migrate_postcopy_ram()) {
1113093e3c42SDr. David Alan Gilbert uint64_t tmp[2];
1114e8ca1db2SDr. David Alan Gilbert tmp[0] = cpu_to_be64(ram_pagesize_summary());
111520afaed9SJuan Quintela tmp[1] = cpu_to_be64(qemu_target_page_size());
1116093e3c42SDr. David Alan Gilbert
1117093e3c42SDr. David Alan Gilbert trace_qemu_savevm_send_postcopy_advise();
111858110f0aSVladimir Sementsov-Ogievskiy qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_ADVISE,
111958110f0aSVladimir Sementsov-Ogievskiy 16, (uint8_t *)tmp);
112058110f0aSVladimir Sementsov-Ogievskiy } else {
112158110f0aSVladimir Sementsov-Ogievskiy qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_ADVISE, 0, NULL);
112258110f0aSVladimir Sementsov-Ogievskiy }
1123093e3c42SDr. David Alan Gilbert }
1124093e3c42SDr. David Alan Gilbert
1125093e3c42SDr. David Alan Gilbert /* Sent prior to starting the destination running in postcopy, discard pages
1126093e3c42SDr. David Alan Gilbert * that have already been sent but redirtied on the source.
1127093e3c42SDr. David Alan Gilbert * CMD_POSTCOPY_RAM_DISCARD consist of:
1128093e3c42SDr. David Alan Gilbert * byte version (0)
1129093e3c42SDr. David Alan Gilbert * byte Length of name field (not including 0)
1130093e3c42SDr. David Alan Gilbert * n x byte RAM block name
1131093e3c42SDr. David Alan Gilbert * byte 0 terminator (just for safety)
1132093e3c42SDr. David Alan Gilbert * n x Byte ranges within the named RAMBlock
1133093e3c42SDr. David Alan Gilbert * be64 Start of the range
1134093e3c42SDr. David Alan Gilbert * be64 Length
1135093e3c42SDr. David Alan Gilbert *
1136093e3c42SDr. David Alan Gilbert * name: RAMBlock name that these entries are part of
1137093e3c42SDr. David Alan Gilbert * len: Number of page entries
1138093e3c42SDr. David Alan Gilbert * start_list: 'len' addresses
1139093e3c42SDr. David Alan Gilbert * length_list: 'len' addresses
1140093e3c42SDr. David Alan Gilbert *
1141093e3c42SDr. 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)1142093e3c42SDr. David Alan Gilbert void qemu_savevm_send_postcopy_ram_discard(QEMUFile *f, const char *name,
1143093e3c42SDr. David Alan Gilbert uint16_t len,
1144093e3c42SDr. David Alan Gilbert uint64_t *start_list,
1145093e3c42SDr. David Alan Gilbert uint64_t *length_list)
1146093e3c42SDr. David Alan Gilbert {
1147093e3c42SDr. David Alan Gilbert uint8_t *buf;
1148093e3c42SDr. David Alan Gilbert uint16_t tmplen;
1149093e3c42SDr. David Alan Gilbert uint16_t t;
1150093e3c42SDr. David Alan Gilbert size_t name_len = strlen(name);
1151093e3c42SDr. David Alan Gilbert
1152093e3c42SDr. David Alan Gilbert trace_qemu_savevm_send_postcopy_ram_discard(name, len);
1153093e3c42SDr. David Alan Gilbert assert(name_len < 256);
1154093e3c42SDr. David Alan Gilbert buf = g_malloc0(1 + 1 + name_len + 1 + (8 + 8) * len);
1155093e3c42SDr. David Alan Gilbert buf[0] = postcopy_ram_discard_version;
1156093e3c42SDr. David Alan Gilbert buf[1] = name_len;
1157093e3c42SDr. David Alan Gilbert memcpy(buf + 2, name, name_len);
1158093e3c42SDr. David Alan Gilbert tmplen = 2 + name_len;
1159093e3c42SDr. David Alan Gilbert buf[tmplen++] = '\0';
1160093e3c42SDr. David Alan Gilbert
1161093e3c42SDr. David Alan Gilbert for (t = 0; t < len; t++) {
11624d885131SPeter Maydell stq_be_p(buf + tmplen, start_list[t]);
1163093e3c42SDr. David Alan Gilbert tmplen += 8;
11644d885131SPeter Maydell stq_be_p(buf + tmplen, length_list[t]);
1165093e3c42SDr. David Alan Gilbert tmplen += 8;
1166093e3c42SDr. David Alan Gilbert }
1167093e3c42SDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_RAM_DISCARD, tmplen, buf);
1168093e3c42SDr. David Alan Gilbert g_free(buf);
1169093e3c42SDr. David Alan Gilbert }
1170093e3c42SDr. David Alan Gilbert
1171093e3c42SDr. David Alan Gilbert /* Get the destination into a state where it can receive postcopy data. */
qemu_savevm_send_postcopy_listen(QEMUFile * f)1172093e3c42SDr. David Alan Gilbert void qemu_savevm_send_postcopy_listen(QEMUFile *f)
1173093e3c42SDr. David Alan Gilbert {
1174093e3c42SDr. David Alan Gilbert trace_savevm_send_postcopy_listen();
1175093e3c42SDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_LISTEN, 0, NULL);
1176093e3c42SDr. David Alan Gilbert }
1177093e3c42SDr. David Alan Gilbert
1178093e3c42SDr. David Alan Gilbert /* Kick the destination into running */
qemu_savevm_send_postcopy_run(QEMUFile * f)1179093e3c42SDr. David Alan Gilbert void qemu_savevm_send_postcopy_run(QEMUFile *f)
1180093e3c42SDr. David Alan Gilbert {
1181093e3c42SDr. David Alan Gilbert trace_savevm_send_postcopy_run();
1182093e3c42SDr. David Alan Gilbert qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_RUN, 0, NULL);
1183093e3c42SDr. David Alan Gilbert }
1184093e3c42SDr. David Alan Gilbert
qemu_savevm_send_postcopy_resume(QEMUFile * f)11853f5875ecSPeter Xu void qemu_savevm_send_postcopy_resume(QEMUFile *f)
11863f5875ecSPeter Xu {
11873f5875ecSPeter Xu trace_savevm_send_postcopy_resume();
11883f5875ecSPeter Xu qemu_savevm_command_send(f, MIG_CMD_POSTCOPY_RESUME, 0, NULL);
11893f5875ecSPeter Xu }
11903f5875ecSPeter Xu
qemu_savevm_send_recv_bitmap(QEMUFile * f,char * block_name)1191f25d4225SPeter Xu void qemu_savevm_send_recv_bitmap(QEMUFile *f, char *block_name)
1192f25d4225SPeter Xu {
1193f25d4225SPeter Xu size_t len;
1194f25d4225SPeter Xu char buf[256];
1195f25d4225SPeter Xu
1196f25d4225SPeter Xu trace_savevm_send_recv_bitmap(block_name);
1197f25d4225SPeter Xu
1198f25d4225SPeter Xu buf[0] = len = strlen(block_name);
1199f25d4225SPeter Xu memcpy(buf + 1, block_name, len);
1200f25d4225SPeter Xu
1201f25d4225SPeter Xu qemu_savevm_command_send(f, MIG_CMD_RECV_BITMAP, len + 1, (uint8_t *)buf);
1202f25d4225SPeter Xu }
1203f25d4225SPeter Xu
qemu_savevm_state_blocked(Error ** errp)1204c3049a56SJuan Quintela bool qemu_savevm_state_blocked(Error **errp)
1205c3049a56SJuan Quintela {
1206c3049a56SJuan Quintela SaveStateEntry *se;
1207c3049a56SJuan Quintela
12080163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1209c3049a56SJuan Quintela if (se->vmsd && se->vmsd->unmigratable) {
1210c3049a56SJuan Quintela error_setg(errp, "State blocked by non-migratable device '%s'",
1211c3049a56SJuan Quintela se->idstr);
1212c3049a56SJuan Quintela return true;
1213c3049a56SJuan Quintela }
1214c3049a56SJuan Quintela }
1215c3049a56SJuan Quintela return false;
1216c3049a56SJuan Quintela }
1217c3049a56SJuan Quintela
qemu_savevm_non_migratable_list(strList ** reasons)12183af8554bSDr. David Alan Gilbert void qemu_savevm_non_migratable_list(strList **reasons)
12193af8554bSDr. David Alan Gilbert {
12203af8554bSDr. David Alan Gilbert SaveStateEntry *se;
12213af8554bSDr. David Alan Gilbert
12223af8554bSDr. David Alan Gilbert QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
12233af8554bSDr. David Alan Gilbert if (se->vmsd && se->vmsd->unmigratable) {
12243af8554bSDr. David Alan Gilbert QAPI_LIST_PREPEND(*reasons,
12253af8554bSDr. David Alan Gilbert g_strdup_printf("non-migratable device: %s",
12263af8554bSDr. David Alan Gilbert se->idstr));
12273af8554bSDr. David Alan Gilbert }
12283af8554bSDr. David Alan Gilbert }
12293af8554bSDr. David Alan Gilbert }
12303af8554bSDr. David Alan Gilbert
qemu_savevm_state_header(QEMUFile * f)1231f796baa1SDr. David Alan Gilbert void qemu_savevm_state_header(QEMUFile *f)
1232f796baa1SDr. David Alan Gilbert {
12332aae1eb8SNikolay Borisov MigrationState *s = migrate_get_current();
12342aae1eb8SNikolay Borisov
12352aae1eb8SNikolay Borisov s->vmdesc = json_writer_new(false);
12362aae1eb8SNikolay Borisov
1237f796baa1SDr. David Alan Gilbert trace_savevm_state_header();
1238f796baa1SDr. David Alan Gilbert qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
1239f796baa1SDr. David Alan Gilbert qemu_put_be32(f, QEMU_VM_FILE_VERSION);
1240172dfd4fSDr. David Alan Gilbert
12412aae1eb8SNikolay Borisov if (s->send_configuration) {
1242172dfd4fSDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_CONFIGURATION);
12432aae1eb8SNikolay Borisov
12442aae1eb8SNikolay Borisov /*
12452aae1eb8SNikolay Borisov * This starts the main json object and is paired with the
12462aae1eb8SNikolay Borisov * json_writer_end_object in
12472aae1eb8SNikolay Borisov * qemu_savevm_state_complete_precopy_non_iterable
12482aae1eb8SNikolay Borisov */
12492aae1eb8SNikolay Borisov json_writer_start_object(s->vmdesc, NULL);
12502aae1eb8SNikolay Borisov
12512aae1eb8SNikolay Borisov json_writer_start_object(s->vmdesc, "configuration");
12522aae1eb8SNikolay Borisov vmstate_save_state(f, &vmstate_configuration, &savevm_state, s->vmdesc);
12532aae1eb8SNikolay Borisov json_writer_end_object(s->vmdesc);
1254172dfd4fSDr. David Alan Gilbert }
1255f796baa1SDr. David Alan Gilbert }
1256f796baa1SDr. David Alan Gilbert
qemu_savevm_state_guest_unplug_pending(void)1257d05de9e3SKeqian Zhu bool qemu_savevm_state_guest_unplug_pending(void)
1258c7e0acd5SJens Freimann {
1259c7e0acd5SJens Freimann SaveStateEntry *se;
1260c7e0acd5SJens Freimann
1261c7e0acd5SJens Freimann QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1262284f42a5SJens Freimann if (se->vmsd && se->vmsd->dev_unplug_pending &&
1263284f42a5SJens Freimann se->vmsd->dev_unplug_pending(se->opaque)) {
1264d05de9e3SKeqian Zhu return true;
1265c7e0acd5SJens Freimann }
1266c7e0acd5SJens Freimann }
1267c7e0acd5SJens Freimann
1268d05de9e3SKeqian Zhu return false;
1269c7e0acd5SJens Freimann }
1270c7e0acd5SJens Freimann
qemu_savevm_state_prepare(Error ** errp)127108fc4cb5SAvihai Horon int qemu_savevm_state_prepare(Error **errp)
127208fc4cb5SAvihai Horon {
127308fc4cb5SAvihai Horon SaveStateEntry *se;
127408fc4cb5SAvihai Horon int ret;
127508fc4cb5SAvihai Horon
127608fc4cb5SAvihai Horon QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
127708fc4cb5SAvihai Horon if (!se->ops || !se->ops->save_prepare) {
127808fc4cb5SAvihai Horon continue;
127908fc4cb5SAvihai Horon }
128008fc4cb5SAvihai Horon if (se->ops->is_active) {
128108fc4cb5SAvihai Horon if (!se->ops->is_active(se->opaque)) {
128208fc4cb5SAvihai Horon continue;
128308fc4cb5SAvihai Horon }
128408fc4cb5SAvihai Horon }
128508fc4cb5SAvihai Horon
128608fc4cb5SAvihai Horon ret = se->ops->save_prepare(se->opaque, errp);
128708fc4cb5SAvihai Horon if (ret < 0) {
128808fc4cb5SAvihai Horon return ret;
128908fc4cb5SAvihai Horon }
129008fc4cb5SAvihai Horon }
129108fc4cb5SAvihai Horon
129208fc4cb5SAvihai Horon return 0;
129308fc4cb5SAvihai Horon }
129408fc4cb5SAvihai Horon
qemu_savevm_state_setup(QEMUFile * f,Error ** errp)1295057a2009SCédric Le Goater int qemu_savevm_state_setup(QEMUFile *f, Error **errp)
1296c3049a56SJuan Quintela {
1297057a2009SCédric Le Goater ERRP_GUARD();
1298e3bf5e68SDavid Hildenbrand MigrationState *ms = migrate_get_current();
1299c3049a56SJuan Quintela SaveStateEntry *se;
1300e6e08e83SCédric Le Goater int ret = 0;
1301c3049a56SJuan Quintela
1302e3bf5e68SDavid Hildenbrand json_writer_int64(ms->vmdesc, "page_size", qemu_target_page_size());
1303e3bf5e68SDavid Hildenbrand json_writer_start_array(ms->vmdesc, "devices");
1304e3bf5e68SDavid Hildenbrand
13059907e842SJuan Quintela trace_savevm_state_setup();
13060163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
130762f42625SDavid Hildenbrand if (se->vmsd && se->vmsd->early_setup) {
1308057a2009SCédric Le Goater ret = vmstate_save(f, se, ms->vmdesc, errp);
130962f42625SDavid Hildenbrand if (ret) {
1310057a2009SCédric Le Goater migrate_set_error(ms, *errp);
131162f42625SDavid Hildenbrand qemu_file_set_error(f, ret);
131262f42625SDavid Hildenbrand break;
131362f42625SDavid Hildenbrand }
131462f42625SDavid Hildenbrand continue;
131562f42625SDavid Hildenbrand }
131662f42625SDavid Hildenbrand
13179907e842SJuan Quintela if (!se->ops || !se->ops->save_setup) {
1318c3049a56SJuan Quintela continue;
1319c3049a56SJuan Quintela }
1320cea3b4c0SWei Yang if (se->ops->is_active) {
1321c3049a56SJuan Quintela if (!se->ops->is_active(se->opaque)) {
1322c3049a56SJuan Quintela continue;
1323c3049a56SJuan Quintela }
1324c3049a56SJuan Quintela }
1325ce39bfc9SDr. David Alan Gilbert save_section_header(f, se, QEMU_VM_SECTION_START);
1326c3049a56SJuan Quintela
132701c3ac68SCédric Le Goater ret = se->ops->save_setup(f, se->opaque, errp);
1328f68945d4SDr. David Alan Gilbert save_section_footer(f, se);
1329c3049a56SJuan Quintela if (ret < 0) {
1330c3049a56SJuan Quintela qemu_file_set_error(f, ret);
1331c3049a56SJuan Quintela break;
1332c3049a56SJuan Quintela }
1333c3049a56SJuan Quintela }
1334bd227060SWei Wang
1335e6e08e83SCédric Le Goater if (ret) {
1336057a2009SCédric Le Goater return ret;
1337e6e08e83SCédric Le Goater }
1338e6e08e83SCédric Le Goater
1339057a2009SCédric Le Goater /* TODO: Should we check that errp is set in case of failure ? */
1340057a2009SCédric Le Goater return precopy_notify(PRECOPY_NOTIFY_SETUP, errp);
1341c3049a56SJuan Quintela }
1342c3049a56SJuan Quintela
qemu_savevm_state_resume_prepare(MigrationState * s)1343d1b8eadbSPeter Xu int qemu_savevm_state_resume_prepare(MigrationState *s)
1344d1b8eadbSPeter Xu {
1345d1b8eadbSPeter Xu SaveStateEntry *se;
1346d1b8eadbSPeter Xu int ret;
1347d1b8eadbSPeter Xu
1348d1b8eadbSPeter Xu trace_savevm_state_resume_prepare();
1349d1b8eadbSPeter Xu
1350d1b8eadbSPeter Xu QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1351d1b8eadbSPeter Xu if (!se->ops || !se->ops->resume_prepare) {
1352d1b8eadbSPeter Xu continue;
1353d1b8eadbSPeter Xu }
1354cea3b4c0SWei Yang if (se->ops->is_active) {
1355d1b8eadbSPeter Xu if (!se->ops->is_active(se->opaque)) {
1356d1b8eadbSPeter Xu continue;
1357d1b8eadbSPeter Xu }
1358d1b8eadbSPeter Xu }
1359d1b8eadbSPeter Xu ret = se->ops->resume_prepare(s, se->opaque);
1360d1b8eadbSPeter Xu if (ret < 0) {
1361d1b8eadbSPeter Xu return ret;
1362d1b8eadbSPeter Xu }
1363d1b8eadbSPeter Xu }
1364d1b8eadbSPeter Xu
1365d1b8eadbSPeter Xu return 0;
1366d1b8eadbSPeter Xu }
1367d1b8eadbSPeter Xu
1368c3049a56SJuan Quintela /*
1369c3049a56SJuan Quintela * this function has three return values:
1370c3049a56SJuan Quintela * negative: there was one error, and we have -errno.
1371c3049a56SJuan Quintela * 0 : We haven't finished, caller have to go again
1372c3049a56SJuan Quintela * 1 : We have finished, we can go to complete phase
1373c3049a56SJuan Quintela */
qemu_savevm_state_iterate(QEMUFile * f,bool postcopy)137435ecd943SDr. David Alan Gilbert int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy)
1375c3049a56SJuan Quintela {
1376c3049a56SJuan Quintela SaveStateEntry *se;
13774e1871c4SAvihai Horon bool all_finished = true;
13784e1871c4SAvihai Horon int ret;
1379c3049a56SJuan Quintela
1380c3049a56SJuan Quintela trace_savevm_state_iterate();
13810163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1382c3049a56SJuan Quintela if (!se->ops || !se->ops->save_live_iterate) {
1383c3049a56SJuan Quintela continue;
1384c3049a56SJuan Quintela }
1385a94cd7b8SWei Yang if (se->ops->is_active &&
1386a94cd7b8SWei Yang !se->ops->is_active(se->opaque)) {
1387c3049a56SJuan Quintela continue;
1388c3049a56SJuan Quintela }
1389a94cd7b8SWei Yang if (se->ops->is_active_iterate &&
1390a94cd7b8SWei Yang !se->ops->is_active_iterate(se->opaque)) {
1391c865d848SVladimir Sementsov-Ogievskiy continue;
1392c865d848SVladimir Sementsov-Ogievskiy }
139335ecd943SDr. David Alan Gilbert /*
139435ecd943SDr. David Alan Gilbert * In the postcopy phase, any device that doesn't know how to
139535ecd943SDr. David Alan Gilbert * do postcopy should have saved it's state in the _complete
139635ecd943SDr. David Alan Gilbert * call that's already run, it might get confused if we call
139735ecd943SDr. David Alan Gilbert * iterate afterwards.
139835ecd943SDr. David Alan Gilbert */
1399c6467627SVladimir Sementsov-Ogievskiy if (postcopy &&
1400c6467627SVladimir Sementsov-Ogievskiy !(se->ops->has_postcopy && se->ops->has_postcopy(se->opaque))) {
140135ecd943SDr. David Alan Gilbert continue;
140235ecd943SDr. David Alan Gilbert }
1403e1fde0e0SJuan Quintela if (migration_rate_exceeded(f)) {
1404c3049a56SJuan Quintela return 0;
1405c3049a56SJuan Quintela }
1406c3049a56SJuan Quintela trace_savevm_section_start(se->idstr, se->section_id);
1407ce39bfc9SDr. David Alan Gilbert
1408ce39bfc9SDr. David Alan Gilbert save_section_header(f, se, QEMU_VM_SECTION_PART);
1409c3049a56SJuan Quintela
1410c3049a56SJuan Quintela ret = se->ops->save_live_iterate(f, se->opaque);
1411c3049a56SJuan Quintela trace_savevm_section_end(se->idstr, se->section_id, ret);
1412f68945d4SDr. David Alan Gilbert save_section_footer(f, se);
1413c3049a56SJuan Quintela
1414c3049a56SJuan Quintela if (ret < 0) {
141592002658SDavid Edmondson error_report("failed to save SaveStateEntry with id(name): "
141692002658SDavid Edmondson "%d(%s): %d",
141792002658SDavid Edmondson se->section_id, se->idstr, ret);
1418c3049a56SJuan Quintela qemu_file_set_error(f, ret);
1419c3049a56SJuan Quintela return ret;
14204e1871c4SAvihai Horon } else if (!ret) {
14214e1871c4SAvihai Horon all_finished = false;
14224e1871c4SAvihai Horon }
14234e1871c4SAvihai Horon }
14244e1871c4SAvihai Horon return all_finished;
1425c3049a56SJuan Quintela }
1426c3049a56SJuan Quintela
should_send_vmdesc(void)1427c3049a56SJuan Quintela static bool should_send_vmdesc(void)
1428c3049a56SJuan Quintela {
1429c3049a56SJuan Quintela MachineState *machine = MACHINE(qdev_get_machine());
14305727309dSJuan Quintela bool in_postcopy = migration_in_postcopy();
14318421b205SDr. David Alan Gilbert return !machine->suppress_vmdesc && !in_postcopy;
1432c3049a56SJuan Quintela }
1433c3049a56SJuan Quintela
1434763c906bSDr. David Alan Gilbert /*
1435763c906bSDr. David Alan Gilbert * Calls the save_live_complete_postcopy methods
1436763c906bSDr. David Alan Gilbert * causing the last few pages to be sent immediately and doing any associated
1437763c906bSDr. David Alan Gilbert * cleanup.
1438763c906bSDr. David Alan Gilbert * Note postcopy also calls qemu_savevm_state_complete_precopy to complete
1439763c906bSDr. David Alan Gilbert * all the other devices, but that happens at the point we switch to postcopy.
1440763c906bSDr. David Alan Gilbert */
qemu_savevm_state_complete_postcopy(QEMUFile * f)1441763c906bSDr. David Alan Gilbert void qemu_savevm_state_complete_postcopy(QEMUFile *f)
1442763c906bSDr. David Alan Gilbert {
1443763c906bSDr. David Alan Gilbert SaveStateEntry *se;
1444763c906bSDr. David Alan Gilbert int ret;
1445763c906bSDr. David Alan Gilbert
1446763c906bSDr. David Alan Gilbert QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1447763c906bSDr. David Alan Gilbert if (!se->ops || !se->ops->save_live_complete_postcopy) {
1448763c906bSDr. David Alan Gilbert continue;
1449763c906bSDr. David Alan Gilbert }
1450cea3b4c0SWei Yang if (se->ops->is_active) {
1451763c906bSDr. David Alan Gilbert if (!se->ops->is_active(se->opaque)) {
1452763c906bSDr. David Alan Gilbert continue;
1453763c906bSDr. David Alan Gilbert }
1454763c906bSDr. David Alan Gilbert }
1455763c906bSDr. David Alan Gilbert trace_savevm_section_start(se->idstr, se->section_id);
1456763c906bSDr. David Alan Gilbert /* Section type */
1457763c906bSDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_SECTION_END);
1458763c906bSDr. David Alan Gilbert qemu_put_be32(f, se->section_id);
1459763c906bSDr. David Alan Gilbert
1460763c906bSDr. David Alan Gilbert ret = se->ops->save_live_complete_postcopy(f, se->opaque);
1461763c906bSDr. David Alan Gilbert trace_savevm_section_end(se->idstr, se->section_id, ret);
1462763c906bSDr. David Alan Gilbert save_section_footer(f, se);
1463763c906bSDr. David Alan Gilbert if (ret < 0) {
1464763c906bSDr. David Alan Gilbert qemu_file_set_error(f, ret);
1465763c906bSDr. David Alan Gilbert return;
1466763c906bSDr. David Alan Gilbert }
1467763c906bSDr. David Alan Gilbert }
1468763c906bSDr. David Alan Gilbert
1469763c906bSDr. David Alan Gilbert qemu_put_byte(f, QEMU_VM_EOF);
1470763c906bSDr. David Alan Gilbert qemu_fflush(f);
1471763c906bSDr. David Alan Gilbert }
1472763c906bSDr. David Alan Gilbert
1473622a80c9SWei Yang static
qemu_savevm_state_complete_precopy_iterable(QEMUFile * f,bool in_postcopy)1474e326767bSWei Yang int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy)
1475c3049a56SJuan Quintela {
14763c80f142SPeter Xu int64_t start_ts_each, end_ts_each;
1477c3049a56SJuan Quintela SaveStateEntry *se;
1478c3049a56SJuan Quintela int ret;
1479c3049a56SJuan Quintela
14800163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1481763c906bSDr. David Alan Gilbert if (!se->ops ||
1482c6467627SVladimir Sementsov-Ogievskiy (in_postcopy && se->ops->has_postcopy &&
1483c6467627SVladimir Sementsov-Ogievskiy se->ops->has_postcopy(se->opaque)) ||
1484763c906bSDr. David Alan Gilbert !se->ops->save_live_complete_precopy) {
1485c3049a56SJuan Quintela continue;
1486c3049a56SJuan Quintela }
14871c0d249dSDr. David Alan Gilbert
1488cea3b4c0SWei Yang if (se->ops->is_active) {
1489c3049a56SJuan Quintela if (!se->ops->is_active(se->opaque)) {
1490c3049a56SJuan Quintela continue;
1491c3049a56SJuan Quintela }
1492c3049a56SJuan Quintela }
14933c80f142SPeter Xu
14943c80f142SPeter Xu start_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
1495c3049a56SJuan Quintela trace_savevm_section_start(se->idstr, se->section_id);
1496ce39bfc9SDr. David Alan Gilbert
1497ce39bfc9SDr. David Alan Gilbert save_section_header(f, se, QEMU_VM_SECTION_END);
1498c3049a56SJuan Quintela
1499a3e06c3dSDr. David Alan Gilbert ret = se->ops->save_live_complete_precopy(f, se->opaque);
1500c3049a56SJuan Quintela trace_savevm_section_end(se->idstr, se->section_id, ret);
1501f68945d4SDr. David Alan Gilbert save_section_footer(f, se);
1502c3049a56SJuan Quintela if (ret < 0) {
1503c3049a56SJuan Quintela qemu_file_set_error(f, ret);
1504a1fbe750SFam Zheng return -1;
1505c3049a56SJuan Quintela }
15063c80f142SPeter Xu end_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
15073c80f142SPeter Xu trace_vmstate_downtime_save("iterable", se->idstr, se->instance_id,
15083c80f142SPeter Xu end_ts_each - start_ts_each);
1509c3049a56SJuan Quintela }
1510c3049a56SJuan Quintela
15113e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("src-iterable-saved");
15123e5f3bcdSPeter Xu
1513622a80c9SWei Yang return 0;
15141c0d249dSDr. David Alan Gilbert }
15151c0d249dSDr. David Alan Gilbert
qemu_savevm_state_complete_precopy_non_iterable(QEMUFile * f,bool in_postcopy,bool inactivate_disks)1516622a80c9SWei Yang int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f,
1517622a80c9SWei Yang bool in_postcopy,
1518622a80c9SWei Yang bool inactivate_disks)
1519622a80c9SWei Yang {
1520e3bf5e68SDavid Hildenbrand MigrationState *ms = migrate_get_current();
15213c80f142SPeter Xu int64_t start_ts_each, end_ts_each;
1522e3bf5e68SDavid Hildenbrand JSONWriter *vmdesc = ms->vmdesc;
1523622a80c9SWei Yang int vmdesc_len;
1524622a80c9SWei Yang SaveStateEntry *se;
15256138d43aSCédric Le Goater Error *local_err = NULL;
1526622a80c9SWei Yang int ret;
1527622a80c9SWei Yang
15280163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
152962f42625SDavid Hildenbrand if (se->vmsd && se->vmsd->early_setup) {
153062f42625SDavid Hildenbrand /* Already saved during qemu_savevm_state_setup(). */
153162f42625SDavid Hildenbrand continue;
153262f42625SDavid Hildenbrand }
153362f42625SDavid Hildenbrand
15343c80f142SPeter Xu start_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
15353c80f142SPeter Xu
15366138d43aSCédric Le Goater ret = vmstate_save(f, se, vmdesc, &local_err);
1537687433f6SDr. David Alan Gilbert if (ret) {
15386138d43aSCédric Le Goater migrate_set_error(ms, local_err);
15396138d43aSCédric Le Goater error_report_err(local_err);
1540687433f6SDr. David Alan Gilbert qemu_file_set_error(f, ret);
1541687433f6SDr. David Alan Gilbert return ret;
1542687433f6SDr. David Alan Gilbert }
15433c80f142SPeter Xu
15443c80f142SPeter Xu end_ts_each = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
15453c80f142SPeter Xu trace_vmstate_downtime_save("non-iterable", se->idstr, se->instance_id,
15463c80f142SPeter Xu end_ts_each - start_ts_each);
1547c3049a56SJuan Quintela }
1548c3049a56SJuan Quintela
1549a1fbe750SFam Zheng if (inactivate_disks) {
1550a1fbe750SFam Zheng /* Inactivate before sending QEMU_VM_EOF so that the
15513b717194SEmanuele Giuseppe Esposito * bdrv_activate_all() on the other end won't fail. */
1552a1fbe750SFam Zheng ret = bdrv_inactivate_all();
1553a1fbe750SFam Zheng if (ret) {
1554848a0503STejus GK error_setg(&local_err, "%s: bdrv_inactivate_all() failed (%d)",
1555c232bf58SDr. David Alan Gilbert __func__, ret);
1556848a0503STejus GK migrate_set_error(ms, local_err);
1557848a0503STejus GK error_report_err(local_err);
1558a1fbe750SFam Zheng qemu_file_set_error(f, ret);
1559a1fbe750SFam Zheng return ret;
1560a1fbe750SFam Zheng }
1561a1fbe750SFam Zheng }
1562763c906bSDr. David Alan Gilbert if (!in_postcopy) {
1563763c906bSDr. David Alan Gilbert /* Postcopy stream will still be going */
1564c3049a56SJuan Quintela qemu_put_byte(f, QEMU_VM_EOF);
1565763c906bSDr. David Alan Gilbert }
1566c3049a56SJuan Quintela
15673ddba9a9SMarkus Armbruster json_writer_end_array(vmdesc);
15683ddba9a9SMarkus Armbruster json_writer_end_object(vmdesc);
15693ddba9a9SMarkus Armbruster vmdesc_len = strlen(json_writer_get(vmdesc));
1570c3049a56SJuan Quintela
1571c3049a56SJuan Quintela if (should_send_vmdesc()) {
1572c3049a56SJuan Quintela qemu_put_byte(f, QEMU_VM_VMDESCRIPTION);
1573c3049a56SJuan Quintela qemu_put_be32(f, vmdesc_len);
15743ddba9a9SMarkus Armbruster qemu_put_buffer(f, (uint8_t *)json_writer_get(vmdesc), vmdesc_len);
1575c3049a56SJuan Quintela }
1576c3049a56SJuan Quintela
1577e3bf5e68SDavid Hildenbrand /* Free it now to detect any inconsistencies. */
1578e3bf5e68SDavid Hildenbrand json_writer_free(vmdesc);
1579e3bf5e68SDavid Hildenbrand ms->vmdesc = NULL;
1580e3bf5e68SDavid Hildenbrand
15813e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("src-non-iterable-saved");
15823e5f3bcdSPeter Xu
1583622a80c9SWei Yang return 0;
1584622a80c9SWei Yang }
1585622a80c9SWei Yang
qemu_savevm_state_complete_precopy(QEMUFile * f,bool iterable_only,bool inactivate_disks)1586622a80c9SWei Yang int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only,
1587622a80c9SWei Yang bool inactivate_disks)
1588622a80c9SWei Yang {
1589622a80c9SWei Yang int ret;
1590622a80c9SWei Yang Error *local_err = NULL;
1591622a80c9SWei Yang bool in_postcopy = migration_in_postcopy();
1592622a80c9SWei Yang
1593622a80c9SWei Yang if (precopy_notify(PRECOPY_NOTIFY_COMPLETE, &local_err)) {
1594622a80c9SWei Yang error_report_err(local_err);
1595622a80c9SWei Yang }
1596622a80c9SWei Yang
1597622a80c9SWei Yang trace_savevm_state_complete_precopy();
1598622a80c9SWei Yang
1599622a80c9SWei Yang cpu_synchronize_all_states();
1600622a80c9SWei Yang
1601e326767bSWei Yang if (!in_postcopy || iterable_only) {
1602e326767bSWei Yang ret = qemu_savevm_state_complete_precopy_iterable(f, in_postcopy);
1603622a80c9SWei Yang if (ret) {
1604622a80c9SWei Yang return ret;
1605622a80c9SWei Yang }
1606e326767bSWei Yang }
1607622a80c9SWei Yang
1608622a80c9SWei Yang if (iterable_only) {
1609622a80c9SWei Yang goto flush;
1610622a80c9SWei Yang }
1611622a80c9SWei Yang
1612622a80c9SWei Yang ret = qemu_savevm_state_complete_precopy_non_iterable(f, in_postcopy,
1613622a80c9SWei Yang inactivate_disks);
1614622a80c9SWei Yang if (ret) {
1615622a80c9SWei Yang return ret;
1616622a80c9SWei Yang }
1617622a80c9SWei Yang
16184e455d51SWei Yang flush:
1619be07a0edSJuan Quintela return qemu_fflush(f);
1620c3049a56SJuan Quintela }
1621c3049a56SJuan Quintela
1622c31b098fSDr. David Alan Gilbert /* Give an estimate of the amount left to be transferred,
1623c31b098fSDr. David Alan Gilbert * the result is split into the amount for units that can and
1624c31b098fSDr. David Alan Gilbert * for units that can't do postcopy.
1625c31b098fSDr. David Alan Gilbert */
qemu_savevm_state_pending_estimate(uint64_t * must_precopy,uint64_t * can_postcopy)162624beea4eSJuan Quintela void qemu_savevm_state_pending_estimate(uint64_t *must_precopy,
162724beea4eSJuan Quintela uint64_t *can_postcopy)
1628c3049a56SJuan Quintela {
1629c3049a56SJuan Quintela SaveStateEntry *se;
1630c31b098fSDr. David Alan Gilbert
163124beea4eSJuan Quintela *must_precopy = 0;
163224beea4eSJuan Quintela *can_postcopy = 0;
1633c31b098fSDr. David Alan Gilbert
16340163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1635e2647050SJuan Quintela if (!se->ops || !se->ops->state_pending_estimate) {
1636c3049a56SJuan Quintela continue;
1637c3049a56SJuan Quintela }
1638cea3b4c0SWei Yang if (se->ops->is_active) {
1639c3049a56SJuan Quintela if (!se->ops->is_active(se->opaque)) {
1640c3049a56SJuan Quintela continue;
1641c3049a56SJuan Quintela }
1642c3049a56SJuan Quintela }
164324beea4eSJuan Quintela se->ops->state_pending_estimate(se->opaque, must_precopy, can_postcopy);
1644c8df4a7aSJuan Quintela }
1645c8df4a7aSJuan Quintela }
1646c8df4a7aSJuan Quintela
qemu_savevm_state_pending_exact(uint64_t * must_precopy,uint64_t * can_postcopy)164724beea4eSJuan Quintela void qemu_savevm_state_pending_exact(uint64_t *must_precopy,
164824beea4eSJuan Quintela uint64_t *can_postcopy)
1649c8df4a7aSJuan Quintela {
1650c8df4a7aSJuan Quintela SaveStateEntry *se;
1651c8df4a7aSJuan Quintela
165224beea4eSJuan Quintela *must_precopy = 0;
165324beea4eSJuan Quintela *can_postcopy = 0;
1654c8df4a7aSJuan Quintela
1655c8df4a7aSJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1656e2647050SJuan Quintela if (!se->ops || !se->ops->state_pending_exact) {
1657c8df4a7aSJuan Quintela continue;
1658c8df4a7aSJuan Quintela }
1659c8df4a7aSJuan Quintela if (se->ops->is_active) {
1660c8df4a7aSJuan Quintela if (!se->ops->is_active(se->opaque)) {
1661c8df4a7aSJuan Quintela continue;
1662c8df4a7aSJuan Quintela }
1663c8df4a7aSJuan Quintela }
166424beea4eSJuan Quintela se->ops->state_pending_exact(se->opaque, must_precopy, can_postcopy);
1665c3049a56SJuan Quintela }
1666c3049a56SJuan Quintela }
1667c3049a56SJuan Quintela
qemu_savevm_state_cleanup(void)1668ea7415faSLiang Li void qemu_savevm_state_cleanup(void)
1669c3049a56SJuan Quintela {
1670c3049a56SJuan Quintela SaveStateEntry *se;
1671bd227060SWei Wang Error *local_err = NULL;
1672bd227060SWei Wang
1673bd227060SWei Wang if (precopy_notify(PRECOPY_NOTIFY_CLEANUP, &local_err)) {
1674bd227060SWei Wang error_report_err(local_err);
1675bd227060SWei Wang }
1676c3049a56SJuan Quintela
1677ea7415faSLiang Li trace_savevm_state_cleanup();
16780163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
167970f794fcSJuan Quintela if (se->ops && se->ops->save_cleanup) {
168070f794fcSJuan Quintela se->ops->save_cleanup(se->opaque);
1681c3049a56SJuan Quintela }
1682c3049a56SJuan Quintela }
1683c3049a56SJuan Quintela }
1684c3049a56SJuan Quintela
qemu_savevm_state(QEMUFile * f,Error ** errp)1685c3049a56SJuan Quintela static int qemu_savevm_state(QEMUFile *f, Error **errp)
1686c3049a56SJuan Quintela {
1687c3049a56SJuan Quintela int ret;
16883e0c8050SPeter Xu MigrationState *ms = migrate_get_current();
16896dcf6668SDenis V. Lunev MigrationStatus status;
16903e0c8050SPeter Xu
1691aeaafb1eSSteve Sistare if (migration_is_running()) {
169200580786SPhilippe Mathieu-Daudé error_setg(errp, "There's a migration process in progress");
16933d63da16SJia Lina return -EINVAL;
16943d63da16SJia Lina }
1695c3049a56SJuan Quintela
169608fc4cb5SAvihai Horon ret = migrate_init(ms, errp);
169708fc4cb5SAvihai Horon if (ret) {
169808fc4cb5SAvihai Horon return ret;
169908fc4cb5SAvihai Horon }
17003d63da16SJia Lina ms->to_dst_file = f;
17013d63da16SJia Lina
1702f796baa1SDr. David Alan Gilbert qemu_savevm_state_header(f);
1703057a2009SCédric Le Goater ret = qemu_savevm_state_setup(f, errp);
1704057a2009SCédric Le Goater if (ret) {
1705057a2009SCédric Le Goater goto cleanup;
1706057a2009SCédric Le Goater }
1707c3049a56SJuan Quintela
1708c3049a56SJuan Quintela while (qemu_file_get_error(f) == 0) {
170935ecd943SDr. David Alan Gilbert if (qemu_savevm_state_iterate(f, false) > 0) {
1710c3049a56SJuan Quintela break;
1711c3049a56SJuan Quintela }
1712c3049a56SJuan Quintela }
1713c3049a56SJuan Quintela
1714c3049a56SJuan Quintela ret = qemu_file_get_error(f);
1715c3049a56SJuan Quintela if (ret == 0) {
1716a1fbe750SFam Zheng qemu_savevm_state_complete_precopy(f, false, false);
1717c3049a56SJuan Quintela ret = qemu_file_get_error(f);
1718c3049a56SJuan Quintela }
171915b3b8eaSDenis V. Lunev if (ret != 0) {
1720c3049a56SJuan Quintela error_setg_errno(errp, -ret, "Error while writing VM state");
1721c3049a56SJuan Quintela }
1722057a2009SCédric Le Goater cleanup:
1723057a2009SCédric Le Goater qemu_savevm_state_cleanup();
17246dcf6668SDenis V. Lunev
17256dcf6668SDenis V. Lunev if (ret != 0) {
17266dcf6668SDenis V. Lunev status = MIGRATION_STATUS_FAILED;
17276dcf6668SDenis V. Lunev } else {
17286dcf6668SDenis V. Lunev status = MIGRATION_STATUS_COMPLETED;
17296dcf6668SDenis V. Lunev }
17306dcf6668SDenis V. Lunev migrate_set_state(&ms->state, MIGRATION_STATUS_SETUP, status);
1731f9c8caa0SVladimir Sementsov-Ogievskiy
1732f9c8caa0SVladimir Sementsov-Ogievskiy /* f is outer parameter, it should not stay in global migration state after
1733f9c8caa0SVladimir Sementsov-Ogievskiy * this function finished */
1734f9c8caa0SVladimir Sementsov-Ogievskiy ms->to_dst_file = NULL;
1735f9c8caa0SVladimir Sementsov-Ogievskiy
1736c3049a56SJuan Quintela return ret;
1737c3049a56SJuan Quintela }
1738c3049a56SJuan Quintela
qemu_savevm_live_state(QEMUFile * f)17393f6df99dSZhang Chen void qemu_savevm_live_state(QEMUFile *f)
17403f6df99dSZhang Chen {
17413f6df99dSZhang Chen /* save QEMU_VM_SECTION_END section */
17423f6df99dSZhang Chen qemu_savevm_state_complete_precopy(f, true, false);
17433f6df99dSZhang Chen qemu_put_byte(f, QEMU_VM_EOF);
17443f6df99dSZhang Chen }
17453f6df99dSZhang Chen
qemu_save_device_state(QEMUFile * f)17463f6df99dSZhang Chen int qemu_save_device_state(QEMUFile *f)
1747c3049a56SJuan Quintela {
17486138d43aSCédric Le Goater MigrationState *ms = migrate_get_current();
17496138d43aSCédric Le Goater Error *local_err = NULL;
1750c3049a56SJuan Quintela SaveStateEntry *se;
1751c3049a56SJuan Quintela
17523f6df99dSZhang Chen if (!migration_in_colo_state()) {
1753c3049a56SJuan Quintela qemu_put_be32(f, QEMU_VM_FILE_MAGIC);
1754c3049a56SJuan Quintela qemu_put_be32(f, QEMU_VM_FILE_VERSION);
17553f6df99dSZhang Chen }
1756c3049a56SJuan Quintela cpu_synchronize_all_states();
1757c3049a56SJuan Quintela
17580163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1759687433f6SDr. David Alan Gilbert int ret;
1760687433f6SDr. David Alan Gilbert
1761c3049a56SJuan Quintela if (se->is_ram) {
1762c3049a56SJuan Quintela continue;
1763c3049a56SJuan Quintela }
17646138d43aSCédric Le Goater ret = vmstate_save(f, se, NULL, &local_err);
1765687433f6SDr. David Alan Gilbert if (ret) {
17666138d43aSCédric Le Goater migrate_set_error(ms, local_err);
17676138d43aSCédric Le Goater error_report_err(local_err);
1768687433f6SDr. David Alan Gilbert return ret;
1769687433f6SDr. David Alan Gilbert }
1770c3049a56SJuan Quintela }
1771c3049a56SJuan Quintela
1772c3049a56SJuan Quintela qemu_put_byte(f, QEMU_VM_EOF);
1773c3049a56SJuan Quintela
1774c3049a56SJuan Quintela return qemu_file_get_error(f);
1775c3049a56SJuan Quintela }
1776c3049a56SJuan Quintela
find_se(const char * idstr,uint32_t instance_id)177793062e23SPeter Xu static SaveStateEntry *find_se(const char *idstr, uint32_t instance_id)
1778c3049a56SJuan Quintela {
1779c3049a56SJuan Quintela SaveStateEntry *se;
1780c3049a56SJuan Quintela
17810163a2e0SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
1782c3049a56SJuan Quintela if (!strcmp(se->idstr, idstr) &&
1783c3049a56SJuan Quintela (instance_id == se->instance_id ||
1784c3049a56SJuan Quintela instance_id == se->alias_id))
1785c3049a56SJuan Quintela return se;
1786c3049a56SJuan Quintela /* Migrating from an older version? */
1787c3049a56SJuan Quintela if (strstr(se->idstr, idstr) && se->compat) {
1788c3049a56SJuan Quintela if (!strcmp(se->compat->idstr, idstr) &&
1789c3049a56SJuan Quintela (instance_id == se->compat->instance_id ||
1790c3049a56SJuan Quintela instance_id == se->alias_id))
1791c3049a56SJuan Quintela return se;
1792c3049a56SJuan Quintela }
1793c3049a56SJuan Quintela }
1794c3049a56SJuan Quintela return NULL;
1795c3049a56SJuan Quintela }
1796c3049a56SJuan Quintela
17977b89bf27SDr. David Alan Gilbert enum LoadVMExitCodes {
17987b89bf27SDr. David Alan Gilbert /* Allow a command to quit all layers of nested loadvm loops */
17997b89bf27SDr. David Alan Gilbert LOADVM_QUIT = 1,
18007b89bf27SDr. David Alan Gilbert };
18017b89bf27SDr. David Alan Gilbert
1802093e3c42SDr. David Alan Gilbert /* ------ incoming postcopy messages ------ */
1803093e3c42SDr. David Alan Gilbert /* 'advise' arrives before any transfers just to tell us that a postcopy
1804093e3c42SDr. David Alan Gilbert * *might* happen - it might be skipped if precopy transferred everything
1805093e3c42SDr. David Alan Gilbert * quickly.
1806093e3c42SDr. David Alan Gilbert */
loadvm_postcopy_handle_advise(MigrationIncomingState * mis,uint16_t len)1807875fcd01SGreg Kurz static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
1808875fcd01SGreg Kurz uint16_t len)
1809093e3c42SDr. David Alan Gilbert {
1810093e3c42SDr. David Alan Gilbert PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE);
1811e8ca1db2SDr. David Alan Gilbert uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps;
1812144fa06bSJuan Quintela size_t page_size = qemu_target_page_size();
1813d3dff7a5SDr. David Alan Gilbert Error *local_err = NULL;
1814093e3c42SDr. David Alan Gilbert
1815093e3c42SDr. David Alan Gilbert trace_loadvm_postcopy_handle_advise();
1816093e3c42SDr. David Alan Gilbert if (ps != POSTCOPY_INCOMING_NONE) {
1817093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_ADVISE in wrong postcopy state (%d)", ps);
1818093e3c42SDr. David Alan Gilbert return -1;
1819093e3c42SDr. David Alan Gilbert }
1820093e3c42SDr. David Alan Gilbert
1821875fcd01SGreg Kurz switch (len) {
1822875fcd01SGreg Kurz case 0:
1823875fcd01SGreg Kurz if (migrate_postcopy_ram()) {
1824875fcd01SGreg Kurz error_report("RAM postcopy is enabled but have 0 byte advise");
1825875fcd01SGreg Kurz return -EINVAL;
1826875fcd01SGreg Kurz }
182758110f0aSVladimir Sementsov-Ogievskiy return 0;
1828875fcd01SGreg Kurz case 8 + 8:
1829875fcd01SGreg Kurz if (!migrate_postcopy_ram()) {
1830875fcd01SGreg Kurz error_report("RAM postcopy is disabled but have 16 byte advise");
1831875fcd01SGreg Kurz return -EINVAL;
1832875fcd01SGreg Kurz }
1833875fcd01SGreg Kurz break;
1834875fcd01SGreg Kurz default:
1835875fcd01SGreg Kurz error_report("CMD_POSTCOPY_ADVISE invalid length (%d)", len);
1836875fcd01SGreg Kurz return -EINVAL;
183758110f0aSVladimir Sementsov-Ogievskiy }
183858110f0aSVladimir Sementsov-Ogievskiy
183974c38cf7SPeter Xu if (!postcopy_ram_supported_by_host(mis, &local_err)) {
184074c38cf7SPeter Xu error_report_err(local_err);
1841328d4d85SDr. David Alan Gilbert postcopy_state_set(POSTCOPY_INCOMING_NONE);
1842eb59db53SDr. David Alan Gilbert return -1;
1843eb59db53SDr. David Alan Gilbert }
1844eb59db53SDr. David Alan Gilbert
1845e8ca1db2SDr. David Alan Gilbert remote_pagesize_summary = qemu_get_be64(mis->from_src_file);
1846e8ca1db2SDr. David Alan Gilbert local_pagesize_summary = ram_pagesize_summary();
1847e8ca1db2SDr. David Alan Gilbert
1848e8ca1db2SDr. David Alan Gilbert if (remote_pagesize_summary != local_pagesize_summary) {
1849093e3c42SDr. David Alan Gilbert /*
1850e8ca1db2SDr. David Alan Gilbert * This detects two potential causes of mismatch:
1851e8ca1db2SDr. David Alan Gilbert * a) A mismatch in host page sizes
1852093e3c42SDr. David Alan Gilbert * Some combinations of mismatch are probably possible but it gets
1853093e3c42SDr. David Alan Gilbert * a bit more complicated. In particular we need to place whole
1854093e3c42SDr. David Alan Gilbert * host pages on the dest at once, and we need to ensure that we
1855093e3c42SDr. David Alan Gilbert * handle dirtying to make sure we never end up sending part of
1856093e3c42SDr. David Alan Gilbert * a hostpage on it's own.
1857e8ca1db2SDr. David Alan Gilbert * b) The use of different huge page sizes on source/destination
1858e8ca1db2SDr. David Alan Gilbert * a more fine grain test is performed during RAM block migration
1859e8ca1db2SDr. David Alan Gilbert * but this test here causes a nice early clear failure, and
1860e8ca1db2SDr. David Alan Gilbert * also fails when passed to an older qemu that doesn't
1861e8ca1db2SDr. David Alan Gilbert * do huge pages.
1862093e3c42SDr. David Alan Gilbert */
1863e8ca1db2SDr. David Alan Gilbert error_report("Postcopy needs matching RAM page sizes (s=%" PRIx64
1864e8ca1db2SDr. David Alan Gilbert " d=%" PRIx64 ")",
1865e8ca1db2SDr. David Alan Gilbert remote_pagesize_summary, local_pagesize_summary);
1866093e3c42SDr. David Alan Gilbert return -1;
1867093e3c42SDr. David Alan Gilbert }
1868093e3c42SDr. David Alan Gilbert
1869093e3c42SDr. David Alan Gilbert remote_tps = qemu_get_be64(mis->from_src_file);
1870144fa06bSJuan Quintela if (remote_tps != page_size) {
1871093e3c42SDr. David Alan Gilbert /*
1872093e3c42SDr. David Alan Gilbert * Again, some differences could be dealt with, but for now keep it
1873093e3c42SDr. David Alan Gilbert * simple.
1874093e3c42SDr. David Alan Gilbert */
187520afaed9SJuan Quintela error_report("Postcopy needs matching target page sizes (s=%d d=%zd)",
1876144fa06bSJuan Quintela (int)remote_tps, page_size);
1877093e3c42SDr. David Alan Gilbert return -1;
1878093e3c42SDr. David Alan Gilbert }
1879093e3c42SDr. David Alan Gilbert
1880d3dff7a5SDr. David Alan Gilbert if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, &local_err)) {
1881d3dff7a5SDr. David Alan Gilbert error_report_err(local_err);
1882d3dff7a5SDr. David Alan Gilbert return -1;
1883d3dff7a5SDr. David Alan Gilbert }
1884d3dff7a5SDr. David Alan Gilbert
18851caddf8aSDr. David Alan Gilbert if (ram_postcopy_incoming_init(mis)) {
18861caddf8aSDr. David Alan Gilbert return -1;
18871caddf8aSDr. David Alan Gilbert }
18881caddf8aSDr. David Alan Gilbert
1889093e3c42SDr. David Alan Gilbert return 0;
1890093e3c42SDr. David Alan Gilbert }
1891093e3c42SDr. David Alan Gilbert
1892093e3c42SDr. David Alan Gilbert /* After postcopy we will be told to throw some pages away since they're
1893093e3c42SDr. David Alan Gilbert * dirty and will have to be demand fetched. Must happen before CPU is
1894093e3c42SDr. David Alan Gilbert * started.
1895093e3c42SDr. David Alan Gilbert * There can be 0..many of these messages, each encoding multiple pages.
1896093e3c42SDr. David Alan Gilbert */
loadvm_postcopy_ram_handle_discard(MigrationIncomingState * mis,uint16_t len)1897093e3c42SDr. David Alan Gilbert static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis,
1898093e3c42SDr. David Alan Gilbert uint16_t len)
1899093e3c42SDr. David Alan Gilbert {
1900093e3c42SDr. David Alan Gilbert int tmp;
1901093e3c42SDr. David Alan Gilbert char ramid[256];
1902093e3c42SDr. David Alan Gilbert PostcopyState ps = postcopy_state_get();
1903093e3c42SDr. David Alan Gilbert
1904093e3c42SDr. David Alan Gilbert trace_loadvm_postcopy_ram_handle_discard();
1905093e3c42SDr. David Alan Gilbert
1906093e3c42SDr. David Alan Gilbert switch (ps) {
1907093e3c42SDr. David Alan Gilbert case POSTCOPY_INCOMING_ADVISE:
1908093e3c42SDr. David Alan Gilbert /* 1st discard */
1909f9527107SDr. David Alan Gilbert tmp = postcopy_ram_prepare_discard(mis);
1910093e3c42SDr. David Alan Gilbert if (tmp) {
1911093e3c42SDr. David Alan Gilbert return tmp;
1912093e3c42SDr. David Alan Gilbert }
1913093e3c42SDr. David Alan Gilbert break;
1914093e3c42SDr. David Alan Gilbert
1915093e3c42SDr. David Alan Gilbert case POSTCOPY_INCOMING_DISCARD:
1916093e3c42SDr. David Alan Gilbert /* Expected state */
1917093e3c42SDr. David Alan Gilbert break;
1918093e3c42SDr. David Alan Gilbert
1919093e3c42SDr. David Alan Gilbert default:
1920093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD in wrong postcopy state (%d)",
1921093e3c42SDr. David Alan Gilbert ps);
1922093e3c42SDr. David Alan Gilbert return -1;
1923093e3c42SDr. David Alan Gilbert }
1924093e3c42SDr. David Alan Gilbert /* We're expecting a
1925093e3c42SDr. David Alan Gilbert * Version (0)
1926093e3c42SDr. David Alan Gilbert * a RAM ID string (length byte, name, 0 term)
1927093e3c42SDr. David Alan Gilbert * then at least 1 16 byte chunk
1928093e3c42SDr. David Alan Gilbert */
1929093e3c42SDr. David Alan Gilbert if (len < (1 + 1 + 1 + 1 + 2 * 8)) {
1930093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len);
1931093e3c42SDr. David Alan Gilbert return -1;
1932093e3c42SDr. David Alan Gilbert }
1933093e3c42SDr. David Alan Gilbert
1934093e3c42SDr. David Alan Gilbert tmp = qemu_get_byte(mis->from_src_file);
1935093e3c42SDr. David Alan Gilbert if (tmp != postcopy_ram_discard_version) {
1936093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD invalid version (%d)", tmp);
1937093e3c42SDr. David Alan Gilbert return -1;
1938093e3c42SDr. David Alan Gilbert }
1939093e3c42SDr. David Alan Gilbert
1940093e3c42SDr. David Alan Gilbert if (!qemu_get_counted_string(mis->from_src_file, ramid)) {
1941093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD Failed to read RAMBlock ID");
1942093e3c42SDr. David Alan Gilbert return -1;
1943093e3c42SDr. David Alan Gilbert }
1944093e3c42SDr. David Alan Gilbert tmp = qemu_get_byte(mis->from_src_file);
1945093e3c42SDr. David Alan Gilbert if (tmp != 0) {
1946093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD missing nil (%d)", tmp);
1947093e3c42SDr. David Alan Gilbert return -1;
1948093e3c42SDr. David Alan Gilbert }
1949093e3c42SDr. David Alan Gilbert
1950093e3c42SDr. David Alan Gilbert len -= 3 + strlen(ramid);
1951093e3c42SDr. David Alan Gilbert if (len % 16) {
1952093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len);
1953093e3c42SDr. David Alan Gilbert return -1;
1954093e3c42SDr. David Alan Gilbert }
1955093e3c42SDr. David Alan Gilbert trace_loadvm_postcopy_ram_handle_discard_header(ramid, len);
1956093e3c42SDr. David Alan Gilbert while (len) {
1957093e3c42SDr. David Alan Gilbert uint64_t start_addr, block_length;
1958093e3c42SDr. David Alan Gilbert start_addr = qemu_get_be64(mis->from_src_file);
1959093e3c42SDr. David Alan Gilbert block_length = qemu_get_be64(mis->from_src_file);
1960093e3c42SDr. David Alan Gilbert
1961093e3c42SDr. David Alan Gilbert len -= 16;
1962aaa2064cSJuan Quintela int ret = ram_discard_range(ramid, start_addr, block_length);
1963093e3c42SDr. David Alan Gilbert if (ret) {
1964093e3c42SDr. David Alan Gilbert return ret;
1965093e3c42SDr. David Alan Gilbert }
1966093e3c42SDr. David Alan Gilbert }
1967093e3c42SDr. David Alan Gilbert trace_loadvm_postcopy_ram_handle_discard_end();
1968093e3c42SDr. David Alan Gilbert
1969093e3c42SDr. David Alan Gilbert return 0;
1970093e3c42SDr. David Alan Gilbert }
1971093e3c42SDr. David Alan Gilbert
1972c76201abSDr. David Alan Gilbert /*
1973c76201abSDr. David Alan Gilbert * Triggered by a postcopy_listen command; this thread takes over reading
1974c76201abSDr. David Alan Gilbert * the input stream, leaving the main thread free to carry on loading the rest
1975c76201abSDr. David Alan Gilbert * of the device state (from RAM).
1976c76201abSDr. David Alan Gilbert * (TODO:This could do with being in a postcopy file - but there again it's
1977c76201abSDr. David Alan Gilbert * just another input loop, not that postcopy specific)
1978c76201abSDr. David Alan Gilbert */
postcopy_ram_listen_thread(void * opaque)1979c76201abSDr. David Alan Gilbert static void *postcopy_ram_listen_thread(void *opaque)
1980c76201abSDr. David Alan Gilbert {
1981c76201abSDr. David Alan Gilbert MigrationIncomingState *mis = migration_incoming_get_current();
1982b411b844SPeter Xu QEMUFile *f = mis->from_src_file;
1983c76201abSDr. David Alan Gilbert int load_res;
1984ee647225SVladimir Sementsov-Ogievskiy MigrationState *migr = migrate_get_current();
1985ee647225SVladimir Sementsov-Ogievskiy
1986ee647225SVladimir Sementsov-Ogievskiy object_ref(OBJECT(migr));
1987c76201abSDr. David Alan Gilbert
19886ba996bbSDr. David Alan Gilbert migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
19896ba996bbSDr. David Alan Gilbert MIGRATION_STATUS_POSTCOPY_ACTIVE);
1990095c12a4SPeter Xu qemu_sem_post(&mis->thread_sync_sem);
1991c76201abSDr. David Alan Gilbert trace_postcopy_ram_listen_thread_start();
1992c76201abSDr. David Alan Gilbert
199374637e6fSLidong Chen rcu_register_thread();
1994c76201abSDr. David Alan Gilbert /*
1995c76201abSDr. David Alan Gilbert * Because we're a thread and not a coroutine we can't yield
1996c76201abSDr. David Alan Gilbert * in qemu_file, and thus we must be blocking now.
1997c76201abSDr. David Alan Gilbert */
1998c76201abSDr. David Alan Gilbert qemu_file_set_blocking(f, true);
1999c76201abSDr. David Alan Gilbert load_res = qemu_loadvm_state_main(f, mis);
2000b411b844SPeter Xu
2001b411b844SPeter Xu /*
2002b411b844SPeter Xu * This is tricky, but, mis->from_src_file can change after it
2003b411b844SPeter Xu * returns, when postcopy recovery happened. In the future, we may
2004b411b844SPeter Xu * want a wrapper for the QEMUFile handle.
2005b411b844SPeter Xu */
2006b411b844SPeter Xu f = mis->from_src_file;
2007b411b844SPeter Xu
2008c76201abSDr. David Alan Gilbert /* And non-blocking again so we don't block in any cleanup */
2009c76201abSDr. David Alan Gilbert qemu_file_set_blocking(f, false);
2010c76201abSDr. David Alan Gilbert
2011c76201abSDr. David Alan Gilbert trace_postcopy_ram_listen_thread_exit();
2012c76201abSDr. David Alan Gilbert if (load_res < 0) {
2013c76201abSDr. David Alan Gilbert qemu_file_set_error(f, load_res);
2014ee647225SVladimir Sementsov-Ogievskiy dirty_bitmap_mig_cancel_incoming();
2015ee647225SVladimir Sementsov-Ogievskiy if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING &&
2016ee647225SVladimir Sementsov-Ogievskiy !migrate_postcopy_ram() && migrate_dirty_bitmaps())
2017ee647225SVladimir Sementsov-Ogievskiy {
2018ee647225SVladimir Sementsov-Ogievskiy error_report("%s: loadvm failed during postcopy: %d. All states "
2019ee647225SVladimir Sementsov-Ogievskiy "are migrated except dirty bitmaps. Some dirty "
2020ee647225SVladimir Sementsov-Ogievskiy "bitmaps may be lost, and present migrated dirty "
2021ee647225SVladimir Sementsov-Ogievskiy "bitmaps are correctly migrated and valid.",
2022ee647225SVladimir Sementsov-Ogievskiy __func__, load_res);
2023ee647225SVladimir Sementsov-Ogievskiy load_res = 0; /* prevent further exit() */
2024ee647225SVladimir Sementsov-Ogievskiy } else {
2025ee647225SVladimir Sementsov-Ogievskiy error_report("%s: loadvm failed: %d", __func__, load_res);
20266ba996bbSDr. David Alan Gilbert migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
20276ba996bbSDr. David Alan Gilbert MIGRATION_STATUS_FAILED);
2028ee647225SVladimir Sementsov-Ogievskiy }
2029ee647225SVladimir Sementsov-Ogievskiy }
2030ee647225SVladimir Sementsov-Ogievskiy if (load_res >= 0) {
2031c76201abSDr. David Alan Gilbert /*
2032c76201abSDr. David Alan Gilbert * This looks good, but it's possible that the device loading in the
2033c76201abSDr. David Alan Gilbert * main thread hasn't finished yet, and so we might not be in 'RUN'
2034c76201abSDr. David Alan Gilbert * state yet; wait for the end of the main thread.
2035c76201abSDr. David Alan Gilbert */
2036c76201abSDr. David Alan Gilbert qemu_event_wait(&mis->main_thread_load_event);
2037c76201abSDr. David Alan Gilbert }
2038c76201abSDr. David Alan Gilbert postcopy_ram_incoming_cleanup(mis);
2039c76201abSDr. David Alan Gilbert
2040c76201abSDr. David Alan Gilbert if (load_res < 0) {
2041c76201abSDr. David Alan Gilbert /*
2042c76201abSDr. David Alan Gilbert * If something went wrong then we have a bad state so exit;
2043c76201abSDr. David Alan Gilbert * depending how far we got it might be possible at this point
2044c76201abSDr. David Alan Gilbert * to leave the guest running and fire MCEs for pages that never
2045c76201abSDr. David Alan Gilbert * arrived as a desperate recovery step.
2046c76201abSDr. David Alan Gilbert */
204774637e6fSLidong Chen rcu_unregister_thread();
2048c76201abSDr. David Alan Gilbert exit(EXIT_FAILURE);
2049c76201abSDr. David Alan Gilbert }
2050c76201abSDr. David Alan Gilbert
20516ba996bbSDr. David Alan Gilbert migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE,
20526ba996bbSDr. David Alan Gilbert MIGRATION_STATUS_COMPLETED);
20536ba996bbSDr. David Alan Gilbert /*
20546ba996bbSDr. David Alan Gilbert * If everything has worked fine, then the main thread has waited
20556ba996bbSDr. David Alan Gilbert * for us to start, and we're the last use of the mis.
20566ba996bbSDr. David Alan Gilbert * (If something broke then qemu will have to exit anyway since it's
20576ba996bbSDr. David Alan Gilbert * got a bad migration state).
20586ba996bbSDr. David Alan Gilbert */
20596ba996bbSDr. David Alan Gilbert migration_incoming_state_destroy();
20606ba996bbSDr. David Alan Gilbert
206174637e6fSLidong Chen rcu_unregister_thread();
20629cf4bb87SDr. David Alan Gilbert mis->have_listen_thread = false;
20632d49bacdSWei Yang postcopy_state_set(POSTCOPY_INCOMING_END);
20642d49bacdSWei Yang
2065ee647225SVladimir Sementsov-Ogievskiy object_unref(OBJECT(migr));
2066ee647225SVladimir Sementsov-Ogievskiy
2067c76201abSDr. David Alan Gilbert return NULL;
2068c76201abSDr. David Alan Gilbert }
2069c76201abSDr. David Alan Gilbert
2070093e3c42SDr. David Alan Gilbert /* After this message we must be able to immediately receive postcopy data */
loadvm_postcopy_handle_listen(MigrationIncomingState * mis)2071093e3c42SDr. David Alan Gilbert static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)
2072093e3c42SDr. David Alan Gilbert {
2073093e3c42SDr. David Alan Gilbert PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_LISTENING);
20746864a7b5SDr. David Alan Gilbert Error *local_err = NULL;
20756864a7b5SDr. David Alan Gilbert
2076c84f976eSPeter Xu trace_loadvm_postcopy_handle_listen("enter");
2077c84f976eSPeter Xu
2078093e3c42SDr. David Alan Gilbert if (ps != POSTCOPY_INCOMING_ADVISE && ps != POSTCOPY_INCOMING_DISCARD) {
2079093e3c42SDr. David Alan Gilbert error_report("CMD_POSTCOPY_LISTEN in wrong postcopy state (%d)", ps);
2080093e3c42SDr. David Alan Gilbert return -1;
2081093e3c42SDr. David Alan Gilbert }
2082f9527107SDr. David Alan Gilbert if (ps == POSTCOPY_INCOMING_ADVISE) {
2083f9527107SDr. David Alan Gilbert /*
2084f9527107SDr. David Alan Gilbert * A rare case, we entered listen without having to do any discards,
2085f9527107SDr. David Alan Gilbert * so do the setup that's normally done at the time of the 1st discard.
2086f9527107SDr. David Alan Gilbert */
208758110f0aSVladimir Sementsov-Ogievskiy if (migrate_postcopy_ram()) {
2088f9527107SDr. David Alan Gilbert postcopy_ram_prepare_discard(mis);
2089f9527107SDr. David Alan Gilbert }
209058110f0aSVladimir Sementsov-Ogievskiy }
2091093e3c42SDr. David Alan Gilbert
2092c84f976eSPeter Xu trace_loadvm_postcopy_handle_listen("after discard");
2093c84f976eSPeter Xu
2094f0a227adSDr. David Alan Gilbert /*
2095f0a227adSDr. David Alan Gilbert * Sensitise RAM - can now generate requests for blocks that don't exist
2096f0a227adSDr. David Alan Gilbert * However, at this point the CPU shouldn't be running, and the IO
2097f0a227adSDr. David Alan Gilbert * shouldn't be doing anything yet so don't actually expect requests
2098f0a227adSDr. David Alan Gilbert */
209958110f0aSVladimir Sementsov-Ogievskiy if (migrate_postcopy_ram()) {
21002a7eb148SWei Yang if (postcopy_ram_incoming_setup(mis)) {
210191b02dc7SFei Li postcopy_ram_incoming_cleanup(mis);
2102f0a227adSDr. David Alan Gilbert return -1;
2103f0a227adSDr. David Alan Gilbert }
210458110f0aSVladimir Sementsov-Ogievskiy }
2105f0a227adSDr. David Alan Gilbert
2106c84f976eSPeter Xu trace_loadvm_postcopy_handle_listen("after uffd");
2107c84f976eSPeter Xu
21086864a7b5SDr. David Alan Gilbert if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_LISTEN, &local_err)) {
21096864a7b5SDr. David Alan Gilbert error_report_err(local_err);
21106864a7b5SDr. David Alan Gilbert return -1;
21116864a7b5SDr. David Alan Gilbert }
21126864a7b5SDr. David Alan Gilbert
2113c76201abSDr. David Alan Gilbert mis->have_listen_thread = true;
2114*e620b1e4SPeter Xu postcopy_thread_create(mis, &mis->listen_thread,
2115*e620b1e4SPeter Xu MIGRATION_THREAD_DST_LISTEN,
2116095c12a4SPeter Xu postcopy_ram_listen_thread, QEMU_THREAD_DETACHED);
2117c84f976eSPeter Xu trace_loadvm_postcopy_handle_listen("return");
2118c84f976eSPeter Xu
2119093e3c42SDr. David Alan Gilbert return 0;
2120093e3c42SDr. David Alan Gilbert }
2121093e3c42SDr. David Alan Gilbert
loadvm_postcopy_handle_run_bh(void * opaque)2122ea6a55bcSDenis V. Lunev static void loadvm_postcopy_handle_run_bh(void *opaque)
2123093e3c42SDr. David Alan Gilbert {
212427c6825bSDr. David Alan Gilbert Error *local_err = NULL;
21251ce54262SWei Yang MigrationIncomingState *mis = opaque;
2126093e3c42SDr. David Alan Gilbert
21273e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-enter");
2128b9a040b9SPeter Xu
212927c6825bSDr. David Alan Gilbert /* TODO we should move all of this lot into postcopy_ram.c or a shared code
213027c6825bSDr. David Alan Gilbert * in migration.c
213127c6825bSDr. David Alan Gilbert */
213227c6825bSDr. David Alan Gilbert cpu_synchronize_all_post_init();
213327c6825bSDr. David Alan Gilbert
21343e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-cpu-synced");
2135b9a040b9SPeter Xu
21367659505cSDr. David Alan Gilbert qemu_announce_self(&mis->announce_timer, migrate_announce_params());
213727c6825bSDr. David Alan Gilbert
21383e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-announced");
2139b9a040b9SPeter Xu
21403b717194SEmanuele Giuseppe Esposito /* Make sure all file formats throw away their mutable metadata.
2141ace21a58SKevin Wolf * If we get an error here, just don't restart the VM yet. */
21423b717194SEmanuele Giuseppe Esposito bdrv_activate_all(&local_err);
214327c6825bSDr. David Alan Gilbert if (local_err) {
214427c6825bSDr. David Alan Gilbert error_report_err(local_err);
21450042fd36SKevin Wolf local_err = NULL;
21460042fd36SKevin Wolf autostart = false;
21470042fd36SKevin Wolf }
21480042fd36SKevin Wolf
21493e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-cache-invalidated");
215027c6825bSDr. David Alan Gilbert
2151b35ebdf0SVladimir Sementsov-Ogievskiy dirty_bitmap_mig_before_vm_start();
2152b35ebdf0SVladimir Sementsov-Ogievskiy
2153093e3c42SDr. David Alan Gilbert if (autostart) {
2154093e3c42SDr. David Alan Gilbert /* Hold onto your hats, starting the CPU */
2155093e3c42SDr. David Alan Gilbert vm_start();
2156093e3c42SDr. David Alan Gilbert } else {
2157093e3c42SDr. David Alan Gilbert /* leave it paused and let management decide when to start the CPU */
2158093e3c42SDr. David Alan Gilbert runstate_set(RUN_STATE_PAUSED);
2159093e3c42SDr. David Alan Gilbert }
2160093e3c42SDr. David Alan Gilbert
21613e5f3bcdSPeter Xu trace_vmstate_downtime_checkpoint("dst-postcopy-bh-vm-started");
2162ea6a55bcSDenis V. Lunev }
2163ea6a55bcSDenis V. Lunev
2164ea6a55bcSDenis V. Lunev /* After all discards we can start running and asking for pages */
loadvm_postcopy_handle_run(MigrationIncomingState * mis)2165ea6a55bcSDenis V. Lunev static int loadvm_postcopy_handle_run(MigrationIncomingState *mis)
2166ea6a55bcSDenis V. Lunev {
21670197d890SWei Yang PostcopyState ps = postcopy_state_get();
2168ea6a55bcSDenis V. Lunev
2169ea6a55bcSDenis V. Lunev trace_loadvm_postcopy_handle_run();
2170ea6a55bcSDenis V. Lunev if (ps != POSTCOPY_INCOMING_LISTENING) {
2171ea6a55bcSDenis V. Lunev error_report("CMD_POSTCOPY_RUN in wrong postcopy state (%d)", ps);
2172ea6a55bcSDenis V. Lunev return -1;
2173ea6a55bcSDenis V. Lunev }
2174ea6a55bcSDenis V. Lunev
21750197d890SWei Yang postcopy_state_set(POSTCOPY_INCOMING_RUNNING);
217644d0d456SFabiano Rosas migration_bh_schedule(loadvm_postcopy_handle_run_bh, mis);
2177ea6a55bcSDenis V. Lunev
217827c6825bSDr. David Alan Gilbert /* We need to finish reading the stream from the package
217927c6825bSDr. David Alan Gilbert * and also stop reading anything more from the stream that loaded the
218027c6825bSDr. David Alan Gilbert * package (since it's now being read by the listener thread).
218127c6825bSDr. David Alan Gilbert * LOADVM_QUIT will quit all the layers of nested loadvm loops.
218227c6825bSDr. David Alan Gilbert */
218327c6825bSDr. David Alan Gilbert return LOADVM_QUIT;
2184093e3c42SDr. David Alan Gilbert }
2185093e3c42SDr. David Alan Gilbert
21860c26781cSPeter Xu /* We must be with page_request_mutex held */
postcopy_sync_page_req(gpointer key,gpointer value,gpointer data)21870c26781cSPeter Xu static gboolean postcopy_sync_page_req(gpointer key, gpointer value,
21880c26781cSPeter Xu gpointer data)
21890c26781cSPeter Xu {
21900c26781cSPeter Xu MigrationIncomingState *mis = data;
21910c26781cSPeter Xu void *host_addr = (void *) key;
21920c26781cSPeter Xu ram_addr_t rb_offset;
21930c26781cSPeter Xu RAMBlock *rb;
21940c26781cSPeter Xu int ret;
21950c26781cSPeter Xu
21960c26781cSPeter Xu rb = qemu_ram_block_from_host(host_addr, true, &rb_offset);
21970c26781cSPeter Xu if (!rb) {
21980c26781cSPeter Xu /*
21990c26781cSPeter Xu * This should _never_ happen. However be nice for a migrating VM to
22000c26781cSPeter Xu * not crash/assert. Post an error (note: intended to not use *_once
22010c26781cSPeter Xu * because we do want to see all the illegal addresses; and this can
22020c26781cSPeter Xu * never be triggered by the guest so we're safe) and move on next.
22030c26781cSPeter Xu */
22040c26781cSPeter Xu error_report("%s: illegal host addr %p", __func__, host_addr);
22050c26781cSPeter Xu /* Try the next entry */
22060c26781cSPeter Xu return FALSE;
22070c26781cSPeter Xu }
22080c26781cSPeter Xu
22090c26781cSPeter Xu ret = migrate_send_rp_message_req_pages(mis, rb, rb_offset);
22100c26781cSPeter Xu if (ret) {
22110c26781cSPeter Xu /* Please refer to above comment. */
22120c26781cSPeter Xu error_report("%s: send rp message failed for addr %p",
22130c26781cSPeter Xu __func__, host_addr);
22140c26781cSPeter Xu return FALSE;
22150c26781cSPeter Xu }
22160c26781cSPeter Xu
22170c26781cSPeter Xu trace_postcopy_page_req_sync(host_addr);
22180c26781cSPeter Xu
22190c26781cSPeter Xu return FALSE;
22200c26781cSPeter Xu }
22210c26781cSPeter Xu
migrate_send_rp_req_pages_pending(MigrationIncomingState * mis)22220c26781cSPeter Xu static void migrate_send_rp_req_pages_pending(MigrationIncomingState *mis)
22230c26781cSPeter Xu {
22240c26781cSPeter Xu WITH_QEMU_LOCK_GUARD(&mis->page_request_mutex) {
22250c26781cSPeter Xu g_tree_foreach(mis->page_requested, postcopy_sync_page_req, mis);
22260c26781cSPeter Xu }
22270c26781cSPeter Xu }
22280c26781cSPeter Xu
loadvm_postcopy_handle_resume(MigrationIncomingState * mis)22293f5875ecSPeter Xu static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis)
22303f5875ecSPeter Xu {
22313f5875ecSPeter Xu if (mis->state != MIGRATION_STATUS_POSTCOPY_RECOVER) {
22323f5875ecSPeter Xu error_report("%s: illegal resume received", __func__);
22333f5875ecSPeter Xu /* Don't fail the load, only for this. */
22343f5875ecSPeter Xu return 0;
22353f5875ecSPeter Xu }
22363f5875ecSPeter Xu
22373f5875ecSPeter Xu /*
2238cc5ab872SPeter Xu * Reset the last_rb before we resend any page req to source again, since
2239cc5ab872SPeter Xu * the source should have it reset already.
2240cc5ab872SPeter Xu */
2241cc5ab872SPeter Xu mis->last_rb = NULL;
2242cc5ab872SPeter Xu
2243cc5ab872SPeter Xu /*
22443f5875ecSPeter Xu * This means source VM is ready to resume the postcopy migration.
22453f5875ecSPeter Xu */
22463f5875ecSPeter Xu migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_RECOVER,
22473f5875ecSPeter Xu MIGRATION_STATUS_POSTCOPY_ACTIVE);
22483f5875ecSPeter Xu
22493f5875ecSPeter Xu trace_loadvm_postcopy_handle_resume();
22503f5875ecSPeter Xu
225113955b89SPeter Xu /* Tell source that "we are ready" */
225213955b89SPeter Xu migrate_send_rp_resume_ack(mis, MIGRATION_RESUME_ACK_VALUE);
22533f5875ecSPeter Xu
22540c26781cSPeter Xu /*
22550c26781cSPeter Xu * After a postcopy recovery, the source should have lost the postcopy
22560c26781cSPeter Xu * queue, or potentially the requested pages could have been lost during
22570c26781cSPeter Xu * the network down phase. Let's re-sync with the source VM by re-sending
22580c26781cSPeter Xu * all the pending pages that we eagerly need, so these threads won't get
22590c26781cSPeter Xu * blocked too long due to the recovery.
22600c26781cSPeter Xu *
22610c26781cSPeter Xu * Without this procedure, the faulted destination VM threads (waiting for
22620c26781cSPeter Xu * page requests right before the postcopy is interrupted) can keep hanging
22630c26781cSPeter Xu * until the pages are sent by the source during the background copying of
22640c26781cSPeter Xu * pages, or another thread faulted on the same address accidentally.
22650c26781cSPeter Xu */
22660c26781cSPeter Xu migrate_send_rp_req_pages_pending(mis);
22670c26781cSPeter Xu
22685e773431SPeter Xu /*
22695e773431SPeter Xu * It's time to switch state and release the fault thread to continue
22705e773431SPeter Xu * service page faults. Note that this should be explicitly after the
22715e773431SPeter Xu * above call to migrate_send_rp_req_pages_pending(). In short:
22725e773431SPeter Xu * migrate_send_rp_message_req_pages() is not thread safe, yet.
22735e773431SPeter Xu */
22745e773431SPeter Xu qemu_sem_post(&mis->postcopy_pause_sem_fault);
22755e773431SPeter Xu
227660bb3c58SPeter Xu if (migrate_postcopy_preempt()) {
22775655aab0SPeter Xu /*
22785655aab0SPeter Xu * The preempt channel will be created in async manner, now let's
22795655aab0SPeter Xu * wait for it and make sure it's created.
22805655aab0SPeter Xu */
22815655aab0SPeter Xu qemu_sem_wait(&mis->postcopy_qemufile_dst_done);
228260bb3c58SPeter Xu assert(mis->postcopy_qemufile_dst);
228360bb3c58SPeter Xu /* Kick the fast ram load thread too */
228460bb3c58SPeter Xu qemu_sem_post(&mis->postcopy_pause_sem_fast_load);
228560bb3c58SPeter Xu }
228660bb3c58SPeter Xu
22873f5875ecSPeter Xu return 0;
22883f5875ecSPeter Xu }
22893f5875ecSPeter Xu
2290c76ca188SDr. David Alan Gilbert /**
229111cf1d98SDr. David Alan Gilbert * Immediately following this command is a blob of data containing an embedded
229211cf1d98SDr. David Alan Gilbert * chunk of migration stream; read it and load it.
2293c76ca188SDr. David Alan Gilbert *
229411cf1d98SDr. David Alan Gilbert * @mis: Incoming state
229511cf1d98SDr. David Alan Gilbert * @length: Length of packaged data to read
229611cf1d98SDr. David Alan Gilbert *
229711cf1d98SDr. David Alan Gilbert * Returns: Negative values on error
229811cf1d98SDr. David Alan Gilbert *
229911cf1d98SDr. David Alan Gilbert */
loadvm_handle_cmd_packaged(MigrationIncomingState * mis)230011cf1d98SDr. David Alan Gilbert static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis)
230111cf1d98SDr. David Alan Gilbert {
230211cf1d98SDr. David Alan Gilbert int ret;
230361b67d47SDaniel P. Berrange size_t length;
230461b67d47SDaniel P. Berrange QIOChannelBuffer *bioc;
230511cf1d98SDr. David Alan Gilbert
230611cf1d98SDr. David Alan Gilbert length = qemu_get_be32(mis->from_src_file);
230711cf1d98SDr. David Alan Gilbert trace_loadvm_handle_cmd_packaged(length);
230811cf1d98SDr. David Alan Gilbert
230911cf1d98SDr. David Alan Gilbert if (length > MAX_VM_CMD_PACKAGED_SIZE) {
231061b67d47SDaniel P. Berrange error_report("Unreasonably large packaged state: %zu", length);
231111cf1d98SDr. David Alan Gilbert return -1;
231211cf1d98SDr. David Alan Gilbert }
231361b67d47SDaniel P. Berrange
231461b67d47SDaniel P. Berrange bioc = qio_channel_buffer_new(length);
23156f01f136SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(bioc), "migration-loadvm-buffer");
231661b67d47SDaniel P. Berrange ret = qemu_get_buffer(mis->from_src_file,
231761b67d47SDaniel P. Berrange bioc->data,
231861b67d47SDaniel P. Berrange length);
231911cf1d98SDr. David Alan Gilbert if (ret != length) {
232061b67d47SDaniel P. Berrange object_unref(OBJECT(bioc));
232161b67d47SDaniel P. Berrange error_report("CMD_PACKAGED: Buffer receive fail ret=%d length=%zu",
232211cf1d98SDr. David Alan Gilbert ret, length);
232311cf1d98SDr. David Alan Gilbert return (ret < 0) ? ret : -EAGAIN;
232411cf1d98SDr. David Alan Gilbert }
232561b67d47SDaniel P. Berrange bioc->usage += length;
232611cf1d98SDr. David Alan Gilbert trace_loadvm_handle_cmd_packaged_received(ret);
232711cf1d98SDr. David Alan Gilbert
232877ef2dc1SDaniel P. Berrangé QEMUFile *packf = qemu_file_new_input(QIO_CHANNEL(bioc));
232911cf1d98SDr. David Alan Gilbert
23307afbdadaSWei Wang /*
23317afbdadaSWei Wang * Before loading the guest states, ensure that the preempt channel has
23327afbdadaSWei Wang * been ready to use, as some of the states (e.g. via virtio_load) might
23337afbdadaSWei Wang * trigger page faults that will be handled through the preempt channel.
23347afbdadaSWei Wang * So yield to the main thread in the case that the channel create event
23357afbdadaSWei Wang * hasn't been dispatched.
23367afbdadaSWei Wang *
23377afbdadaSWei Wang * TODO: if we can move migration loadvm out of main thread, then we
23387afbdadaSWei Wang * won't block main thread from polling the accept() fds. We can drop
23397afbdadaSWei Wang * this as a whole when that is done.
23407afbdadaSWei Wang */
23417afbdadaSWei Wang do {
23427afbdadaSWei Wang if (!migrate_postcopy_preempt() || !qemu_in_coroutine() ||
23437afbdadaSWei Wang mis->postcopy_qemufile_dst) {
23447afbdadaSWei Wang break;
23457afbdadaSWei Wang }
23467afbdadaSWei Wang
23477afbdadaSWei Wang aio_co_schedule(qemu_get_current_aio_context(), qemu_coroutine_self());
23487afbdadaSWei Wang qemu_coroutine_yield();
23497afbdadaSWei Wang } while (1);
23507afbdadaSWei Wang
235111cf1d98SDr. David Alan Gilbert ret = qemu_loadvm_state_main(packf, mis);
235211cf1d98SDr. David Alan Gilbert trace_loadvm_handle_cmd_packaged_main(ret);
235311cf1d98SDr. David Alan Gilbert qemu_fclose(packf);
235461b67d47SDaniel P. Berrange object_unref(OBJECT(bioc));
235511cf1d98SDr. David Alan Gilbert
235611cf1d98SDr. David Alan Gilbert return ret;
235711cf1d98SDr. David Alan Gilbert }
235811cf1d98SDr. David Alan Gilbert
235911cf1d98SDr. David Alan Gilbert /*
2360f25d4225SPeter Xu * Handle request that source requests for recved_bitmap on
2361f25d4225SPeter Xu * destination. Payload format:
2362f25d4225SPeter Xu *
2363f25d4225SPeter Xu * len (1 byte) + ramblock_name (<255 bytes)
2364f25d4225SPeter Xu */
loadvm_handle_recv_bitmap(MigrationIncomingState * mis,uint16_t len)2365f25d4225SPeter Xu static int loadvm_handle_recv_bitmap(MigrationIncomingState *mis,
2366f25d4225SPeter Xu uint16_t len)
2367f25d4225SPeter Xu {
2368f25d4225SPeter Xu QEMUFile *file = mis->from_src_file;
2369f25d4225SPeter Xu RAMBlock *rb;
2370f25d4225SPeter Xu char block_name[256];
2371f25d4225SPeter Xu size_t cnt;
2372f25d4225SPeter Xu
2373f25d4225SPeter Xu cnt = qemu_get_counted_string(file, block_name);
2374f25d4225SPeter Xu if (!cnt) {
2375f25d4225SPeter Xu error_report("%s: failed to read block name", __func__);
2376f25d4225SPeter Xu return -EINVAL;
2377f25d4225SPeter Xu }
2378f25d4225SPeter Xu
2379f25d4225SPeter Xu /* Validate before using the data */
2380f25d4225SPeter Xu if (qemu_file_get_error(file)) {
2381f25d4225SPeter Xu return qemu_file_get_error(file);
2382f25d4225SPeter Xu }
2383f25d4225SPeter Xu
2384f25d4225SPeter Xu if (len != cnt + 1) {
2385f25d4225SPeter Xu error_report("%s: invalid payload length (%d)", __func__, len);
2386f25d4225SPeter Xu return -EINVAL;
2387f25d4225SPeter Xu }
2388f25d4225SPeter Xu
2389f25d4225SPeter Xu rb = qemu_ram_block_by_name(block_name);
2390f25d4225SPeter Xu if (!rb) {
2391f25d4225SPeter Xu error_report("%s: block '%s' not found", __func__, block_name);
2392f25d4225SPeter Xu return -EINVAL;
2393f25d4225SPeter Xu }
2394f25d4225SPeter Xu
2395a335debbSPeter Xu migrate_send_rp_recv_bitmap(mis, block_name);
2396f25d4225SPeter Xu
2397f25d4225SPeter Xu trace_loadvm_handle_recv_bitmap(block_name);
2398f25d4225SPeter Xu
2399f25d4225SPeter Xu return 0;
2400f25d4225SPeter Xu }
2401f25d4225SPeter Xu
loadvm_process_enable_colo(MigrationIncomingState * mis)2402aad555c2SZhang Chen static int loadvm_process_enable_colo(MigrationIncomingState *mis)
2403aad555c2SZhang Chen {
240418b1d3c9SDavid Hildenbrand int ret = migration_incoming_enable_colo();
240518b1d3c9SDavid Hildenbrand
240618b1d3c9SDavid Hildenbrand if (!ret) {
240718b1d3c9SDavid Hildenbrand ret = colo_init_ram_cache();
240818b1d3c9SDavid Hildenbrand if (ret) {
240918b1d3c9SDavid Hildenbrand migration_incoming_disable_colo();
241018b1d3c9SDavid Hildenbrand }
241118b1d3c9SDavid Hildenbrand }
241218b1d3c9SDavid Hildenbrand return ret;
2413aad555c2SZhang Chen }
2414aad555c2SZhang Chen
2415f25d4225SPeter Xu /*
241611cf1d98SDr. David Alan Gilbert * Process an incoming 'QEMU_VM_COMMAND'
241711cf1d98SDr. David Alan Gilbert * 0 just a normal return
24187b89bf27SDr. David Alan Gilbert * LOADVM_QUIT All good, but exit the loop
241911cf1d98SDr. David Alan Gilbert * <0 Error
2420c76ca188SDr. David Alan Gilbert */
loadvm_process_command(QEMUFile * f)2421c76ca188SDr. David Alan Gilbert static int loadvm_process_command(QEMUFile *f)
2422c76ca188SDr. David Alan Gilbert {
24232e37701eSDr. David Alan Gilbert MigrationIncomingState *mis = migration_incoming_get_current();
2424c76ca188SDr. David Alan Gilbert uint16_t cmd;
2425c76ca188SDr. David Alan Gilbert uint16_t len;
24262e37701eSDr. David Alan Gilbert uint32_t tmp32;
2427c76ca188SDr. David Alan Gilbert
2428c76ca188SDr. David Alan Gilbert cmd = qemu_get_be16(f);
2429c76ca188SDr. David Alan Gilbert len = qemu_get_be16(f);
2430c76ca188SDr. David Alan Gilbert
24317a9ddfbfSPeter Xu /* Check validity before continue processing of cmds */
24327a9ddfbfSPeter Xu if (qemu_file_get_error(f)) {
24337a9ddfbfSPeter Xu return qemu_file_get_error(f);
24347a9ddfbfSPeter Xu }
24357a9ddfbfSPeter Xu
2436c76ca188SDr. David Alan Gilbert if (cmd >= MIG_CMD_MAX || cmd == MIG_CMD_INVALID) {
2437c76ca188SDr. David Alan Gilbert error_report("MIG_CMD 0x%x unknown (len 0x%x)", cmd, len);
2438c76ca188SDr. David Alan Gilbert return -EINVAL;
2439c76ca188SDr. David Alan Gilbert }
2440c76ca188SDr. David Alan Gilbert
2441a7060ba3SPeter Xu trace_loadvm_process_command(mig_cmd_args[cmd].name, len);
2442a7060ba3SPeter Xu
2443c76ca188SDr. David Alan Gilbert if (mig_cmd_args[cmd].len != -1 && mig_cmd_args[cmd].len != len) {
2444c76ca188SDr. David Alan Gilbert error_report("%s received with bad length - expecting %zu, got %d",
2445c76ca188SDr. David Alan Gilbert mig_cmd_args[cmd].name,
2446c76ca188SDr. David Alan Gilbert (size_t)mig_cmd_args[cmd].len, len);
2447c76ca188SDr. David Alan Gilbert return -ERANGE;
2448c76ca188SDr. David Alan Gilbert }
2449c76ca188SDr. David Alan Gilbert
2450c76ca188SDr. David Alan Gilbert switch (cmd) {
24512e37701eSDr. David Alan Gilbert case MIG_CMD_OPEN_RETURN_PATH:
24522e37701eSDr. David Alan Gilbert if (mis->to_src_file) {
24532e37701eSDr. David Alan Gilbert error_report("CMD_OPEN_RETURN_PATH called when RP already open");
24542e37701eSDr. David Alan Gilbert /* Not really a problem, so don't give up */
24552e37701eSDr. David Alan Gilbert return 0;
24562e37701eSDr. David Alan Gilbert }
24572e37701eSDr. David Alan Gilbert mis->to_src_file = qemu_file_get_return_path(f);
24582e37701eSDr. David Alan Gilbert if (!mis->to_src_file) {
24592e37701eSDr. David Alan Gilbert error_report("CMD_OPEN_RETURN_PATH failed");
24602e37701eSDr. David Alan Gilbert return -1;
24612e37701eSDr. David Alan Gilbert }
24621b4adb10SAvihai Horon
24631b4adb10SAvihai Horon /*
24641b4adb10SAvihai Horon * Switchover ack is enabled but no device uses it, so send an ACK to
24651b4adb10SAvihai Horon * source that it's OK to switchover. Do it here, after return path has
24661b4adb10SAvihai Horon * been created.
24671b4adb10SAvihai Horon */
24681b4adb10SAvihai Horon if (migrate_switchover_ack() && !mis->switchover_ack_pending_num) {
24691b4adb10SAvihai Horon int ret = migrate_send_rp_switchover_ack(mis);
24701b4adb10SAvihai Horon if (ret) {
24711b4adb10SAvihai Horon error_report(
24721b4adb10SAvihai Horon "Could not send switchover ack RP MSG, err %d (%s)", ret,
24731b4adb10SAvihai Horon strerror(-ret));
24741b4adb10SAvihai Horon return ret;
24751b4adb10SAvihai Horon }
24761b4adb10SAvihai Horon }
24772e37701eSDr. David Alan Gilbert break;
24782e37701eSDr. David Alan Gilbert
24792e37701eSDr. David Alan Gilbert case MIG_CMD_PING:
24802e37701eSDr. David Alan Gilbert tmp32 = qemu_get_be32(f);
24812e37701eSDr. David Alan Gilbert trace_loadvm_process_command_ping(tmp32);
24822e37701eSDr. David Alan Gilbert if (!mis->to_src_file) {
24832e37701eSDr. David Alan Gilbert error_report("CMD_PING (0x%x) received with no return path",
24842e37701eSDr. David Alan Gilbert tmp32);
24852e37701eSDr. David Alan Gilbert return -1;
24862e37701eSDr. David Alan Gilbert }
24876decec93SDr. David Alan Gilbert migrate_send_rp_pong(mis, tmp32);
24882e37701eSDr. David Alan Gilbert break;
2489093e3c42SDr. David Alan Gilbert
249011cf1d98SDr. David Alan Gilbert case MIG_CMD_PACKAGED:
249111cf1d98SDr. David Alan Gilbert return loadvm_handle_cmd_packaged(mis);
249211cf1d98SDr. David Alan Gilbert
2493093e3c42SDr. David Alan Gilbert case MIG_CMD_POSTCOPY_ADVISE:
2494875fcd01SGreg Kurz return loadvm_postcopy_handle_advise(mis, len);
2495093e3c42SDr. David Alan Gilbert
2496093e3c42SDr. David Alan Gilbert case MIG_CMD_POSTCOPY_LISTEN:
2497093e3c42SDr. David Alan Gilbert return loadvm_postcopy_handle_listen(mis);
2498093e3c42SDr. David Alan Gilbert
2499093e3c42SDr. David Alan Gilbert case MIG_CMD_POSTCOPY_RUN:
2500093e3c42SDr. David Alan Gilbert return loadvm_postcopy_handle_run(mis);
2501093e3c42SDr. David Alan Gilbert
2502093e3c42SDr. David Alan Gilbert case MIG_CMD_POSTCOPY_RAM_DISCARD:
2503093e3c42SDr. David Alan Gilbert return loadvm_postcopy_ram_handle_discard(mis, len);
2504f25d4225SPeter Xu
25053f5875ecSPeter Xu case MIG_CMD_POSTCOPY_RESUME:
25063f5875ecSPeter Xu return loadvm_postcopy_handle_resume(mis);
25073f5875ecSPeter Xu
2508f25d4225SPeter Xu case MIG_CMD_RECV_BITMAP:
2509f25d4225SPeter Xu return loadvm_handle_recv_bitmap(mis, len);
2510aad555c2SZhang Chen
2511aad555c2SZhang Chen case MIG_CMD_ENABLE_COLO:
2512aad555c2SZhang Chen return loadvm_process_enable_colo(mis);
2513c76ca188SDr. David Alan Gilbert }
2514c76ca188SDr. David Alan Gilbert
2515c76ca188SDr. David Alan Gilbert return 0;
2516c76ca188SDr. David Alan Gilbert }
2517c76ca188SDr. David Alan Gilbert
251859f39a47SDr. David Alan Gilbert /*
251959f39a47SDr. David Alan Gilbert * Read a footer off the wire and check that it matches the expected section
252059f39a47SDr. David Alan Gilbert *
252159f39a47SDr. David Alan Gilbert * Returns: true if the footer was good
252259f39a47SDr. David Alan Gilbert * false if there is a problem (and calls error_report to say why)
252359f39a47SDr. David Alan Gilbert */
check_section_footer(QEMUFile * f,SaveStateEntry * se)25240f42f657SJuan Quintela static bool check_section_footer(QEMUFile *f, SaveStateEntry *se)
252559f39a47SDr. David Alan Gilbert {
25267a9ddfbfSPeter Xu int ret;
252759f39a47SDr. David Alan Gilbert uint8_t read_mark;
252859f39a47SDr. David Alan Gilbert uint32_t read_section_id;
252959f39a47SDr. David Alan Gilbert
253015c38503SPeter Xu if (!migrate_get_current()->send_section_footer) {
253159f39a47SDr. David Alan Gilbert /* No footer to check */
253259f39a47SDr. David Alan Gilbert return true;
253359f39a47SDr. David Alan Gilbert }
253459f39a47SDr. David Alan Gilbert
253559f39a47SDr. David Alan Gilbert read_mark = qemu_get_byte(f);
253659f39a47SDr. David Alan Gilbert
25377a9ddfbfSPeter Xu ret = qemu_file_get_error(f);
25387a9ddfbfSPeter Xu if (ret) {
25397a9ddfbfSPeter Xu error_report("%s: Read section footer failed: %d",
25407a9ddfbfSPeter Xu __func__, ret);
25417a9ddfbfSPeter Xu return false;
25427a9ddfbfSPeter Xu }
25437a9ddfbfSPeter Xu
254459f39a47SDr. David Alan Gilbert if (read_mark != QEMU_VM_SECTION_FOOTER) {
25450f42f657SJuan Quintela error_report("Missing section footer for %s", se->idstr);
254659f39a47SDr. David Alan Gilbert return false;
254759f39a47SDr. David Alan Gilbert }
254859f39a47SDr. David Alan Gilbert
254959f39a47SDr. David Alan Gilbert read_section_id = qemu_get_be32(f);
25500f42f657SJuan Quintela if (read_section_id != se->load_section_id) {
255159f39a47SDr. David Alan Gilbert error_report("Mismatched section id in footer for %s -"
255259f39a47SDr. David Alan Gilbert " read 0x%x expected 0x%x",
25530f42f657SJuan Quintela se->idstr, read_section_id, se->load_section_id);
255459f39a47SDr. David Alan Gilbert return false;
255559f39a47SDr. David Alan Gilbert }
255659f39a47SDr. David Alan Gilbert
255759f39a47SDr. David Alan Gilbert /* All good */
255859f39a47SDr. David Alan Gilbert return true;
255959f39a47SDr. David Alan Gilbert }
256059f39a47SDr. David Alan Gilbert
2561fb3520a8Szhanghailiang static int
qemu_loadvm_section_start_full(QEMUFile * f,uint8_t type)2562c83b77f4SSteve Sistare qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type)
25637b89bf27SDr. David Alan Gilbert {
25643c80f142SPeter Xu bool trace_downtime = (type == QEMU_VM_SECTION_FULL);
25657b89bf27SDr. David Alan Gilbert uint32_t instance_id, version_id, section_id;
25663c80f142SPeter Xu int64_t start_ts, end_ts;
25677b89bf27SDr. David Alan Gilbert SaveStateEntry *se;
25687b89bf27SDr. David Alan Gilbert char idstr[256];
2569fb3520a8Szhanghailiang int ret;
25707b89bf27SDr. David Alan Gilbert
25717b89bf27SDr. David Alan Gilbert /* Read section start */
25727b89bf27SDr. David Alan Gilbert section_id = qemu_get_be32(f);
25737b89bf27SDr. David Alan Gilbert if (!qemu_get_counted_string(f, idstr)) {
25747b89bf27SDr. David Alan Gilbert error_report("Unable to read ID string for section %u",
25757b89bf27SDr. David Alan Gilbert section_id);
25767b89bf27SDr. David Alan Gilbert return -EINVAL;
25777b89bf27SDr. David Alan Gilbert }
25787b89bf27SDr. David Alan Gilbert instance_id = qemu_get_be32(f);
25797b89bf27SDr. David Alan Gilbert version_id = qemu_get_be32(f);
25807b89bf27SDr. David Alan Gilbert
25817a9ddfbfSPeter Xu ret = qemu_file_get_error(f);
25827a9ddfbfSPeter Xu if (ret) {
25837a9ddfbfSPeter Xu error_report("%s: Failed to read instance/version ID: %d",
25847a9ddfbfSPeter Xu __func__, ret);
25857a9ddfbfSPeter Xu return ret;
25867a9ddfbfSPeter Xu }
25877a9ddfbfSPeter Xu
25887b89bf27SDr. David Alan Gilbert trace_qemu_loadvm_state_section_startfull(section_id, idstr,
25897b89bf27SDr. David Alan Gilbert instance_id, version_id);
25907b89bf27SDr. David Alan Gilbert /* Find savevm section */
25917b89bf27SDr. David Alan Gilbert se = find_se(idstr, instance_id);
25927b89bf27SDr. David Alan Gilbert if (se == NULL) {
259393062e23SPeter Xu error_report("Unknown savevm section or instance '%s' %"PRIu32". "
2594827beacbSJose Ricardo Ziviani "Make sure that your current VM setup matches your "
2595827beacbSJose Ricardo Ziviani "saved VM setup, including any hotplugged devices",
25967b89bf27SDr. David Alan Gilbert idstr, instance_id);
25977b89bf27SDr. David Alan Gilbert return -EINVAL;
25987b89bf27SDr. David Alan Gilbert }
25997b89bf27SDr. David Alan Gilbert
26007b89bf27SDr. David Alan Gilbert /* Validate version */
26017b89bf27SDr. David Alan Gilbert if (version_id > se->version_id) {
26027b89bf27SDr. David Alan Gilbert error_report("savevm: unsupported version %d for '%s' v%d",
26037b89bf27SDr. David Alan Gilbert version_id, idstr, se->version_id);
26047b89bf27SDr. David Alan Gilbert return -EINVAL;
26057b89bf27SDr. David Alan Gilbert }
26060f42f657SJuan Quintela se->load_version_id = version_id;
26070f42f657SJuan Quintela se->load_section_id = section_id;
26087b89bf27SDr. David Alan Gilbert
260988c16567SWen Congyang /* Validate if it is a device's state */
261088c16567SWen Congyang if (xen_enabled() && se->is_ram) {
261188c16567SWen Congyang error_report("loadvm: %s RAM loading not allowed on Xen", idstr);
261288c16567SWen Congyang return -EINVAL;
261388c16567SWen Congyang }
261488c16567SWen Congyang
26153c80f142SPeter Xu if (trace_downtime) {
26163c80f142SPeter Xu start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
26173c80f142SPeter Xu }
26183c80f142SPeter Xu
26193a011c26SJuan Quintela ret = vmstate_load(f, se);
26207b89bf27SDr. David Alan Gilbert if (ret < 0) {
262193062e23SPeter Xu error_report("error while loading state for instance 0x%"PRIx32" of"
26227b89bf27SDr. David Alan Gilbert " device '%s'", instance_id, idstr);
26237b89bf27SDr. David Alan Gilbert return ret;
26247b89bf27SDr. David Alan Gilbert }
26253c80f142SPeter Xu
26263c80f142SPeter Xu if (trace_downtime) {
26273c80f142SPeter Xu end_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
26283c80f142SPeter Xu trace_vmstate_downtime_load("non-iterable", se->idstr,
26293c80f142SPeter Xu se->instance_id, end_ts - start_ts);
26303c80f142SPeter Xu }
26313c80f142SPeter Xu
26320f42f657SJuan Quintela if (!check_section_footer(f, se)) {
26337b89bf27SDr. David Alan Gilbert return -EINVAL;
26347b89bf27SDr. David Alan Gilbert }
2635fb3520a8Szhanghailiang
2636fb3520a8Szhanghailiang return 0;
2637fb3520a8Szhanghailiang }
2638fb3520a8Szhanghailiang
2639fb3520a8Szhanghailiang static int
qemu_loadvm_section_part_end(QEMUFile * f,uint8_t type)2640c83b77f4SSteve Sistare qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type)
2641fb3520a8Szhanghailiang {
26423c80f142SPeter Xu bool trace_downtime = (type == QEMU_VM_SECTION_END);
26433c80f142SPeter Xu int64_t start_ts, end_ts;
2644fb3520a8Szhanghailiang uint32_t section_id;
26450f42f657SJuan Quintela SaveStateEntry *se;
2646fb3520a8Szhanghailiang int ret;
2647fb3520a8Szhanghailiang
26487b89bf27SDr. David Alan Gilbert section_id = qemu_get_be32(f);
26497b89bf27SDr. David Alan Gilbert
26507a9ddfbfSPeter Xu ret = qemu_file_get_error(f);
26517a9ddfbfSPeter Xu if (ret) {
26527a9ddfbfSPeter Xu error_report("%s: Failed to read section ID: %d",
26537a9ddfbfSPeter Xu __func__, ret);
26547a9ddfbfSPeter Xu return ret;
26557a9ddfbfSPeter Xu }
26567a9ddfbfSPeter Xu
26577b89bf27SDr. David Alan Gilbert trace_qemu_loadvm_state_section_partend(section_id);
26580f42f657SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
26590f42f657SJuan Quintela if (se->load_section_id == section_id) {
26607b89bf27SDr. David Alan Gilbert break;
26617b89bf27SDr. David Alan Gilbert }
26627b89bf27SDr. David Alan Gilbert }
26630f42f657SJuan Quintela if (se == NULL) {
26647b89bf27SDr. David Alan Gilbert error_report("Unknown savevm section %d", section_id);
26657b89bf27SDr. David Alan Gilbert return -EINVAL;
26667b89bf27SDr. David Alan Gilbert }
26677b89bf27SDr. David Alan Gilbert
26683c80f142SPeter Xu if (trace_downtime) {
26693c80f142SPeter Xu start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
26703c80f142SPeter Xu }
26713c80f142SPeter Xu
26723a011c26SJuan Quintela ret = vmstate_load(f, se);
26737b89bf27SDr. David Alan Gilbert if (ret < 0) {
26747b89bf27SDr. David Alan Gilbert error_report("error while loading state section id %d(%s)",
26750f42f657SJuan Quintela section_id, se->idstr);
26767b89bf27SDr. David Alan Gilbert return ret;
26777b89bf27SDr. David Alan Gilbert }
26783c80f142SPeter Xu
26793c80f142SPeter Xu if (trace_downtime) {
26803c80f142SPeter Xu end_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME);
26813c80f142SPeter Xu trace_vmstate_downtime_load("iterable", se->idstr,
26823c80f142SPeter Xu se->instance_id, end_ts - start_ts);
26833c80f142SPeter Xu }
26843c80f142SPeter Xu
26850f42f657SJuan Quintela if (!check_section_footer(f, se)) {
26867b89bf27SDr. David Alan Gilbert return -EINVAL;
26877b89bf27SDr. David Alan Gilbert }
2688fb3520a8Szhanghailiang
2689fb3520a8Szhanghailiang return 0;
2690fb3520a8Szhanghailiang }
2691fb3520a8Szhanghailiang
qemu_loadvm_state_header(QEMUFile * f)269216015d32SWei Yang static int qemu_loadvm_state_header(QEMUFile *f)
269316015d32SWei Yang {
269416015d32SWei Yang unsigned int v;
269516015d32SWei Yang int ret;
269616015d32SWei Yang
269716015d32SWei Yang v = qemu_get_be32(f);
269816015d32SWei Yang if (v != QEMU_VM_FILE_MAGIC) {
269916015d32SWei Yang error_report("Not a migration stream");
270016015d32SWei Yang return -EINVAL;
270116015d32SWei Yang }
270216015d32SWei Yang
270316015d32SWei Yang v = qemu_get_be32(f);
270416015d32SWei Yang if (v == QEMU_VM_FILE_VERSION_COMPAT) {
270516015d32SWei Yang error_report("SaveVM v2 format is obsolete and don't work anymore");
270616015d32SWei Yang return -ENOTSUP;
270716015d32SWei Yang }
270816015d32SWei Yang if (v != QEMU_VM_FILE_VERSION) {
270916015d32SWei Yang error_report("Unsupported migration stream version");
271016015d32SWei Yang return -ENOTSUP;
271116015d32SWei Yang }
271216015d32SWei Yang
271316015d32SWei Yang if (migrate_get_current()->send_configuration) {
271416015d32SWei Yang if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) {
271516015d32SWei Yang error_report("Configuration section missing");
271616015d32SWei Yang return -EINVAL;
271716015d32SWei Yang }
271816015d32SWei Yang ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0);
271916015d32SWei Yang
272016015d32SWei Yang if (ret) {
272116015d32SWei Yang return ret;
272216015d32SWei Yang }
272316015d32SWei Yang }
272416015d32SWei Yang return 0;
272516015d32SWei Yang }
272616015d32SWei Yang
qemu_loadvm_state_switchover_ack_needed(MigrationIncomingState * mis)27271b4adb10SAvihai Horon static void qemu_loadvm_state_switchover_ack_needed(MigrationIncomingState *mis)
27281b4adb10SAvihai Horon {
27291b4adb10SAvihai Horon SaveStateEntry *se;
27301b4adb10SAvihai Horon
27311b4adb10SAvihai Horon QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
27321b4adb10SAvihai Horon if (!se->ops || !se->ops->switchover_ack_needed) {
27331b4adb10SAvihai Horon continue;
27341b4adb10SAvihai Horon }
27351b4adb10SAvihai Horon
27361b4adb10SAvihai Horon if (se->ops->switchover_ack_needed(se->opaque)) {
27371b4adb10SAvihai Horon mis->switchover_ack_pending_num++;
27381b4adb10SAvihai Horon }
27391b4adb10SAvihai Horon }
27401b4adb10SAvihai Horon
27411b4adb10SAvihai Horon trace_loadvm_state_switchover_ack_needed(mis->switchover_ack_pending_num);
27421b4adb10SAvihai Horon }
27431b4adb10SAvihai Horon
qemu_loadvm_state_setup(QEMUFile * f,Error ** errp)2744e4fa064dSCédric Le Goater static int qemu_loadvm_state_setup(QEMUFile *f, Error **errp)
2745acb5ea86SJuan Quintela {
2746e4fa064dSCédric Le Goater ERRP_GUARD();
2747acb5ea86SJuan Quintela SaveStateEntry *se;
2748acb5ea86SJuan Quintela int ret;
2749acb5ea86SJuan Quintela
2750acb5ea86SJuan Quintela trace_loadvm_state_setup();
2751acb5ea86SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
2752acb5ea86SJuan Quintela if (!se->ops || !se->ops->load_setup) {
2753acb5ea86SJuan Quintela continue;
2754acb5ea86SJuan Quintela }
2755cea3b4c0SWei Yang if (se->ops->is_active) {
2756acb5ea86SJuan Quintela if (!se->ops->is_active(se->opaque)) {
2757acb5ea86SJuan Quintela continue;
2758acb5ea86SJuan Quintela }
2759acb5ea86SJuan Quintela }
2760acb5ea86SJuan Quintela
2761e4fa064dSCédric Le Goater ret = se->ops->load_setup(f, se->opaque, errp);
2762acb5ea86SJuan Quintela if (ret < 0) {
2763e4fa064dSCédric Le Goater error_prepend(errp, "Load state of device %s failed: ",
2764e4fa064dSCédric Le Goater se->idstr);
2765acb5ea86SJuan Quintela qemu_file_set_error(f, ret);
2766acb5ea86SJuan Quintela return ret;
2767acb5ea86SJuan Quintela }
2768acb5ea86SJuan Quintela }
2769acb5ea86SJuan Quintela return 0;
2770acb5ea86SJuan Quintela }
2771acb5ea86SJuan Quintela
qemu_loadvm_state_cleanup(void)2772acb5ea86SJuan Quintela void qemu_loadvm_state_cleanup(void)
2773acb5ea86SJuan Quintela {
2774acb5ea86SJuan Quintela SaveStateEntry *se;
2775acb5ea86SJuan Quintela
2776acb5ea86SJuan Quintela trace_loadvm_state_cleanup();
2777acb5ea86SJuan Quintela QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
2778acb5ea86SJuan Quintela if (se->ops && se->ops->load_cleanup) {
2779acb5ea86SJuan Quintela se->ops->load_cleanup(se->opaque);
2780acb5ea86SJuan Quintela }
2781acb5ea86SJuan Quintela }
2782acb5ea86SJuan Quintela }
2783acb5ea86SJuan Quintela
2784b411b844SPeter Xu /* Return true if we should continue the migration, or false. */
postcopy_pause_incoming(MigrationIncomingState * mis)2785b411b844SPeter Xu static bool postcopy_pause_incoming(MigrationIncomingState *mis)
2786b411b844SPeter Xu {
278777dadc3fSPeter Xu int i;
278877dadc3fSPeter Xu
2789b411b844SPeter Xu trace_postcopy_pause_incoming();
2790b411b844SPeter Xu
2791ee647225SVladimir Sementsov-Ogievskiy assert(migrate_postcopy_ram());
2792ee647225SVladimir Sementsov-Ogievskiy
279339675fffSPeter Xu /*
279439675fffSPeter Xu * Unregister yank with either from/to src would work, since ioc behind it
279539675fffSPeter Xu * is the same
279639675fffSPeter Xu */
279739675fffSPeter Xu migration_ioc_unregister_yank_from_file(mis->from_src_file);
279839675fffSPeter Xu
2799b411b844SPeter Xu assert(mis->from_src_file);
2800b411b844SPeter Xu qemu_file_shutdown(mis->from_src_file);
2801b411b844SPeter Xu qemu_fclose(mis->from_src_file);
2802b411b844SPeter Xu mis->from_src_file = NULL;
2803b411b844SPeter Xu
2804b411b844SPeter Xu assert(mis->to_src_file);
2805b411b844SPeter Xu qemu_file_shutdown(mis->to_src_file);
2806b411b844SPeter Xu qemu_mutex_lock(&mis->rp_mutex);
2807b411b844SPeter Xu qemu_fclose(mis->to_src_file);
2808b411b844SPeter Xu mis->to_src_file = NULL;
2809b411b844SPeter Xu qemu_mutex_unlock(&mis->rp_mutex);
2810b411b844SPeter Xu
281160bb3c58SPeter Xu /*
281260bb3c58SPeter Xu * NOTE: this must happen before reset the PostcopyTmpPages below,
281360bb3c58SPeter Xu * otherwise it's racy to reset those fields when the fast load thread
281460bb3c58SPeter Xu * can be accessing it in parallel.
281560bb3c58SPeter Xu */
281660bb3c58SPeter Xu if (mis->postcopy_qemufile_dst) {
281760bb3c58SPeter Xu qemu_file_shutdown(mis->postcopy_qemufile_dst);
281860bb3c58SPeter Xu /* Take the mutex to make sure the fast ram load thread halted */
281960bb3c58SPeter Xu qemu_mutex_lock(&mis->postcopy_prio_thread_mutex);
282060bb3c58SPeter Xu migration_ioc_unregister_yank_from_file(mis->postcopy_qemufile_dst);
282160bb3c58SPeter Xu qemu_fclose(mis->postcopy_qemufile_dst);
282260bb3c58SPeter Xu mis->postcopy_qemufile_dst = NULL;
282360bb3c58SPeter Xu qemu_mutex_unlock(&mis->postcopy_prio_thread_mutex);
282460bb3c58SPeter Xu }
282560bb3c58SPeter Xu
28260e99bb8fSPeter Xu /* Current state can be either ACTIVE or RECOVER */
28270e99bb8fSPeter Xu migrate_set_state(&mis->state, mis->state,
2828eed1cc78SPeter Xu MIGRATION_STATUS_POSTCOPY_PAUSED);
2829eed1cc78SPeter Xu
28303a7804c3SPeter Xu /* Notify the fault thread for the invalidated file handle */
28313a7804c3SPeter Xu postcopy_fault_thread_notify(mis);
28323a7804c3SPeter Xu
283336f62f11SPeter Xu /*
283436f62f11SPeter Xu * If network is interrupted, any temp page we received will be useless
283536f62f11SPeter Xu * because we didn't mark them as "received" in receivedmap. After a
283636f62f11SPeter Xu * proper recovery later (which will sync src dirty bitmap with receivedmap
283736f62f11SPeter Xu * on dest) these cached small pages will be resent again.
283836f62f11SPeter Xu */
283936f62f11SPeter Xu for (i = 0; i < mis->postcopy_channels; i++) {
284036f62f11SPeter Xu postcopy_temp_page_reset(&mis->postcopy_tmp_pages[i]);
284136f62f11SPeter Xu }
284236f62f11SPeter Xu
2843b411b844SPeter Xu error_report("Detected IO failure for postcopy. "
2844b411b844SPeter Xu "Migration paused.");
2845b411b844SPeter Xu
28464146b77eSPeter Xu do {
2847b411b844SPeter Xu qemu_sem_wait(&mis->postcopy_pause_sem_dst);
28484146b77eSPeter Xu } while (postcopy_is_paused(mis->state));
2849b411b844SPeter Xu
2850b411b844SPeter Xu trace_postcopy_pause_incoming_continued();
2851b411b844SPeter Xu
2852b411b844SPeter Xu return true;
2853b411b844SPeter Xu }
2854b411b844SPeter Xu
qemu_loadvm_state_main(QEMUFile * f,MigrationIncomingState * mis)28553f6df99dSZhang Chen int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis)
2856fb3520a8Szhanghailiang {
2857fb3520a8Szhanghailiang uint8_t section_type;
2858ccb783c3SDr. David Alan Gilbert int ret = 0;
2859fb3520a8Szhanghailiang
2860b411b844SPeter Xu retry:
28617a9ddfbfSPeter Xu while (true) {
28627a9ddfbfSPeter Xu section_type = qemu_get_byte(f);
28637a9ddfbfSPeter Xu
286460bb3c58SPeter Xu ret = qemu_file_get_error_obj_any(f, mis->postcopy_qemufile_dst, NULL);
286560bb3c58SPeter Xu if (ret) {
28667a9ddfbfSPeter Xu break;
28677a9ddfbfSPeter Xu }
28687a9ddfbfSPeter Xu
2869fb3520a8Szhanghailiang trace_qemu_loadvm_state_section(section_type);
2870fb3520a8Szhanghailiang switch (section_type) {
2871fb3520a8Szhanghailiang case QEMU_VM_SECTION_START:
2872fb3520a8Szhanghailiang case QEMU_VM_SECTION_FULL:
2873c83b77f4SSteve Sistare ret = qemu_loadvm_section_start_full(f, section_type);
2874fb3520a8Szhanghailiang if (ret < 0) {
2875ccb783c3SDr. David Alan Gilbert goto out;
2876fb3520a8Szhanghailiang }
2877fb3520a8Szhanghailiang break;
2878fb3520a8Szhanghailiang case QEMU_VM_SECTION_PART:
2879fb3520a8Szhanghailiang case QEMU_VM_SECTION_END:
2880c83b77f4SSteve Sistare ret = qemu_loadvm_section_part_end(f, section_type);
2881fb3520a8Szhanghailiang if (ret < 0) {
2882ccb783c3SDr. David Alan Gilbert goto out;
2883fb3520a8Szhanghailiang }
28847b89bf27SDr. David Alan Gilbert break;
28857b89bf27SDr. David Alan Gilbert case QEMU_VM_COMMAND:
28867b89bf27SDr. David Alan Gilbert ret = loadvm_process_command(f);
28877b89bf27SDr. David Alan Gilbert trace_qemu_loadvm_state_section_command(ret);
28884695ce3fSWei Yang if ((ret < 0) || (ret == LOADVM_QUIT)) {
2889ccb783c3SDr. David Alan Gilbert goto out;
28907b89bf27SDr. David Alan Gilbert }
28917b89bf27SDr. David Alan Gilbert break;
28927a9ddfbfSPeter Xu case QEMU_VM_EOF:
28937a9ddfbfSPeter Xu /* This is the end of migration */
28947a9ddfbfSPeter Xu goto out;
28957b89bf27SDr. David Alan Gilbert default:
28967b89bf27SDr. David Alan Gilbert error_report("Unknown savevm section type %d", section_type);
2897ccb783c3SDr. David Alan Gilbert ret = -EINVAL;
2898ccb783c3SDr. David Alan Gilbert goto out;
28997b89bf27SDr. David Alan Gilbert }
29007b89bf27SDr. David Alan Gilbert }
29017b89bf27SDr. David Alan Gilbert
2902ccb783c3SDr. David Alan Gilbert out:
2903ccb783c3SDr. David Alan Gilbert if (ret < 0) {
2904ccb783c3SDr. David Alan Gilbert qemu_file_set_error(f, ret);
2905b411b844SPeter Xu
2906ee647225SVladimir Sementsov-Ogievskiy /* Cancel bitmaps incoming regardless of recovery */
2907ee647225SVladimir Sementsov-Ogievskiy dirty_bitmap_mig_cancel_incoming();
2908ee647225SVladimir Sementsov-Ogievskiy
2909b411b844SPeter Xu /*
2910fd037a65SPeter Xu * If we are during an active postcopy, then we pause instead
2911fd037a65SPeter Xu * of bail out to at least keep the VM's dirty data. Note
2912fd037a65SPeter Xu * that POSTCOPY_INCOMING_LISTENING stage is still not enough,
2913fd037a65SPeter Xu * during which we're still receiving device states and we
2914fd037a65SPeter Xu * still haven't yet started the VM on destination.
2915ee647225SVladimir Sementsov-Ogievskiy *
2916ee647225SVladimir Sementsov-Ogievskiy * Only RAM postcopy supports recovery. Still, if RAM postcopy is
2917ee647225SVladimir Sementsov-Ogievskiy * enabled, canceled bitmaps postcopy will not affect RAM postcopy
2918ee647225SVladimir Sementsov-Ogievskiy * recovering.
2919b411b844SPeter Xu */
2920b411b844SPeter Xu if (postcopy_state_get() == POSTCOPY_INCOMING_RUNNING &&
2921ee647225SVladimir Sementsov-Ogievskiy migrate_postcopy_ram() && postcopy_pause_incoming(mis)) {
2922b411b844SPeter Xu /* Reset f to point to the newly created channel */
2923b411b844SPeter Xu f = mis->from_src_file;
2924b411b844SPeter Xu goto retry;
2925b411b844SPeter Xu }
2926ccb783c3SDr. David Alan Gilbert }
2927ccb783c3SDr. David Alan Gilbert return ret;
29287b89bf27SDr. David Alan Gilbert }
29297b89bf27SDr. David Alan Gilbert
qemu_loadvm_state(QEMUFile * f)2930c3049a56SJuan Quintela int qemu_loadvm_state(QEMUFile *f)
2931c3049a56SJuan Quintela {
29321a8f46f8SDr. David Alan Gilbert MigrationIncomingState *mis = migration_incoming_get_current();
2933c3049a56SJuan Quintela Error *local_err = NULL;
2934c3049a56SJuan Quintela int ret;
2935c3049a56SJuan Quintela
2936c3049a56SJuan Quintela if (qemu_savevm_state_blocked(&local_err)) {
2937c3049a56SJuan Quintela error_report_err(local_err);
2938c3049a56SJuan Quintela return -EINVAL;
2939c3049a56SJuan Quintela }
2940c3049a56SJuan Quintela
294116015d32SWei Yang ret = qemu_loadvm_state_header(f);
294261964c23SJuan Quintela if (ret) {
294361964c23SJuan Quintela return ret;
294461964c23SJuan Quintela }
294561964c23SJuan Quintela
2946e4fa064dSCédric Le Goater if (qemu_loadvm_state_setup(f, &local_err) != 0) {
2947e4fa064dSCédric Le Goater error_report_err(local_err);
29489e14b849SWei Yang return -EINVAL;
29499e14b849SWei Yang }
29509e14b849SWei Yang
29511b4adb10SAvihai Horon if (migrate_switchover_ack()) {
29521b4adb10SAvihai Horon qemu_loadvm_state_switchover_ack_needed(mis);
29531b4adb10SAvihai Horon }
29541b4adb10SAvihai Horon
295575e972daSDavid Gibson cpu_synchronize_all_pre_loadvm();
295675e972daSDavid Gibson
29577b89bf27SDr. David Alan Gilbert ret = qemu_loadvm_state_main(f, mis);
29587b89bf27SDr. David Alan Gilbert qemu_event_set(&mis->main_thread_load_event);
2959c3049a56SJuan Quintela
29607b89bf27SDr. David Alan Gilbert trace_qemu_loadvm_state_post_main(ret);
2961c3049a56SJuan Quintela
2962c76201abSDr. David Alan Gilbert if (mis->have_listen_thread) {
29634ce56229SFabiano Rosas /*
29644ce56229SFabiano Rosas * Postcopy listen thread still going, don't synchronize the
29654ce56229SFabiano Rosas * cpus yet.
29664ce56229SFabiano Rosas */
2967c76201abSDr. David Alan Gilbert return ret;
2968c76201abSDr. David Alan Gilbert }
2969c76201abSDr. David Alan Gilbert
29707b89bf27SDr. David Alan Gilbert if (ret == 0) {
29717b89bf27SDr. David Alan Gilbert ret = qemu_file_get_error(f);
2972c3049a56SJuan Quintela }
2973c3049a56SJuan Quintela
2974c3049a56SJuan Quintela /*
2975c3049a56SJuan Quintela * Try to read in the VMDESC section as well, so that dumping tools that
2976c3049a56SJuan Quintela * intercept our migration stream have the chance to see it.
2977c3049a56SJuan Quintela */
29781aca9a5fSDr. David Alan Gilbert
29791aca9a5fSDr. David Alan Gilbert /* We've got to be careful; if we don't read the data and just shut the fd
29801aca9a5fSDr. David Alan Gilbert * then the sender can error if we close while it's still sending.
29811aca9a5fSDr. David Alan Gilbert * We also mustn't read data that isn't there; some transports (RDMA)
29821aca9a5fSDr. David Alan Gilbert * will stall waiting for that data when the source has already closed.
29831aca9a5fSDr. David Alan Gilbert */
29847b89bf27SDr. David Alan Gilbert if (ret == 0 && should_send_vmdesc()) {
29851aca9a5fSDr. David Alan Gilbert uint8_t *buf;
29861aca9a5fSDr. David Alan Gilbert uint32_t size;
29877b89bf27SDr. David Alan Gilbert uint8_t section_type = qemu_get_byte(f);
29881aca9a5fSDr. David Alan Gilbert
29891aca9a5fSDr. David Alan Gilbert if (section_type != QEMU_VM_VMDESCRIPTION) {
29901aca9a5fSDr. David Alan Gilbert error_report("Expected vmdescription section, but got %d",
29911aca9a5fSDr. David Alan Gilbert section_type);
29921aca9a5fSDr. David Alan Gilbert /*
29931aca9a5fSDr. David Alan Gilbert * It doesn't seem worth failing at this point since
29941aca9a5fSDr. David Alan Gilbert * we apparently have an otherwise valid VM state
29951aca9a5fSDr. David Alan Gilbert */
29961aca9a5fSDr. David Alan Gilbert } else {
29971aca9a5fSDr. David Alan Gilbert buf = g_malloc(0x1000);
29981aca9a5fSDr. David Alan Gilbert size = qemu_get_be32(f);
2999c3049a56SJuan Quintela
3000c3049a56SJuan Quintela while (size > 0) {
3001c3049a56SJuan Quintela uint32_t read_chunk = MIN(size, 0x1000);
3002c3049a56SJuan Quintela qemu_get_buffer(f, buf, read_chunk);
3003c3049a56SJuan Quintela size -= read_chunk;
3004c3049a56SJuan Quintela }
3005c3049a56SJuan Quintela g_free(buf);
3006c3049a56SJuan Quintela }
30071aca9a5fSDr. David Alan Gilbert }
3008c3049a56SJuan Quintela
3009c3049a56SJuan Quintela cpu_synchronize_all_post_init();
3010c3049a56SJuan Quintela
3011c3049a56SJuan Quintela return ret;
3012c3049a56SJuan Quintela }
3013c3049a56SJuan Quintela
qemu_load_device_state(QEMUFile * f)30143f6df99dSZhang Chen int qemu_load_device_state(QEMUFile *f)
30153f6df99dSZhang Chen {
30163f6df99dSZhang Chen MigrationIncomingState *mis = migration_incoming_get_current();
30173f6df99dSZhang Chen int ret;
30183f6df99dSZhang Chen
30193f6df99dSZhang Chen /* Load QEMU_VM_SECTION_FULL section */
30203f6df99dSZhang Chen ret = qemu_loadvm_state_main(f, mis);
30213f6df99dSZhang Chen if (ret < 0) {
30223f6df99dSZhang Chen error_report("Failed to load device state: %d", ret);
30233f6df99dSZhang Chen return ret;
30243f6df99dSZhang Chen }
30253f6df99dSZhang Chen
30263f6df99dSZhang Chen cpu_synchronize_all_post_init();
30273f6df99dSZhang Chen return 0;
30283f6df99dSZhang Chen }
30293f6df99dSZhang Chen
qemu_loadvm_approve_switchover(void)30301b4adb10SAvihai Horon int qemu_loadvm_approve_switchover(void)
30311b4adb10SAvihai Horon {
30321b4adb10SAvihai Horon MigrationIncomingState *mis = migration_incoming_get_current();
30331b4adb10SAvihai Horon
30341b4adb10SAvihai Horon if (!mis->switchover_ack_pending_num) {
30351b4adb10SAvihai Horon return -EINVAL;
30361b4adb10SAvihai Horon }
30371b4adb10SAvihai Horon
30381b4adb10SAvihai Horon mis->switchover_ack_pending_num--;
30391b4adb10SAvihai Horon trace_loadvm_approve_switchover(mis->switchover_ack_pending_num);
30401b4adb10SAvihai Horon
30411b4adb10SAvihai Horon if (mis->switchover_ack_pending_num) {
30421b4adb10SAvihai Horon return 0;
30431b4adb10SAvihai Horon }
30441b4adb10SAvihai Horon
30451b4adb10SAvihai Horon return migrate_send_rp_switchover_ack(mis);
30461b4adb10SAvihai Horon }
30471b4adb10SAvihai Horon
save_snapshot(const char * name,bool overwrite,const char * vmstate,bool has_devices,strList * devices,Error ** errp)3048f1a9fcddSDaniel P. Berrangé bool save_snapshot(const char *name, bool overwrite, const char *vmstate,
3049f1a9fcddSDaniel P. Berrangé bool has_devices, strList *devices, Error **errp)
3050c3049a56SJuan Quintela {
3051e26f98e2SDaniel P. Berrangé BlockDriverState *bs;
305280ef0586STuguoyi QEMUSnapshotInfo sn1, *sn = &sn1;
305366270a47SDenis V. Lunev int ret = -1, ret2;
3054c3049a56SJuan Quintela QEMUFile *f;
305558b10570SSteve Sistare RunState saved_state = runstate_get();
3056c3049a56SJuan Quintela uint64_t vm_state_size;
305785cd1cc6SDaniel P. Berrangé g_autoptr(GDateTime) now = g_date_time_new_now_local();
3058c3049a56SJuan Quintela
30596b573efeSEmanuele Giuseppe Esposito GLOBAL_STATE_CODE();
30606b573efeSEmanuele Giuseppe Esposito
30615aaac467SPaolo Bonzini if (migration_is_blocked(errp)) {
30627ea14df2SPhilippe Mathieu-Daudé return false;
30635aaac467SPaolo Bonzini }
30645aaac467SPaolo Bonzini
3065377b21ccSPavel Dovgalyuk if (!replay_can_snapshot()) {
30664dd32b3dSMarkus Armbruster error_setg(errp, "Record/replay does not allow making snapshot "
3067377b21ccSPavel Dovgalyuk "right now. Try once more later.");
30687ea14df2SPhilippe Mathieu-Daudé return false;
3069377b21ccSPavel Dovgalyuk }
3070377b21ccSPavel Dovgalyuk
3071f1a9fcddSDaniel P. Berrangé if (!bdrv_all_can_snapshot(has_devices, devices, errp)) {
30727ea14df2SPhilippe Mathieu-Daudé return false;
3073c3049a56SJuan Quintela }
3074c3049a56SJuan Quintela
30750b461605SDenis V. Lunev /* Delete old snapshots of the same name */
3076ac8c19baSPavel Dovgalyuk if (name) {
3077f781f841SDaniel P. Berrangé if (overwrite) {
3078f1a9fcddSDaniel P. Berrangé if (bdrv_all_delete_snapshot(name, has_devices,
3079f1a9fcddSDaniel P. Berrangé devices, errp) < 0) {
30807ea14df2SPhilippe Mathieu-Daudé return false;
3081ac8c19baSPavel Dovgalyuk }
3082f781f841SDaniel P. Berrangé } else {
3083f1a9fcddSDaniel P. Berrangé ret2 = bdrv_all_has_snapshot(name, has_devices, devices, errp);
3084f781f841SDaniel P. Berrangé if (ret2 < 0) {
3085f781f841SDaniel P. Berrangé return false;
3086f781f841SDaniel P. Berrangé }
3087f781f841SDaniel P. Berrangé if (ret2 == 1) {
3088f781f841SDaniel P. Berrangé error_setg(errp,
3089f781f841SDaniel P. Berrangé "Snapshot '%s' already exists in one or more devices",
3090f781f841SDaniel P. Berrangé name);
3091f781f841SDaniel P. Berrangé return false;
3092f781f841SDaniel P. Berrangé }
3093f781f841SDaniel P. Berrangé }
30940b461605SDenis V. Lunev }
30950b461605SDenis V. Lunev
3096f1a9fcddSDaniel P. Berrangé bs = bdrv_all_find_vmstate_bs(vmstate, has_devices, devices, errp);
30977cb14481SDenis V. Lunev if (bs == NULL) {
30987ea14df2SPhilippe Mathieu-Daudé return false;
3099c3049a56SJuan Quintela }
3100c3049a56SJuan Quintela
3101c33f1829SVladimir Sementsov-Ogievskiy global_state_store();
3102c3049a56SJuan Quintela vm_stop(RUN_STATE_SAVE_VM);
3103c3049a56SJuan Quintela
31048649f2f9SStefan Hajnoczi bdrv_drain_all_begin();
31058649f2f9SStefan Hajnoczi
3106c3049a56SJuan Quintela memset(sn, 0, sizeof(*sn));
3107c3049a56SJuan Quintela
3108c3049a56SJuan Quintela /* fill auxiliary fields */
310985cd1cc6SDaniel P. Berrangé sn->date_sec = g_date_time_to_unix(now);
311085cd1cc6SDaniel P. Berrangé sn->date_nsec = g_date_time_get_microsecond(now) * 1000;
3111c3049a56SJuan Quintela sn->vm_clock_nsec = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3112b39847a5SPavel Dovgalyuk if (replay_mode != REPLAY_MODE_NONE) {
3113b39847a5SPavel Dovgalyuk sn->icount = replay_get_current_icount();
3114b39847a5SPavel Dovgalyuk } else {
3115b39847a5SPavel Dovgalyuk sn->icount = -1ULL;
3116b39847a5SPavel Dovgalyuk }
3117c3049a56SJuan Quintela
3118c3049a56SJuan Quintela if (name) {
3119c3049a56SJuan Quintela pstrcpy(sn->name, sizeof(sn->name), name);
3120c3049a56SJuan Quintela } else {
312185cd1cc6SDaniel P. Berrangé g_autofree char *autoname = g_date_time_format(now, "vm-%Y%m%d%H%M%S");
312285cd1cc6SDaniel P. Berrangé pstrcpy(sn->name, sizeof(sn->name), autoname);
3123c3049a56SJuan Quintela }
3124c3049a56SJuan Quintela
3125c3049a56SJuan Quintela /* save the VM state */
3126c3049a56SJuan Quintela f = qemu_fopen_bdrv(bs, 1);
3127c3049a56SJuan Quintela if (!f) {
3128927d6638SJuan Quintela error_setg(errp, "Could not open VM state file");
3129c3049a56SJuan Quintela goto the_end;
3130c3049a56SJuan Quintela }
3131927d6638SJuan Quintela ret = qemu_savevm_state(f, errp);
3132e9c0eed7SJuan Quintela vm_state_size = qemu_file_transferred(f);
313366270a47SDenis V. Lunev ret2 = qemu_fclose(f);
3134c3049a56SJuan Quintela if (ret < 0) {
3135c3049a56SJuan Quintela goto the_end;
3136c3049a56SJuan Quintela }
313766270a47SDenis V. Lunev if (ret2 < 0) {
313866270a47SDenis V. Lunev ret = ret2;
313966270a47SDenis V. Lunev goto the_end;
314066270a47SDenis V. Lunev }
3141c3049a56SJuan Quintela
3142f1a9fcddSDaniel P. Berrangé ret = bdrv_all_create_snapshot(sn, bs, vm_state_size,
3143f1a9fcddSDaniel P. Berrangé has_devices, devices, errp);
3144c3049a56SJuan Quintela if (ret < 0) {
3145f1a9fcddSDaniel P. Berrangé bdrv_all_delete_snapshot(sn->name, has_devices, devices, NULL);
3146ac8c19baSPavel Dovgalyuk goto the_end;
3147c3049a56SJuan Quintela }
3148c3049a56SJuan Quintela
3149ac8c19baSPavel Dovgalyuk ret = 0;
3150ac8c19baSPavel Dovgalyuk
3151c3049a56SJuan Quintela the_end:
31528649f2f9SStefan Hajnoczi bdrv_drain_all_end();
31538649f2f9SStefan Hajnoczi
315458b10570SSteve Sistare vm_resume(saved_state);
31557ea14df2SPhilippe Mathieu-Daudé return ret == 0;
3156ac8c19baSPavel Dovgalyuk }
3157ac8c19baSPavel Dovgalyuk
qmp_xen_save_devices_state(const char * filename,bool has_live,bool live,Error ** errp)31585d6c599fSAnthony PERARD void qmp_xen_save_devices_state(const char *filename, bool has_live, bool live,
31595d6c599fSAnthony PERARD Error **errp)
3160c3049a56SJuan Quintela {
3161c3049a56SJuan Quintela QEMUFile *f;
31628925839fSDaniel P. Berrange QIOChannelFile *ioc;
3163c3049a56SJuan Quintela int saved_vm_running;
3164c3049a56SJuan Quintela int ret;
3165c3049a56SJuan Quintela
31665d6c599fSAnthony PERARD if (!has_live) {
31675d6c599fSAnthony PERARD /* live default to true so old version of Xen tool stack can have a
31683a4452d8Szhaolichang * successful live migration */
31695d6c599fSAnthony PERARD live = true;
31705d6c599fSAnthony PERARD }
31715d6c599fSAnthony PERARD
3172c3049a56SJuan Quintela saved_vm_running = runstate_is_running();
3173c3049a56SJuan Quintela vm_stop(RUN_STATE_SAVE_VM);
3174c69adea4SAnthony PERARD global_state_store_running();
3175c3049a56SJuan Quintela
3176b4deb9bfSDov Murik ioc = qio_channel_file_new_path(filename, O_WRONLY | O_CREAT | O_TRUNC,
3177b4deb9bfSDov Murik 0660, errp);
31788925839fSDaniel P. Berrange if (!ioc) {
3179c3049a56SJuan Quintela goto the_end;
3180c3049a56SJuan Quintela }
31816f01f136SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-save-state");
318277ef2dc1SDaniel P. Berrangé f = qemu_file_new_output(QIO_CHANNEL(ioc));
3183032b79f7SRoss Lagerwall object_unref(OBJECT(ioc));
3184c3049a56SJuan Quintela ret = qemu_save_device_state(f);
318596994fd1SRoss Lagerwall if (ret < 0 || qemu_fclose(f) < 0) {
3186fdac62dbSMarkus Armbruster error_setg(errp, "saving Xen device state failed");
31875d6c599fSAnthony PERARD } else {
31885d6c599fSAnthony PERARD /* libxl calls the QMP command "stop" before calling
31895d6c599fSAnthony PERARD * "xen-save-devices-state" and in case of migration failure, libxl
31905d6c599fSAnthony PERARD * would call "cont".
31915d6c599fSAnthony PERARD * So call bdrv_inactivate_all (release locks) here to let the other
31923a4452d8Szhaolichang * side of the migration take control of the images.
31935d6c599fSAnthony PERARD */
31945d6c599fSAnthony PERARD if (live && !saved_vm_running) {
31955d6c599fSAnthony PERARD ret = bdrv_inactivate_all();
31965d6c599fSAnthony PERARD if (ret) {
31975d6c599fSAnthony PERARD error_setg(errp, "%s: bdrv_inactivate_all() failed (%d)",
31985d6c599fSAnthony PERARD __func__, ret);
31995d6c599fSAnthony PERARD }
32005d6c599fSAnthony PERARD }
3201c3049a56SJuan Quintela }
3202c3049a56SJuan Quintela
3203c3049a56SJuan Quintela the_end:
3204c3049a56SJuan Quintela if (saved_vm_running) {
3205c3049a56SJuan Quintela vm_start();
3206c3049a56SJuan Quintela }
3207c3049a56SJuan Quintela }
3208c3049a56SJuan Quintela
qmp_xen_load_devices_state(const char * filename,Error ** errp)320988c16567SWen Congyang void qmp_xen_load_devices_state(const char *filename, Error **errp)
321088c16567SWen Congyang {
321188c16567SWen Congyang QEMUFile *f;
321288c16567SWen Congyang QIOChannelFile *ioc;
321388c16567SWen Congyang int ret;
321488c16567SWen Congyang
321588c16567SWen Congyang /* Guest must be paused before loading the device state; the RAM state
321688c16567SWen Congyang * will already have been loaded by xc
321788c16567SWen Congyang */
321888c16567SWen Congyang if (runstate_is_running()) {
321988c16567SWen Congyang error_setg(errp, "Cannot update device state while vm is running");
322088c16567SWen Congyang return;
322188c16567SWen Congyang }
322288c16567SWen Congyang vm_stop(RUN_STATE_RESTORE_VM);
322388c16567SWen Congyang
322488c16567SWen Congyang ioc = qio_channel_file_new_path(filename, O_RDONLY | O_BINARY, 0, errp);
322588c16567SWen Congyang if (!ioc) {
322688c16567SWen Congyang return;
322788c16567SWen Congyang }
32286f01f136SDaniel P. Berrange qio_channel_set_name(QIO_CHANNEL(ioc), "migration-xen-load-state");
322977ef2dc1SDaniel P. Berrangé f = qemu_file_new_input(QIO_CHANNEL(ioc));
3230032b79f7SRoss Lagerwall object_unref(OBJECT(ioc));
323188c16567SWen Congyang
323288c16567SWen Congyang ret = qemu_loadvm_state(f);
323388c16567SWen Congyang qemu_fclose(f);
323488c16567SWen Congyang if (ret < 0) {
3235fdac62dbSMarkus Armbruster error_setg(errp, "loading Xen device state failed");
323688c16567SWen Congyang }
323788c16567SWen Congyang migration_incoming_state_destroy();
323888c16567SWen Congyang }
323988c16567SWen Congyang
load_snapshot(const char * name,const char * vmstate,bool has_devices,strList * devices,Error ** errp)3240f1a9fcddSDaniel P. Berrangé bool load_snapshot(const char *name, const char *vmstate,
3241f1a9fcddSDaniel P. Berrangé bool has_devices, strList *devices, Error **errp)
3242c3049a56SJuan Quintela {
3243e26f98e2SDaniel P. Berrangé BlockDriverState *bs_vm_state;
3244c3049a56SJuan Quintela QEMUSnapshotInfo sn;
3245c3049a56SJuan Quintela QEMUFile *f;
3246c3049a56SJuan Quintela int ret;
3247b4b076daSJuan Quintela MigrationIncomingState *mis = migration_incoming_get_current();
3248c3049a56SJuan Quintela
3249f1a9fcddSDaniel P. Berrangé if (!bdrv_all_can_snapshot(has_devices, devices, errp)) {
3250f61fe11aSDaniel P. Berrangé return false;
3251849f96e2SDenis V. Lunev }
3252f1a9fcddSDaniel P. Berrangé ret = bdrv_all_has_snapshot(name, has_devices, devices, errp);
3253723ccda1SDenis V. Lunev if (ret < 0) {
3254f61fe11aSDaniel P. Berrangé return false;
3255723ccda1SDenis V. Lunev }
32563d3e9b1fSDaniel P. Berrangé if (ret == 0) {
32573d3e9b1fSDaniel P. Berrangé error_setg(errp, "Snapshot '%s' does not exist in one or more devices",
32583d3e9b1fSDaniel P. Berrangé name);
32593d3e9b1fSDaniel P. Berrangé return false;
32603d3e9b1fSDaniel P. Berrangé }
3261849f96e2SDenis V. Lunev
3262f1a9fcddSDaniel P. Berrangé bs_vm_state = bdrv_all_find_vmstate_bs(vmstate, has_devices, devices, errp);
3263c3049a56SJuan Quintela if (!bs_vm_state) {
3264f61fe11aSDaniel P. Berrangé return false;
3265c3049a56SJuan Quintela }
3266c3049a56SJuan Quintela
3267c3049a56SJuan Quintela /* Don't even try to load empty VM states */
3268c3049a56SJuan Quintela ret = bdrv_snapshot_find(bs_vm_state, &sn, name);
3269c3049a56SJuan Quintela if (ret < 0) {
327097d2b66dSNicholas Piggin error_setg(errp, "Snapshot can not be found");
3271f61fe11aSDaniel P. Berrangé return false;
3272c3049a56SJuan Quintela } else if (sn.vm_state_size == 0) {
3273927d6638SJuan Quintela error_setg(errp, "This is a disk-only snapshot. Revert to it "
3274927d6638SJuan Quintela " offline using qemu-img");
3275f61fe11aSDaniel P. Berrangé return false;
3276c3049a56SJuan Quintela }
3277c3049a56SJuan Quintela
3278f9a9fb65SPavel Dovgalyuk /*
3279f9a9fb65SPavel Dovgalyuk * Flush the record/replay queue. Now the VM state is going
3280f9a9fb65SPavel Dovgalyuk * to change. Therefore we don't need to preserve its consistency
3281f9a9fb65SPavel Dovgalyuk */
3282f9a9fb65SPavel Dovgalyuk replay_flush_events();
3283f9a9fb65SPavel Dovgalyuk
3284c3049a56SJuan Quintela /* Flush all IO requests so they don't interfere with the new state. */
32858649f2f9SStefan Hajnoczi bdrv_drain_all_begin();
3286c3049a56SJuan Quintela
3287f1a9fcddSDaniel P. Berrangé ret = bdrv_all_goto_snapshot(name, has_devices, devices, errp);
3288c3049a56SJuan Quintela if (ret < 0) {
32898649f2f9SStefan Hajnoczi goto err_drain;
3290c3049a56SJuan Quintela }
3291c3049a56SJuan Quintela
3292c3049a56SJuan Quintela /* restore the VM state */
3293c3049a56SJuan Quintela f = qemu_fopen_bdrv(bs_vm_state, 0);
3294c3049a56SJuan Quintela if (!f) {
3295927d6638SJuan Quintela error_setg(errp, "Could not open VM state file");
32968649f2f9SStefan Hajnoczi goto err_drain;
3297c3049a56SJuan Quintela }
3298c3049a56SJuan Quintela
32997966d70fSJason A. Donenfeld qemu_system_reset(SHUTDOWN_CAUSE_SNAPSHOT_LOAD);
3300b4b076daSJuan Quintela mis->from_src_file = f;
3301c3049a56SJuan Quintela
3302b5eea99eSLukas Straub if (!yank_register_instance(MIGRATION_YANK_INSTANCE, errp)) {
3303b5eea99eSLukas Straub ret = -EINVAL;
3304b5eea99eSLukas Straub goto err_drain;
3305b5eea99eSLukas Straub }
330679b3c12aSDenis V. Lunev ret = qemu_loadvm_state(f);
33071575829dSStefan Hajnoczi migration_incoming_state_destroy();
330879b3c12aSDenis V. Lunev
33098649f2f9SStefan Hajnoczi bdrv_drain_all_end();
33108649f2f9SStefan Hajnoczi
3311c3049a56SJuan Quintela if (ret < 0) {
3312927d6638SJuan Quintela error_setg(errp, "Error %d while loading VM state", ret);
3313f61fe11aSDaniel P. Berrangé return false;
3314c3049a56SJuan Quintela }
3315c3049a56SJuan Quintela
3316f61fe11aSDaniel P. Berrangé return true;
33178649f2f9SStefan Hajnoczi
33188649f2f9SStefan Hajnoczi err_drain:
33198649f2f9SStefan Hajnoczi bdrv_drain_all_end();
3320f61fe11aSDaniel P. Berrangé return false;
3321c3049a56SJuan Quintela }
3322c3049a56SJuan Quintela
load_snapshot_resume(RunState state)332358b10570SSteve Sistare void load_snapshot_resume(RunState state)
332458b10570SSteve Sistare {
332558b10570SSteve Sistare vm_resume(state);
332658b10570SSteve Sistare if (state == RUN_STATE_RUNNING && runstate_get() == RUN_STATE_SUSPENDED) {
332758b10570SSteve Sistare qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, &error_abort);
332858b10570SSteve Sistare }
332958b10570SSteve Sistare }
333058b10570SSteve Sistare
delete_snapshot(const char * name,bool has_devices,strList * devices,Error ** errp)3331bef7e9e2SDaniel P. Berrangé bool delete_snapshot(const char *name, bool has_devices,
3332bef7e9e2SDaniel P. Berrangé strList *devices, Error **errp)
3333bef7e9e2SDaniel P. Berrangé {
3334bef7e9e2SDaniel P. Berrangé if (!bdrv_all_can_snapshot(has_devices, devices, errp)) {
3335bef7e9e2SDaniel P. Berrangé return false;
3336bef7e9e2SDaniel P. Berrangé }
3337bef7e9e2SDaniel P. Berrangé
3338bef7e9e2SDaniel P. Berrangé if (bdrv_all_delete_snapshot(name, has_devices, devices, errp) < 0) {
3339bef7e9e2SDaniel P. Berrangé return false;
3340bef7e9e2SDaniel P. Berrangé }
3341bef7e9e2SDaniel P. Berrangé
3342bef7e9e2SDaniel P. Berrangé return true;
3343bef7e9e2SDaniel P. Berrangé }
3344bef7e9e2SDaniel P. Berrangé
vmstate_register_ram(MemoryRegion * mr,DeviceState * dev)3345c3049a56SJuan Quintela void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev)
3346c3049a56SJuan Quintela {
3347fa53a0e5SGonglei qemu_ram_set_idstr(mr->ram_block,
3348c3049a56SJuan Quintela memory_region_name(mr), dev);
3349b895de50SCédric Le Goater qemu_ram_set_migratable(mr->ram_block);
3350c3049a56SJuan Quintela }
3351c3049a56SJuan Quintela
vmstate_unregister_ram(MemoryRegion * mr,DeviceState * dev)3352c3049a56SJuan Quintela void vmstate_unregister_ram(MemoryRegion *mr, DeviceState *dev)
3353c3049a56SJuan Quintela {
3354fa53a0e5SGonglei qemu_ram_unset_idstr(mr->ram_block);
3355b895de50SCédric Le Goater qemu_ram_unset_migratable(mr->ram_block);
3356c3049a56SJuan Quintela }
3357c3049a56SJuan Quintela
vmstate_register_ram_global(MemoryRegion * mr)3358c3049a56SJuan Quintela void vmstate_register_ram_global(MemoryRegion *mr)
3359c3049a56SJuan Quintela {
3360c3049a56SJuan Quintela vmstate_register_ram(mr, NULL);
3361c3049a56SJuan Quintela }
33621bfe5f05SJuan Quintela
vmstate_check_only_migratable(const VMStateDescription * vmsd)33631bfe5f05SJuan Quintela bool vmstate_check_only_migratable(const VMStateDescription *vmsd)
33641bfe5f05SJuan Quintela {
33651bfe5f05SJuan Quintela /* check needed if --only-migratable is specified */
3366811f8652SMarkus Armbruster if (!only_migratable) {
33671bfe5f05SJuan Quintela return true;
33681bfe5f05SJuan Quintela }
33691bfe5f05SJuan Quintela
33701bfe5f05SJuan Quintela return !(vmsd && vmsd->unmigratable);
33711bfe5f05SJuan Quintela }
33720f0d83a4SDaniel P. Berrangé
33730f0d83a4SDaniel P. Berrangé typedef struct SnapshotJob {
33740f0d83a4SDaniel P. Berrangé Job common;
33750f0d83a4SDaniel P. Berrangé char *tag;
33760f0d83a4SDaniel P. Berrangé char *vmstate;
33770f0d83a4SDaniel P. Berrangé strList *devices;
33780f0d83a4SDaniel P. Berrangé Coroutine *co;
33790f0d83a4SDaniel P. Berrangé Error **errp;
33800f0d83a4SDaniel P. Berrangé bool ret;
33810f0d83a4SDaniel P. Berrangé } SnapshotJob;
33820f0d83a4SDaniel P. Berrangé
qmp_snapshot_job_free(SnapshotJob * s)33830f0d83a4SDaniel P. Berrangé static void qmp_snapshot_job_free(SnapshotJob *s)
33840f0d83a4SDaniel P. Berrangé {
33850f0d83a4SDaniel P. Berrangé g_free(s->tag);
33860f0d83a4SDaniel P. Berrangé g_free(s->vmstate);
33870f0d83a4SDaniel P. Berrangé qapi_free_strList(s->devices);
33880f0d83a4SDaniel P. Berrangé }
33890f0d83a4SDaniel P. Berrangé
33900f0d83a4SDaniel P. Berrangé
snapshot_load_job_bh(void * opaque)33910f0d83a4SDaniel P. Berrangé static void snapshot_load_job_bh(void *opaque)
33920f0d83a4SDaniel P. Berrangé {
33930f0d83a4SDaniel P. Berrangé Job *job = opaque;
33940f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
339558b10570SSteve Sistare RunState orig_state = runstate_get();
33960f0d83a4SDaniel P. Berrangé
33970f0d83a4SDaniel P. Berrangé job_progress_set_remaining(&s->common, 1);
33980f0d83a4SDaniel P. Berrangé
33990f0d83a4SDaniel P. Berrangé vm_stop(RUN_STATE_RESTORE_VM);
34000f0d83a4SDaniel P. Berrangé
34010f0d83a4SDaniel P. Berrangé s->ret = load_snapshot(s->tag, s->vmstate, true, s->devices, s->errp);
340258b10570SSteve Sistare if (s->ret) {
340358b10570SSteve Sistare load_snapshot_resume(orig_state);
34040f0d83a4SDaniel P. Berrangé }
34050f0d83a4SDaniel P. Berrangé
34060f0d83a4SDaniel P. Berrangé job_progress_update(&s->common, 1);
34070f0d83a4SDaniel P. Berrangé
34080f0d83a4SDaniel P. Berrangé qmp_snapshot_job_free(s);
34090f0d83a4SDaniel P. Berrangé aio_co_wake(s->co);
34100f0d83a4SDaniel P. Berrangé }
34110f0d83a4SDaniel P. Berrangé
snapshot_save_job_bh(void * opaque)34120f0d83a4SDaniel P. Berrangé static void snapshot_save_job_bh(void *opaque)
34130f0d83a4SDaniel P. Berrangé {
34140f0d83a4SDaniel P. Berrangé Job *job = opaque;
34150f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34160f0d83a4SDaniel P. Berrangé
34170f0d83a4SDaniel P. Berrangé job_progress_set_remaining(&s->common, 1);
34180f0d83a4SDaniel P. Berrangé s->ret = save_snapshot(s->tag, false, s->vmstate,
34190f0d83a4SDaniel P. Berrangé true, s->devices, s->errp);
34200f0d83a4SDaniel P. Berrangé job_progress_update(&s->common, 1);
34210f0d83a4SDaniel P. Berrangé
34220f0d83a4SDaniel P. Berrangé qmp_snapshot_job_free(s);
34230f0d83a4SDaniel P. Berrangé aio_co_wake(s->co);
34240f0d83a4SDaniel P. Berrangé }
34250f0d83a4SDaniel P. Berrangé
snapshot_delete_job_bh(void * opaque)34260f0d83a4SDaniel P. Berrangé static void snapshot_delete_job_bh(void *opaque)
34270f0d83a4SDaniel P. Berrangé {
34280f0d83a4SDaniel P. Berrangé Job *job = opaque;
34290f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34300f0d83a4SDaniel P. Berrangé
34310f0d83a4SDaniel P. Berrangé job_progress_set_remaining(&s->common, 1);
34320f0d83a4SDaniel P. Berrangé s->ret = delete_snapshot(s->tag, true, s->devices, s->errp);
34330f0d83a4SDaniel P. Berrangé job_progress_update(&s->common, 1);
34340f0d83a4SDaniel P. Berrangé
34350f0d83a4SDaniel P. Berrangé qmp_snapshot_job_free(s);
34360f0d83a4SDaniel P. Berrangé aio_co_wake(s->co);
34370f0d83a4SDaniel P. Berrangé }
34380f0d83a4SDaniel P. Berrangé
snapshot_save_job_run(Job * job,Error ** errp)34390f0d83a4SDaniel P. Berrangé static int coroutine_fn snapshot_save_job_run(Job *job, Error **errp)
34400f0d83a4SDaniel P. Berrangé {
34410f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34420f0d83a4SDaniel P. Berrangé s->errp = errp;
34430f0d83a4SDaniel P. Berrangé s->co = qemu_coroutine_self();
34440f0d83a4SDaniel P. Berrangé aio_bh_schedule_oneshot(qemu_get_aio_context(),
34450f0d83a4SDaniel P. Berrangé snapshot_save_job_bh, job);
34460f0d83a4SDaniel P. Berrangé qemu_coroutine_yield();
34470f0d83a4SDaniel P. Berrangé return s->ret ? 0 : -1;
34480f0d83a4SDaniel P. Berrangé }
34490f0d83a4SDaniel P. Berrangé
snapshot_load_job_run(Job * job,Error ** errp)34500f0d83a4SDaniel P. Berrangé static int coroutine_fn snapshot_load_job_run(Job *job, Error **errp)
34510f0d83a4SDaniel P. Berrangé {
34520f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34530f0d83a4SDaniel P. Berrangé s->errp = errp;
34540f0d83a4SDaniel P. Berrangé s->co = qemu_coroutine_self();
34550f0d83a4SDaniel P. Berrangé aio_bh_schedule_oneshot(qemu_get_aio_context(),
34560f0d83a4SDaniel P. Berrangé snapshot_load_job_bh, job);
34570f0d83a4SDaniel P. Berrangé qemu_coroutine_yield();
34580f0d83a4SDaniel P. Berrangé return s->ret ? 0 : -1;
34590f0d83a4SDaniel P. Berrangé }
34600f0d83a4SDaniel P. Berrangé
snapshot_delete_job_run(Job * job,Error ** errp)34610f0d83a4SDaniel P. Berrangé static int coroutine_fn snapshot_delete_job_run(Job *job, Error **errp)
34620f0d83a4SDaniel P. Berrangé {
34630f0d83a4SDaniel P. Berrangé SnapshotJob *s = container_of(job, SnapshotJob, common);
34640f0d83a4SDaniel P. Berrangé s->errp = errp;
34650f0d83a4SDaniel P. Berrangé s->co = qemu_coroutine_self();
34660f0d83a4SDaniel P. Berrangé aio_bh_schedule_oneshot(qemu_get_aio_context(),
34670f0d83a4SDaniel P. Berrangé snapshot_delete_job_bh, job);
34680f0d83a4SDaniel P. Berrangé qemu_coroutine_yield();
34690f0d83a4SDaniel P. Berrangé return s->ret ? 0 : -1;
34700f0d83a4SDaniel P. Berrangé }
34710f0d83a4SDaniel P. Berrangé
34720f0d83a4SDaniel P. Berrangé
34730f0d83a4SDaniel P. Berrangé static const JobDriver snapshot_load_job_driver = {
34740f0d83a4SDaniel P. Berrangé .instance_size = sizeof(SnapshotJob),
34750f0d83a4SDaniel P. Berrangé .job_type = JOB_TYPE_SNAPSHOT_LOAD,
34760f0d83a4SDaniel P. Berrangé .run = snapshot_load_job_run,
34770f0d83a4SDaniel P. Berrangé };
34780f0d83a4SDaniel P. Berrangé
34790f0d83a4SDaniel P. Berrangé static const JobDriver snapshot_save_job_driver = {
34800f0d83a4SDaniel P. Berrangé .instance_size = sizeof(SnapshotJob),
34810f0d83a4SDaniel P. Berrangé .job_type = JOB_TYPE_SNAPSHOT_SAVE,
34820f0d83a4SDaniel P. Berrangé .run = snapshot_save_job_run,
34830f0d83a4SDaniel P. Berrangé };
34840f0d83a4SDaniel P. Berrangé
34850f0d83a4SDaniel P. Berrangé static const JobDriver snapshot_delete_job_driver = {
34860f0d83a4SDaniel P. Berrangé .instance_size = sizeof(SnapshotJob),
34870f0d83a4SDaniel P. Berrangé .job_type = JOB_TYPE_SNAPSHOT_DELETE,
34880f0d83a4SDaniel P. Berrangé .run = snapshot_delete_job_run,
34890f0d83a4SDaniel P. Berrangé };
34900f0d83a4SDaniel P. Berrangé
34910f0d83a4SDaniel P. Berrangé
qmp_snapshot_save(const char * job_id,const char * tag,const char * vmstate,strList * devices,Error ** errp)34920f0d83a4SDaniel P. Berrangé void qmp_snapshot_save(const char *job_id,
34930f0d83a4SDaniel P. Berrangé const char *tag,
34940f0d83a4SDaniel P. Berrangé const char *vmstate,
34950f0d83a4SDaniel P. Berrangé strList *devices,
34960f0d83a4SDaniel P. Berrangé Error **errp)
34970f0d83a4SDaniel P. Berrangé {
34980f0d83a4SDaniel P. Berrangé SnapshotJob *s;
34990f0d83a4SDaniel P. Berrangé
35000f0d83a4SDaniel P. Berrangé s = job_create(job_id, &snapshot_save_job_driver, NULL,
35010f0d83a4SDaniel P. Berrangé qemu_get_aio_context(), JOB_MANUAL_DISMISS,
35020f0d83a4SDaniel P. Berrangé NULL, NULL, errp);
35030f0d83a4SDaniel P. Berrangé if (!s) {
35040f0d83a4SDaniel P. Berrangé return;
35050f0d83a4SDaniel P. Berrangé }
35060f0d83a4SDaniel P. Berrangé
35070f0d83a4SDaniel P. Berrangé s->tag = g_strdup(tag);
35080f0d83a4SDaniel P. Berrangé s->vmstate = g_strdup(vmstate);
35090f0d83a4SDaniel P. Berrangé s->devices = QAPI_CLONE(strList, devices);
35100f0d83a4SDaniel P. Berrangé
35110f0d83a4SDaniel P. Berrangé job_start(&s->common);
35120f0d83a4SDaniel P. Berrangé }
35130f0d83a4SDaniel P. Berrangé
qmp_snapshot_load(const char * job_id,const char * tag,const char * vmstate,strList * devices,Error ** errp)35140f0d83a4SDaniel P. Berrangé void qmp_snapshot_load(const char *job_id,
35150f0d83a4SDaniel P. Berrangé const char *tag,
35160f0d83a4SDaniel P. Berrangé const char *vmstate,
35170f0d83a4SDaniel P. Berrangé strList *devices,
35180f0d83a4SDaniel P. Berrangé Error **errp)
35190f0d83a4SDaniel P. Berrangé {
35200f0d83a4SDaniel P. Berrangé SnapshotJob *s;
35210f0d83a4SDaniel P. Berrangé
35220f0d83a4SDaniel P. Berrangé s = job_create(job_id, &snapshot_load_job_driver, NULL,
35230f0d83a4SDaniel P. Berrangé qemu_get_aio_context(), JOB_MANUAL_DISMISS,
35240f0d83a4SDaniel P. Berrangé NULL, NULL, errp);
35250f0d83a4SDaniel P. Berrangé if (!s) {
35260f0d83a4SDaniel P. Berrangé return;
35270f0d83a4SDaniel P. Berrangé }
35280f0d83a4SDaniel P. Berrangé
35290f0d83a4SDaniel P. Berrangé s->tag = g_strdup(tag);
35300f0d83a4SDaniel P. Berrangé s->vmstate = g_strdup(vmstate);
35310f0d83a4SDaniel P. Berrangé s->devices = QAPI_CLONE(strList, devices);
35320f0d83a4SDaniel P. Berrangé
35330f0d83a4SDaniel P. Berrangé job_start(&s->common);
35340f0d83a4SDaniel P. Berrangé }
35350f0d83a4SDaniel P. Berrangé
qmp_snapshot_delete(const char * job_id,const char * tag,strList * devices,Error ** errp)35360f0d83a4SDaniel P. Berrangé void qmp_snapshot_delete(const char *job_id,
35370f0d83a4SDaniel P. Berrangé const char *tag,
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_delete_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->devices = QAPI_CLONE(strList, devices);
35520f0d83a4SDaniel P. Berrangé
35530f0d83a4SDaniel P. Berrangé job_start(&s->common);
35540f0d83a4SDaniel P. Berrangé }
3555