From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53544) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z4o5m-0006Vq-V0 for qemu-devel@nongnu.org; Tue, 16 Jun 2015 06:27:44 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Z4o5j-0000zL-F2 for qemu-devel@nongnu.org; Tue, 16 Jun 2015 06:27:42 -0400 Received: from mx1.redhat.com ([209.132.183.28]:48346) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z4o5j-0000z7-5q for qemu-devel@nongnu.org; Tue, 16 Jun 2015 06:27:39 -0400 From: "Dr. David Alan Gilbert (git)" Date: Tue, 16 Jun 2015 11:26:29 +0100 Message-Id: <1434450415-11339-17-git-send-email-dgilbert@redhat.com> In-Reply-To: <1434450415-11339-1-git-send-email-dgilbert@redhat.com> References: <1434450415-11339-1-git-send-email-dgilbert@redhat.com> Subject: [Qemu-devel] [PATCH v7 16/42] Rework loadvm path for subloops List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: aarcange@redhat.com, yamahata@private.email.ne.jp, quintela@redhat.com, liang.z.li@intel.com, luis@cs.umu.se, amit.shah@redhat.com, pbonzini@redhat.com, david@gibson.dropbear.id.au From: "Dr. David Alan Gilbert" 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: Dr. David Alan Gilbert --- include/migration/migration.h | 6 ++ migration/migration.c | 2 + migration/savevm.c | 131 +++++++++++++++++++++++------------------- trace-events | 4 ++ 4 files changed, 83 insertions(+), 60 deletions(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index 868f59a..1bf78f6 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -54,6 +54,12 @@ typedef QLIST_HEAD(, LoadStateEntry) LoadStateEntry_Head; struct MigrationIncomingState { QEMUFile *file; + /* + * Free at the start of the main state load, set as the main thread finishes + * loading state. + */ + QemuEvent main_thread_load_event; + QEMUFile *return_path; QemuMutex rp_mutex; /* We send replies from multiple threads */ diff --git a/migration/migration.c b/migration/migration.c index fb2f491..a743018 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -86,12 +86,14 @@ MigrationIncomingState *migration_incoming_state_new(QEMUFile* f) mis_current->file = f; QLIST_INIT(&mis_current->loadvm_handlers); qemu_mutex_init(&mis_current->rp_mutex); + qemu_event_init(&mis_current->main_thread_load_event, false); return mis_current; } void migration_incoming_state_destroy(void) { + qemu_event_destroy(&mis_current->main_thread_load_event); loadvm_free_handlers(mis_current); g_free(mis_current); mis_current = NULL; diff --git a/migration/savevm.c b/migration/savevm.c index d424c2a..7052a6f 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1013,6 +1013,13 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id) 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); + static int loadvm_process_command_simple_lencheck(const char *name, unsigned int actual, unsigned int expected) @@ -1028,7 +1035,9 @@ static int loadvm_process_command_simple_lencheck(const char *name, /* * Process an incoming 'QEMU_VM_COMMAND' - * negative return on error (will issue error message) + * 0 just a normal return + * LOADVM_QUIT All good, but exit the loop + * <0 Error */ static int loadvm_process_command(QEMUFile *f) { @@ -1099,36 +1108,12 @@ 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; - unsigned int v; 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; - } + trace_qemu_loadvm_state_main(); while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) { uint32_t instance_id, version_id, section_id; SaveStateEntry *se; @@ -1156,16 +1141,14 @@ int qemu_loadvm_state(QEMUFile *f) if (se == NULL) { error_report("Unknown savevm section or instance '%s' %d", idstr, instance_id); - ret = -EINVAL; - goto out; + 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); - ret = -EINVAL; - goto out; + return -EINVAL; } /* Add entry */ @@ -1180,11 +1163,10 @@ int qemu_loadvm_state(QEMUFile *f) if (ret < 0) { error_report("error while loading state for instance 0x%x of" " device '%s'", instance_id, idstr); - goto out; + return ret; } if (!check_section_footer(f, le->se)) { - ret = -EINVAL; - goto out; + return -EINVAL; } break; case QEMU_VM_SECTION_PART: @@ -1199,58 +1181,87 @@ int qemu_loadvm_state(QEMUFile *f) } if (le == NULL) { error_report("Unknown savevm section %d", section_id); - ret = -EINVAL; - goto out; + return -EINVAL; } ret = vmstate_load(f, le->se, le->version_id); if (ret < 0) { error_report("error while loading state section id %d(%s)", section_id, le->se->idstr); - goto out; + return ret; } if (!check_section_footer(f, le->se)) { - ret = -EINVAL; - goto out; + return -EINVAL; } break; case QEMU_VM_COMMAND: ret = loadvm_process_command(f); - if (ret < 0) { - goto out; + trace_qemu_loadvm_state_section_command(ret); + if ((ret < 0) || (ret & LOADVM_QUIT)) { + return ret; } break; default: error_report("Unknown savevm section type %d", section_type); - ret = -EINVAL; - goto out; + return -EINVAL; } } - file_error_after_eof = qemu_file_get_error(f); + return 0; +} - /* - * Try to read in the VMDESC section as well, so that dumping tools that - * intercept our migration stream have the chance to see it. - */ - if (qemu_get_byte(f) == QEMU_VM_VMDESCRIPTION) { - uint32_t size = qemu_get_be32(f); - uint8_t *buf = g_malloc(0x1000); +int qemu_loadvm_state(QEMUFile *f) +{ + MigrationIncomingState *mis = migration_incoming_get_current(); + Error *local_err = NULL; + unsigned int v; + int ret; - while (size > 0) { - uint32_t read_chunk = MIN(size, 0x1000); - qemu_get_buffer(f, buf, read_chunk); - size -= read_chunk; - } - g_free(buf); + if (qemu_savevm_state_blocked(&local_err)) { + error_report_err(local_err); + return -EINVAL; } - cpu_synchronize_all_post_init(); + 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; + } - ret = 0; + ret = qemu_loadvm_state_main(f, mis); + qemu_event_set(&mis->main_thread_load_event); -out: + trace_qemu_loadvm_state_post_main(ret); if (ret == 0) { + int file_error_after_eof = qemu_file_get_error(f); + + /* + * Try to read in the VMDESC section as well, so that dumping tools that + * intercept our migration stream have the chance to see it. + */ + if (qemu_get_byte(f) == QEMU_VM_VMDESCRIPTION) { + uint32_t size = qemu_get_be32(f); + uint8_t *buf = g_malloc(0x1000); + + while (size > 0) { + uint32_t read_chunk = MIN(size, 0x1000); + qemu_get_buffer(f, buf, read_chunk); + size -= read_chunk; + } + g_free(buf); + } + + cpu_synchronize_all_post_init(); /* We may not have a VMDESC section, so ignore relative errors */ ret = file_error_after_eof; } diff --git a/trace-events b/trace-events index 282cde1..5644cc2 100644 --- a/trace-events +++ b/trace-events @@ -1181,7 +1181,11 @@ virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64 # migration/savevm.c 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_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" loadvm_process_command(uint16_t com, uint16_t len) "com=0x%x len=%d" loadvm_process_command_ping(uint32_t val) "%x" -- 2.4.3