diff options
Diffstat (limited to 'migration/savevm.c')
-rw-r--r-- | migration/savevm.c | 329 |
1 files changed, 190 insertions, 139 deletions
diff --git a/migration/savevm.c b/migration/savevm.c index abe0547..7b35ec4 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -963,13 +963,20 @@ void vmstate_unregister(VMStateIf *obj, const VMStateDescription *vmsd, } } -static int vmstate_load(QEMUFile *f, SaveStateEntry *se) +static int vmstate_load(QEMUFile *f, SaveStateEntry *se, Error **errp) { + int ret; trace_vmstate_load(se->idstr, se->vmsd ? se->vmsd->name : "(old)"); if (!se->vmsd) { /* Old style */ - return se->ops->load_state(f, se->opaque, se->load_version_id); + ret = se->ops->load_state(f, se->opaque, se->load_version_id); + if (ret < 0) { + error_setg(errp, "Failed to load vmstate version_id: %d, ret: %d", + se->load_version_id, ret); + } + return ret; } - return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id); + return vmstate_load_state(f, se->vmsd, se->opaque, se->load_version_id, + errp); } static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se, @@ -1049,8 +1056,8 @@ static int vmstate_save(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc, if (!se->vmsd) { vmstate_save_old_style(f, se, vmdesc); } else { - ret = vmstate_save_state_with_err(f, se->vmsd, se->opaque, vmdesc, - errp); + ret = vmstate_save_state(f, se->vmsd, se->opaque, vmdesc, + errp); if (ret) { return ret; } @@ -1278,6 +1285,7 @@ void qemu_savevm_state_header(QEMUFile *f) { MigrationState *s = migrate_get_current(); JSONWriter *vmdesc = s->vmdesc; + Error *local_err = NULL; trace_savevm_state_header(); qemu_put_be32(f, QEMU_VM_FILE_MAGIC); @@ -1296,7 +1304,11 @@ void qemu_savevm_state_header(QEMUFile *f) json_writer_start_object(vmdesc, "configuration"); } - vmstate_save_state(f, &vmstate_configuration, &savevm_state, vmdesc); + vmstate_save_state(f, &vmstate_configuration, &savevm_state, + vmdesc, &local_err); + if (local_err) { + error_report_err(local_err); + } if (vmdesc) { json_writer_end_object(vmdesc); @@ -1905,39 +1917,39 @@ enum LoadVMExitCodes { * quickly. */ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis, - uint16_t len) + uint16_t len, Error **errp) { PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_ADVISE); uint64_t remote_pagesize_summary, local_pagesize_summary, remote_tps; size_t page_size = qemu_target_page_size(); - Error *local_err = NULL; trace_loadvm_postcopy_handle_advise(); if (ps != POSTCOPY_INCOMING_NONE) { - error_report("CMD_POSTCOPY_ADVISE in wrong postcopy state (%d)", ps); + error_setg(errp, "CMD_POSTCOPY_ADVISE in wrong postcopy state (%d)", + ps); return -1; } switch (len) { case 0: if (migrate_postcopy_ram()) { - error_report("RAM postcopy is enabled but have 0 byte advise"); + error_setg(errp, "RAM postcopy is enabled but have 0 byte advise"); return -EINVAL; } return 0; case 8 + 8: if (!migrate_postcopy_ram()) { - error_report("RAM postcopy is disabled but have 16 byte advise"); + error_setg(errp, + "RAM postcopy is disabled but have 16 byte advise"); return -EINVAL; } break; default: - error_report("CMD_POSTCOPY_ADVISE invalid length (%d)", len); + error_setg(errp, "CMD_POSTCOPY_ADVISE invalid length (%d)", len); return -EINVAL; } - if (!postcopy_ram_supported_by_host(mis, &local_err)) { - error_report_err(local_err); + if (!postcopy_ram_supported_by_host(mis, errp)) { postcopy_state_set(POSTCOPY_INCOMING_NONE); return -1; } @@ -1960,9 +1972,10 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis, * also fails when passed to an older qemu that doesn't * do huge pages. */ - error_report("Postcopy needs matching RAM page sizes (s=%" PRIx64 - " d=%" PRIx64 ")", - remote_pagesize_summary, local_pagesize_summary); + error_setg(errp, + "Postcopy needs matching RAM page sizes " + "(s=%" PRIx64 " d=%" PRIx64 ")", + remote_pagesize_summary, local_pagesize_summary); return -1; } @@ -1972,17 +1985,18 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis, * Again, some differences could be dealt with, but for now keep it * simple. */ - error_report("Postcopy needs matching target page sizes (s=%d d=%zd)", - (int)remote_tps, page_size); + error_setg(errp, + "Postcopy needs matching target page sizes (s=%d d=%zd)", + (int)remote_tps, page_size); return -1; } - if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, &local_err)) { - error_report_err(local_err); + if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_ADVISE, errp)) { return -1; } - if (ram_postcopy_incoming_init(mis)) { + if (ram_postcopy_incoming_init(mis, errp) < 0) { + error_prepend(errp, "Postcopy RAM incoming init failed: "); return -1; } @@ -1995,7 +2009,7 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis, * There can be 0..many of these messages, each encoding multiple pages. */ static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis, - uint16_t len) + uint16_t len, Error **errp) { int tmp; char ramid[256]; @@ -2008,6 +2022,7 @@ static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis, /* 1st discard */ tmp = postcopy_ram_prepare_discard(mis); if (tmp) { + error_setg(errp, "Failed to prepare for RAM discard: %d", tmp); return tmp; } break; @@ -2017,8 +2032,9 @@ static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis, break; default: - error_report("CMD_POSTCOPY_RAM_DISCARD in wrong postcopy state (%d)", - ps); + error_setg(errp, + "CMD_POSTCOPY_RAM_DISCARD in wrong postcopy state (%d)", + ps); return -1; } /* We're expecting a @@ -2027,29 +2043,30 @@ static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis, * then at least 1 16 byte chunk */ if (len < (1 + 1 + 1 + 1 + 2 * 8)) { - error_report("CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len); + error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len); return -1; } tmp = qemu_get_byte(mis->from_src_file); if (tmp != postcopy_ram_discard_version) { - error_report("CMD_POSTCOPY_RAM_DISCARD invalid version (%d)", tmp); + error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD invalid version (%d)", tmp); return -1; } if (!qemu_get_counted_string(mis->from_src_file, ramid)) { - error_report("CMD_POSTCOPY_RAM_DISCARD Failed to read RAMBlock ID"); + error_setg(errp, + "CMD_POSTCOPY_RAM_DISCARD Failed to read RAMBlock ID"); return -1; } tmp = qemu_get_byte(mis->from_src_file); if (tmp != 0) { - error_report("CMD_POSTCOPY_RAM_DISCARD missing nil (%d)", tmp); + error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD missing nil (%d)", tmp); return -1; } len -= 3 + strlen(ramid); if (len % 16) { - error_report("CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len); + error_setg(errp, "CMD_POSTCOPY_RAM_DISCARD invalid length (%d)", len); return -1; } trace_loadvm_postcopy_ram_handle_discard_header(ramid, len); @@ -2061,6 +2078,7 @@ static int loadvm_postcopy_ram_handle_discard(MigrationIncomingState *mis, len -= 16; int ret = ram_discard_range(ramid, start_addr, block_length); if (ret) { + error_setg(errp, "Failed to discard RAM range %s: %d", ramid, ret); return ret; } } @@ -2082,6 +2100,7 @@ static void *postcopy_ram_listen_thread(void *opaque) QEMUFile *f = mis->from_src_file; int load_res; MigrationState *migr = migrate_get_current(); + Error *local_err = NULL; object_ref(OBJECT(migr)); @@ -2098,7 +2117,7 @@ static void *postcopy_ram_listen_thread(void *opaque) qemu_file_set_blocking(f, true, &error_fatal); /* TODO: sanity check that only postcopiable data will be loaded here */ - load_res = qemu_loadvm_state_main(f, mis); + load_res = qemu_loadvm_state_main(f, mis, &local_err); /* * This is tricky, but, mis->from_src_file can change after it @@ -2124,7 +2143,10 @@ static void *postcopy_ram_listen_thread(void *opaque) __func__, load_res); load_res = 0; /* prevent further exit() */ } else { - error_report("%s: loadvm failed: %d", __func__, load_res); + error_prepend(&local_err, + "loadvm failed during postcopy: %d: ", load_res); + migrate_set_error(migr, local_err); + error_report_err(local_err); migrate_set_state(&mis->state, MIGRATION_STATUS_POSTCOPY_ACTIVE, MIGRATION_STATUS_FAILED); } @@ -2172,15 +2194,16 @@ static void *postcopy_ram_listen_thread(void *opaque) } /* After this message we must be able to immediately receive postcopy data */ -static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis) +static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis, + Error **errp) { PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_LISTENING); - Error *local_err = NULL; trace_loadvm_postcopy_handle_listen("enter"); if (ps != POSTCOPY_INCOMING_ADVISE && ps != POSTCOPY_INCOMING_DISCARD) { - error_report("CMD_POSTCOPY_LISTEN in wrong postcopy state (%d)", ps); + error_setg(errp, + "CMD_POSTCOPY_LISTEN in wrong postcopy state (%d)", ps); return -1; } if (ps == POSTCOPY_INCOMING_ADVISE) { @@ -2203,14 +2226,14 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis) if (migrate_postcopy_ram()) { if (postcopy_ram_incoming_setup(mis)) { postcopy_ram_incoming_cleanup(mis); + error_setg(errp, "Failed to setup incoming postcopy RAM blocks"); return -1; } } trace_loadvm_postcopy_handle_listen("after uffd"); - if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_LISTEN, &local_err)) { - error_report_err(local_err); + if (postcopy_notify(POSTCOPY_NOTIFY_INBOUND_LISTEN, errp)) { return -1; } @@ -2263,13 +2286,13 @@ static void loadvm_postcopy_handle_run_bh(void *opaque) } /* After all discards we can start running and asking for pages */ -static int loadvm_postcopy_handle_run(MigrationIncomingState *mis) +static int loadvm_postcopy_handle_run(MigrationIncomingState *mis, Error **errp) { PostcopyState ps = postcopy_state_get(); trace_loadvm_postcopy_handle_run(); if (ps != POSTCOPY_INCOMING_LISTENING) { - error_report("CMD_POSTCOPY_RUN in wrong postcopy state (%d)", ps); + error_setg(errp, "CMD_POSTCOPY_RUN in wrong postcopy state (%d)", ps); return -1; } @@ -2327,12 +2350,12 @@ static void migrate_send_rp_req_pages_pending(MigrationIncomingState *mis) } } -static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis) +static void loadvm_postcopy_handle_resume(MigrationIncomingState *mis) { if (mis->state != MIGRATION_STATUS_POSTCOPY_RECOVER) { - error_report("%s: illegal resume received", __func__); + warn_report("%s: illegal resume received", __func__); /* Don't fail the load, only for this. */ - return 0; + return; } /* @@ -2384,8 +2407,6 @@ static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis) /* Kick the fast ram load thread too */ qemu_sem_post(&mis->postcopy_pause_sem_fast_load); } - - return 0; } /** @@ -2398,7 +2419,7 @@ static int loadvm_postcopy_handle_resume(MigrationIncomingState *mis) * Returns: Negative values on error * */ -static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis) +static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis, Error **errp) { int ret; size_t length; @@ -2408,7 +2429,7 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis) trace_loadvm_handle_cmd_packaged(length); if (length > MAX_VM_CMD_PACKAGED_SIZE) { - error_report("Unreasonably large packaged state: %zu", length); + error_setg(errp, "Unreasonably large packaged state: %zu", length); return -1; } @@ -2419,8 +2440,8 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis) length); if (ret != length) { object_unref(OBJECT(bioc)); - error_report("CMD_PACKAGED: Buffer receive fail ret=%d length=%zu", - ret, length); + error_setg(errp, "CMD_PACKAGED: Buffer receive fail ret=%d length=%zu", + ret, length); return (ret < 0) ? ret : -EAGAIN; } bioc->usage += length; @@ -2449,7 +2470,7 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis) qemu_coroutine_yield(); } while (1); - ret = qemu_loadvm_state_main(packf, mis); + ret = qemu_loadvm_state_main(packf, mis, errp); trace_loadvm_handle_cmd_packaged_main(ret); qemu_fclose(packf); object_unref(OBJECT(bioc)); @@ -2464,32 +2485,35 @@ static int loadvm_handle_cmd_packaged(MigrationIncomingState *mis) * len (1 byte) + ramblock_name (<255 bytes) */ static int loadvm_handle_recv_bitmap(MigrationIncomingState *mis, - uint16_t len) + uint16_t len, Error **errp) { QEMUFile *file = mis->from_src_file; RAMBlock *rb; char block_name[256]; size_t cnt; + int ret; cnt = qemu_get_counted_string(file, block_name); if (!cnt) { - error_report("%s: failed to read block name", __func__); + error_setg(errp, "failed to read block name"); return -EINVAL; } /* Validate before using the data */ - if (qemu_file_get_error(file)) { - return qemu_file_get_error(file); + ret = qemu_file_get_error(file); + if (ret < 0) { + error_setg(errp, "loadvm failed: stream error: %d", ret); + return ret; } if (len != cnt + 1) { - error_report("%s: invalid payload length (%d)", __func__, len); + error_setg(errp, "invalid payload length (%d)", len); return -EINVAL; } rb = qemu_ram_block_by_name(block_name); if (!rb) { - error_report("%s: block '%s' not found", __func__, block_name); + error_setg(errp, "block '%s' not found", block_name); return -EINVAL; } @@ -2500,20 +2524,26 @@ static int loadvm_handle_recv_bitmap(MigrationIncomingState *mis, return 0; } -static int loadvm_process_enable_colo(MigrationIncomingState *mis) +static int loadvm_process_enable_colo(MigrationIncomingState *mis, + Error **errp) { - int ret = migration_incoming_enable_colo(); + ERRP_GUARD(); + int ret; - if (!ret) { - ret = colo_init_ram_cache(); - if (ret) { - migration_incoming_disable_colo(); - } + ret = migration_incoming_enable_colo(errp); + if (ret < 0) { + return ret; + } + + ret = colo_init_ram_cache(errp); + if (ret) { + error_prepend(errp, "failed to init colo RAM cache: %d: ", ret); + migration_incoming_disable_colo(); } return ret; } -static int loadvm_postcopy_handle_switchover_start(void) +static int loadvm_postcopy_handle_switchover_start(Error **errp) { SaveStateEntry *se; @@ -2526,6 +2556,7 @@ static int loadvm_postcopy_handle_switchover_start(void) ret = se->ops->switchover_start(se->opaque); if (ret < 0) { + error_setg(errp, "Switchover start failed: %d", ret); return ret; } } @@ -2539,32 +2570,37 @@ static int loadvm_postcopy_handle_switchover_start(void) * LOADVM_QUIT All good, but exit the loop * <0 Error */ -static int loadvm_process_command(QEMUFile *f) +static int loadvm_process_command(QEMUFile *f, Error **errp) { MigrationIncomingState *mis = migration_incoming_get_current(); uint16_t cmd; uint16_t len; uint32_t tmp32; + int ret; cmd = qemu_get_be16(f); len = qemu_get_be16(f); /* Check validity before continue processing of cmds */ - if (qemu_file_get_error(f)) { - return qemu_file_get_error(f); + ret = qemu_file_get_error(f); + if (ret) { + error_setg(errp, + "Failed to load VM process command: stream error: %d", + ret); + return ret; } if (cmd >= MIG_CMD_MAX || cmd == MIG_CMD_INVALID) { - error_report("MIG_CMD 0x%x unknown (len 0x%x)", cmd, len); + error_setg(errp, "MIG_CMD 0x%x unknown (len 0x%x)", cmd, len); return -EINVAL; } trace_loadvm_process_command(mig_cmd_args[cmd].name, len); if (mig_cmd_args[cmd].len != -1 && mig_cmd_args[cmd].len != len) { - error_report("%s received with bad length - expecting %zu, got %d", - mig_cmd_args[cmd].name, - (size_t)mig_cmd_args[cmd].len, len); + error_setg(errp, "%s received with bad length - expecting %zu, got %d", + mig_cmd_args[cmd].name, + (size_t)mig_cmd_args[cmd].len, len); return -ERANGE; } @@ -2576,10 +2612,6 @@ static int loadvm_process_command(QEMUFile *f) return 0; } mis->to_src_file = qemu_file_get_return_path(f); - if (!mis->to_src_file) { - error_report("CMD_OPEN_RETURN_PATH failed"); - return -1; - } /* * Switchover ack is enabled but no device uses it, so send an ACK to @@ -2587,11 +2619,10 @@ static int loadvm_process_command(QEMUFile *f) * been created. */ if (migrate_switchover_ack() && !mis->switchover_ack_pending_num) { - int ret = migrate_send_rp_switchover_ack(mis); + ret = migrate_send_rp_switchover_ack(mis); if (ret) { - error_report( - "Could not send switchover ack RP MSG, err %d (%s)", ret, - strerror(-ret)); + error_setg_errno(errp, -ret, + "Could not send switchover ack RP MSG"); return ret; } } @@ -2601,39 +2632,40 @@ static int loadvm_process_command(QEMUFile *f) tmp32 = qemu_get_be32(f); trace_loadvm_process_command_ping(tmp32); if (!mis->to_src_file) { - error_report("CMD_PING (0x%x) received with no return path", - tmp32); + error_setg(errp, "CMD_PING (0x%x) received with no return path", + tmp32); return -1; } migrate_send_rp_pong(mis, tmp32); break; case MIG_CMD_PACKAGED: - return loadvm_handle_cmd_packaged(mis); + return loadvm_handle_cmd_packaged(mis, errp); case MIG_CMD_POSTCOPY_ADVISE: - return loadvm_postcopy_handle_advise(mis, len); + return loadvm_postcopy_handle_advise(mis, len, errp); case MIG_CMD_POSTCOPY_LISTEN: - return loadvm_postcopy_handle_listen(mis); + return loadvm_postcopy_handle_listen(mis, errp); case MIG_CMD_POSTCOPY_RUN: - return loadvm_postcopy_handle_run(mis); + return loadvm_postcopy_handle_run(mis, errp); case MIG_CMD_POSTCOPY_RAM_DISCARD: - return loadvm_postcopy_ram_handle_discard(mis, len); + return loadvm_postcopy_ram_handle_discard(mis, len, errp); case MIG_CMD_POSTCOPY_RESUME: - return loadvm_postcopy_handle_resume(mis); + loadvm_postcopy_handle_resume(mis); + return 0; case MIG_CMD_RECV_BITMAP: - return loadvm_handle_recv_bitmap(mis, len); + return loadvm_handle_recv_bitmap(mis, len, errp); case MIG_CMD_ENABLE_COLO: - return loadvm_process_enable_colo(mis); + return loadvm_process_enable_colo(mis, errp); case MIG_CMD_SWITCHOVER_START: - return loadvm_postcopy_handle_switchover_start(); + return loadvm_postcopy_handle_switchover_start(errp); } return 0; @@ -2683,8 +2715,9 @@ static bool check_section_footer(QEMUFile *f, SaveStateEntry *se) } static int -qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type) +qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type, Error **errp) { + ERRP_GUARD(); bool trace_downtime = (type == QEMU_VM_SECTION_FULL); uint32_t instance_id, version_id, section_id; int64_t start_ts, end_ts; @@ -2695,8 +2728,8 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type) /* Read section start */ section_id = qemu_get_be32(f); if (!qemu_get_counted_string(f, idstr)) { - error_report("Unable to read ID string for section %u", - section_id); + error_setg(errp, "Unable to read ID string for section %u", + section_id); return -EINVAL; } instance_id = qemu_get_be32(f); @@ -2704,8 +2737,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type) ret = qemu_file_get_error(f); if (ret) { - error_report("%s: Failed to read instance/version ID: %d", - __func__, ret); + error_setg(errp, "Failed to read instance/version ID: %d", ret); return ret; } @@ -2714,17 +2746,17 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type) /* Find savevm section */ se = find_se(idstr, instance_id); if (se == NULL) { - error_report("Unknown savevm section or instance '%s' %"PRIu32". " - "Make sure that your current VM setup matches your " - "saved VM setup, including any hotplugged devices", - idstr, instance_id); + error_setg(errp, "Unknown section or instance '%s' %"PRIu32". " + "Make sure that your current VM setup matches your " + "saved VM setup, including any hotplugged devices", + idstr, instance_id); return -EINVAL; } /* Validate version */ if (version_id > se->version_id) { - error_report("savevm: unsupported version %d for '%s' v%d", - version_id, idstr, se->version_id); + error_setg(errp, "unsupported version %d for '%s' v%d", + version_id, idstr, se->version_id); return -EINVAL; } se->load_version_id = version_id; @@ -2732,7 +2764,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type) /* Validate if it is a device's state */ if (xen_enabled() && se->is_ram) { - error_report("loadvm: %s RAM loading not allowed on Xen", idstr); + error_setg(errp, "loadvm: %s RAM loading not allowed on Xen", idstr); return -EINVAL; } @@ -2740,10 +2772,11 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type) start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME); } - ret = vmstate_load(f, se); + ret = vmstate_load(f, se, errp); if (ret < 0) { - error_report("error while loading state for instance 0x%"PRIx32" of" - " device '%s'", instance_id, idstr); + error_prepend(errp, + "error while loading state for instance 0x%"PRIx32" of" + " device '%s': ", instance_id, idstr); return ret; } @@ -2754,6 +2787,8 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type) } if (!check_section_footer(f, se)) { + error_setg(errp, "Section footer error, section_id: %d", + section_id); return -EINVAL; } @@ -2761,7 +2796,7 @@ qemu_loadvm_section_start_full(QEMUFile *f, uint8_t type) } static int -qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type) +qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type, Error **errp) { bool trace_downtime = (type == QEMU_VM_SECTION_END); int64_t start_ts, end_ts; @@ -2773,8 +2808,7 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type) ret = qemu_file_get_error(f); if (ret) { - error_report("%s: Failed to read section ID: %d", - __func__, ret); + error_setg(errp, "Failed to read section ID: %d", ret); return ret; } @@ -2785,7 +2819,7 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type) } } if (se == NULL) { - error_report("Unknown savevm section %d", section_id); + error_setg(errp, "Unknown section %d", section_id); return -EINVAL; } @@ -2793,10 +2827,8 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type) start_ts = qemu_clock_get_us(QEMU_CLOCK_REALTIME); } - ret = vmstate_load(f, se); + ret = vmstate_load(f, se, errp); if (ret < 0) { - error_report("error while loading state section id %d(%s)", - section_id, se->idstr); return ret; } @@ -2807,40 +2839,50 @@ qemu_loadvm_section_part_end(QEMUFile *f, uint8_t type) } if (!check_section_footer(f, se)) { + error_setg(errp, "Section footer error, section_id: %d", + section_id); return -EINVAL; } return 0; } -static int qemu_loadvm_state_header(QEMUFile *f) +static int qemu_loadvm_state_header(QEMUFile *f, Error **errp) { unsigned int v; int ret; v = qemu_get_be32(f); if (v != QEMU_VM_FILE_MAGIC) { - error_report("Not a migration stream"); + error_setg(errp, "Not a migration stream, magic: %x != %x", + v, QEMU_VM_FILE_MAGIC); return -EINVAL; } v = qemu_get_be32(f); if (v == QEMU_VM_FILE_VERSION_COMPAT) { - error_report("SaveVM v2 format is obsolete and don't work anymore"); + error_setg(errp, + "SaveVM v2 format is obsolete and no longer supported"); + return -ENOTSUP; } if (v != QEMU_VM_FILE_VERSION) { - error_report("Unsupported migration stream version"); + error_setg(errp, "Unsupported migration stream version, " + "file version %x != %x", + v, QEMU_VM_FILE_VERSION); return -ENOTSUP; } if (migrate_get_current()->send_configuration) { - if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) { - error_report("Configuration section missing"); + v = qemu_get_byte(f); + if (v != QEMU_VM_CONFIGURATION) { + error_setg(errp, "Configuration section missing, %x != %x", + v, QEMU_VM_CONFIGURATION); return -EINVAL; } - ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0); + ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0, + errp); if (ret) { return ret; } @@ -3028,8 +3070,10 @@ static bool postcopy_pause_incoming(MigrationIncomingState *mis) return true; } -int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis) +int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis, + Error **errp) { + ERRP_GUARD(); uint8_t section_type; int ret = 0; @@ -3037,8 +3081,11 @@ retry: while (true) { section_type = qemu_get_byte(f); - ret = qemu_file_get_error_obj_any(f, mis->postcopy_qemufile_dst, NULL); + ret = qemu_file_get_error_obj_any(f, mis->postcopy_qemufile_dst, errp); if (ret) { + error_prepend(errp, + "Failed to load section ID: stream error: %d: ", + ret); break; } @@ -3046,20 +3093,20 @@ retry: switch (section_type) { case QEMU_VM_SECTION_START: case QEMU_VM_SECTION_FULL: - ret = qemu_loadvm_section_start_full(f, section_type); + ret = qemu_loadvm_section_start_full(f, section_type, errp); if (ret < 0) { goto out; } break; case QEMU_VM_SECTION_PART: case QEMU_VM_SECTION_END: - ret = qemu_loadvm_section_part_end(f, section_type); + ret = qemu_loadvm_section_part_end(f, section_type, errp); if (ret < 0) { goto out; } break; case QEMU_VM_COMMAND: - ret = loadvm_process_command(f); + ret = loadvm_process_command(f, errp); trace_qemu_loadvm_state_section_command(ret); if ((ret < 0) || (ret == LOADVM_QUIT)) { goto out; @@ -3069,7 +3116,7 @@ retry: /* This is the end of migration */ goto out; default: - error_report("Unknown savevm section type %d", section_type); + error_setg(errp, "Unknown section type %d", section_type); ret = -EINVAL; goto out; } @@ -3097,33 +3144,31 @@ out: migrate_postcopy_ram() && postcopy_pause_incoming(mis)) { /* Reset f to point to the newly created channel */ f = mis->from_src_file; + error_free_or_abort(errp); goto retry; } } return ret; } -int qemu_loadvm_state(QEMUFile *f) +int qemu_loadvm_state(QEMUFile *f, Error **errp) { MigrationState *s = migrate_get_current(); MigrationIncomingState *mis = migration_incoming_get_current(); - Error *local_err = NULL; int ret; - if (qemu_savevm_state_blocked(&local_err)) { - error_report_err(local_err); + if (qemu_savevm_state_blocked(errp)) { return -EINVAL; } qemu_loadvm_thread_pool_create(mis); - ret = qemu_loadvm_state_header(f); + ret = qemu_loadvm_state_header(f, errp); if (ret) { return ret; } - if (qemu_loadvm_state_setup(f, &local_err) != 0) { - error_report_err(local_err); + if (qemu_loadvm_state_setup(f, errp) != 0) { return -EINVAL; } @@ -3133,7 +3178,7 @@ int qemu_loadvm_state(QEMUFile *f) cpu_synchronize_all_pre_loadvm(); - ret = qemu_loadvm_state_main(f, mis); + ret = qemu_loadvm_state_main(f, mis, errp); qemu_event_set(&mis->main_thread_load_event); trace_qemu_loadvm_state_post_main(ret); @@ -3151,8 +3196,15 @@ int qemu_loadvm_state(QEMUFile *f) if (migrate_has_error(migrate_get_current()) || !qemu_loadvm_thread_pool_wait(s, mis)) { ret = -EINVAL; + error_setg(errp, + "Error while loading vmstate"); } else { ret = qemu_file_get_error(f); + if (ret < 0) { + error_setg(errp, + "Error while loading vmstate: stream error: %d", + ret); + } } } /* @@ -3201,15 +3253,14 @@ int qemu_loadvm_state(QEMUFile *f) return ret; } -int qemu_load_device_state(QEMUFile *f) +int qemu_load_device_state(QEMUFile *f, Error **errp) { MigrationIncomingState *mis = migration_incoming_get_current(); int ret; /* Load QEMU_VM_SECTION_FULL section */ - ret = qemu_loadvm_state_main(f, mis); + ret = qemu_loadvm_state_main(f, mis, errp); if (ret < 0) { - error_report("Failed to load device state: %d", ret); return ret; } @@ -3417,6 +3468,7 @@ void qmp_xen_save_devices_state(const char *filename, bool has_live, bool live, void qmp_xen_load_devices_state(const char *filename, Error **errp) { + ERRP_GUARD(); QEMUFile *f; QIOChannelFile *ioc; int ret; @@ -3438,10 +3490,10 @@ void qmp_xen_load_devices_state(const char *filename, Error **errp) f = qemu_file_new_input(QIO_CHANNEL(ioc)); object_unref(OBJECT(ioc)); - ret = qemu_loadvm_state(f); + ret = qemu_loadvm_state(f, errp); qemu_fclose(f); if (ret < 0) { - error_setg(errp, "loading Xen device state failed"); + error_prepend(errp, "loading Xen device state failed: "); } migration_incoming_state_destroy(); } @@ -3512,13 +3564,12 @@ bool load_snapshot(const char *name, const char *vmstate, ret = -EINVAL; goto err_drain; } - ret = qemu_loadvm_state(f); + ret = qemu_loadvm_state(f, errp); migration_incoming_state_destroy(); bdrv_drain_all_end(); if (ret < 0) { - error_setg(errp, "Error %d while loading VM state", ret); return false; } |