提交 7b89bf27 编写于 作者: D Dr. David Alan Gilbert 提交者: Juan Quintela

Rework loadvm path for subloops

Postcopy needs to have two migration streams loading concurrently;
one from memory (with the device state) and the other from the fd
with the memory transactions.

Split the core of qemu_loadvm_state out so we can use it for both.

Allow the inner loadvm loop to quit and cause the parent loops to
exit as well.
Signed-off-by: NDr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: NJuan Quintela <quintela@redhat.com>
Reviewed-by: NAmit Shah <amit.shah@redhat.com>
Signed-off-by: NJuan Quintela <quintela@redhat.com>
上级 70b20477
...@@ -57,6 +57,12 @@ typedef QLIST_HEAD(, LoadStateEntry) LoadStateEntry_Head; ...@@ -57,6 +57,12 @@ typedef QLIST_HEAD(, LoadStateEntry) LoadStateEntry_Head;
struct MigrationIncomingState { struct MigrationIncomingState {
QEMUFile *from_src_file; QEMUFile *from_src_file;
/*
* Free at the start of the main state load, set as the main thread finishes
* loading state.
*/
QemuEvent main_thread_load_event;
QEMUFile *to_src_file; QEMUFile *to_src_file;
QemuMutex rp_mutex; /* We send replies from multiple threads */ QemuMutex rp_mutex; /* We send replies from multiple threads */
......
...@@ -98,12 +98,14 @@ MigrationIncomingState *migration_incoming_state_new(QEMUFile* f) ...@@ -98,12 +98,14 @@ MigrationIncomingState *migration_incoming_state_new(QEMUFile* f)
mis_current->from_src_file = f; mis_current->from_src_file = f;
QLIST_INIT(&mis_current->loadvm_handlers); QLIST_INIT(&mis_current->loadvm_handlers);
qemu_mutex_init(&mis_current->rp_mutex); qemu_mutex_init(&mis_current->rp_mutex);
qemu_event_init(&mis_current->main_thread_load_event, false);
return mis_current; return mis_current;
} }
void migration_incoming_state_destroy(void) void migration_incoming_state_destroy(void)
{ {
qemu_event_destroy(&mis_current->main_thread_load_event);
loadvm_free_handlers(mis_current); loadvm_free_handlers(mis_current);
g_free(mis_current); g_free(mis_current);
mis_current = NULL; mis_current = NULL;
......
...@@ -1051,11 +1051,18 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id) ...@@ -1051,11 +1051,18 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id)
return NULL; return NULL;
} }
enum LoadVMExitCodes {
/* Allow a command to quit all layers of nested loadvm loops */
LOADVM_QUIT = 1,
};
static int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis);
/** /**
* loadvm_process_command: Process an incoming 'QEMU_VM_COMMAND' * loadvm_process_command: Process an incoming 'QEMU_VM_COMMAND'
* *
* Returns: 0 on success, negative on error (in which case it will issue an * Returns: 0 on just a normal return
* error message). * LOADVM_QUIT All good, but exit the loop
* <0 error (in which case it will issue an error message).
* @f: The stream to read the command data from. * @f: The stream to read the command data from.
*/ */
static int loadvm_process_command(QEMUFile *f) static int loadvm_process_command(QEMUFile *f)
...@@ -1162,47 +1169,10 @@ void loadvm_free_handlers(MigrationIncomingState *mis) ...@@ -1162,47 +1169,10 @@ void loadvm_free_handlers(MigrationIncomingState *mis)
} }
} }
int qemu_loadvm_state(QEMUFile *f) static int qemu_loadvm_state_main(QEMUFile *f, MigrationIncomingState *mis)
{ {
MigrationIncomingState *mis = migration_incoming_get_current();
Error *local_err = NULL;
uint8_t section_type; uint8_t section_type;
unsigned int v;
int ret; int ret;
int file_error_after_eof = -1;
if (qemu_savevm_state_blocked(&local_err)) {
error_report_err(local_err);
return -EINVAL;
}
v = qemu_get_be32(f);
if (v != QEMU_VM_FILE_MAGIC) {
error_report("Not a migration stream");
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");
return -ENOTSUP;
}
if (v != QEMU_VM_FILE_VERSION) {
error_report("Unsupported migration stream version");
return -ENOTSUP;
}
if (!savevm_state.skip_configuration) {
if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) {
error_report("Configuration section missing");
return -EINVAL;
}
ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0);
if (ret) {
return ret;
}
}
while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) { while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) {
uint32_t instance_id, version_id, section_id; uint32_t instance_id, version_id, section_id;
...@@ -1231,16 +1201,14 @@ int qemu_loadvm_state(QEMUFile *f) ...@@ -1231,16 +1201,14 @@ int qemu_loadvm_state(QEMUFile *f)
if (se == NULL) { if (se == NULL) {
error_report("Unknown savevm section or instance '%s' %d", error_report("Unknown savevm section or instance '%s' %d",
idstr, instance_id); idstr, instance_id);
ret = -EINVAL; return -EINVAL;
goto out;
} }
/* Validate version */ /* Validate version */
if (version_id > se->version_id) { if (version_id > se->version_id) {
error_report("savevm: unsupported version %d for '%s' v%d", error_report("savevm: unsupported version %d for '%s' v%d",
version_id, idstr, se->version_id); version_id, idstr, se->version_id);
ret = -EINVAL; return -EINVAL;
goto out;
} }
/* Add entry */ /* Add entry */
...@@ -1255,11 +1223,10 @@ int qemu_loadvm_state(QEMUFile *f) ...@@ -1255,11 +1223,10 @@ int qemu_loadvm_state(QEMUFile *f)
if (ret < 0) { if (ret < 0) {
error_report("error while loading state for instance 0x%x of" error_report("error while loading state for instance 0x%x of"
" device '%s'", instance_id, idstr); " device '%s'", instance_id, idstr);
goto out; return ret;
} }
if (!check_section_footer(f, le)) { if (!check_section_footer(f, le)) {
ret = -EINVAL; return -EINVAL;
goto out;
} }
break; break;
case QEMU_VM_SECTION_PART: case QEMU_VM_SECTION_PART:
...@@ -1274,35 +1241,83 @@ int qemu_loadvm_state(QEMUFile *f) ...@@ -1274,35 +1241,83 @@ int qemu_loadvm_state(QEMUFile *f)
} }
if (le == NULL) { if (le == NULL) {
error_report("Unknown savevm section %d", section_id); error_report("Unknown savevm section %d", section_id);
ret = -EINVAL; return -EINVAL;
goto out;
} }
ret = vmstate_load(f, le->se, le->version_id); ret = vmstate_load(f, le->se, le->version_id);
if (ret < 0) { if (ret < 0) {
error_report("error while loading state section id %d(%s)", error_report("error while loading state section id %d(%s)",
section_id, le->se->idstr); section_id, le->se->idstr);
goto out; return ret;
} }
if (!check_section_footer(f, le)) { if (!check_section_footer(f, le)) {
ret = -EINVAL; return -EINVAL;
goto out;
} }
break; break;
case QEMU_VM_COMMAND: case QEMU_VM_COMMAND:
ret = loadvm_process_command(f); ret = loadvm_process_command(f);
if (ret < 0) { trace_qemu_loadvm_state_section_command(ret);
goto out; if ((ret < 0) || (ret & LOADVM_QUIT)) {
return ret;
} }
break; break;
default: default:
error_report("Unknown savevm section type %d", section_type); error_report("Unknown savevm section type %d", section_type);
ret = -EINVAL; return -EINVAL;
goto out; }
}
return 0;
}
int qemu_loadvm_state(QEMUFile *f)
{
MigrationIncomingState *mis = migration_incoming_get_current();
Error *local_err = NULL;
unsigned int v;
int ret;
if (qemu_savevm_state_blocked(&local_err)) {
error_report_err(local_err);
return -EINVAL;
}
v = qemu_get_be32(f);
if (v != QEMU_VM_FILE_MAGIC) {
error_report("Not a migration stream");
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");
return -ENOTSUP;
}
if (v != QEMU_VM_FILE_VERSION) {
error_report("Unsupported migration stream version");
return -ENOTSUP;
}
if (!savevm_state.skip_configuration) {
if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) {
error_report("Configuration section missing");
return -EINVAL;
}
ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0);
if (ret) {
return ret;
} }
} }
file_error_after_eof = qemu_file_get_error(f); ret = qemu_loadvm_state_main(f, mis);
qemu_event_set(&mis->main_thread_load_event);
trace_qemu_loadvm_state_post_main(ret);
if (ret == 0) {
ret = qemu_file_get_error(f);
}
/* /*
* Try to read in the VMDESC section as well, so that dumping tools that * Try to read in the VMDESC section as well, so that dumping tools that
...@@ -1314,10 +1329,10 @@ int qemu_loadvm_state(QEMUFile *f) ...@@ -1314,10 +1329,10 @@ int qemu_loadvm_state(QEMUFile *f)
* We also mustn't read data that isn't there; some transports (RDMA) * We also mustn't read data that isn't there; some transports (RDMA)
* will stall waiting for that data when the source has already closed. * will stall waiting for that data when the source has already closed.
*/ */
if (should_send_vmdesc()) { if (ret == 0 && should_send_vmdesc()) {
uint8_t *buf; uint8_t *buf;
uint32_t size; uint32_t size;
section_type = qemu_get_byte(f); uint8_t section_type = qemu_get_byte(f);
if (section_type != QEMU_VM_VMDESCRIPTION) { if (section_type != QEMU_VM_VMDESCRIPTION) {
error_report("Expected vmdescription section, but got %d", error_report("Expected vmdescription section, but got %d",
...@@ -1341,14 +1356,6 @@ int qemu_loadvm_state(QEMUFile *f) ...@@ -1341,14 +1356,6 @@ int qemu_loadvm_state(QEMUFile *f)
cpu_synchronize_all_post_init(); cpu_synchronize_all_post_init();
ret = 0;
out:
if (ret == 0) {
/* We may not have a VMDESC section, so ignore relative errors */
ret = file_error_after_eof;
}
return ret; return ret;
} }
......
...@@ -1202,7 +1202,11 @@ virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64 ...@@ -1202,7 +1202,11 @@ virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64
# migration/savevm.c # migration/savevm.c
qemu_loadvm_state_section(unsigned int section_type) "%d" qemu_loadvm_state_section(unsigned int section_type) "%d"
qemu_loadvm_state_section_command(int ret) "%d"
qemu_loadvm_state_section_partend(uint32_t section_id) "%u" qemu_loadvm_state_section_partend(uint32_t section_id) "%u"
qemu_loadvm_state_main(void) ""
qemu_loadvm_state_main_quit_parent(void) ""
qemu_loadvm_state_post_main(int ret) "%d"
qemu_loadvm_state_section_startfull(uint32_t section_id, const char *idstr, uint32_t instance_id, uint32_t version_id) "%u(%s) %u %u" qemu_loadvm_state_section_startfull(uint32_t section_id, const char *idstr, uint32_t instance_id, uint32_t version_id) "%u(%s) %u %u"
loadvm_process_command(uint16_t com, uint16_t len) "com=0x%x len=%d" loadvm_process_command(uint16_t com, uint16_t len) "com=0x%x len=%d"
loadvm_process_command_ping(uint32_t val) "%x" loadvm_process_command_ping(uint32_t val) "%x"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册