From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:60768) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X37VM-0007rH-PS for qemu-devel@nongnu.org; Fri, 04 Jul 2014 13:42:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X37VE-0008KL-JE for qemu-devel@nongnu.org; Fri, 04 Jul 2014 13:42:36 -0400 Received: from mx1.redhat.com ([209.132.183.28]:50161) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X37VE-0008KA-AW for qemu-devel@nongnu.org; Fri, 04 Jul 2014 13:42:28 -0400 From: "Dr. David Alan Gilbert (git)" Date: Fri, 4 Jul 2014 18:41:26 +0100 Message-Id: <1404495717-4239-16-git-send-email-dgilbert@redhat.com> In-Reply-To: <1404495717-4239-1-git-send-email-dgilbert@redhat.com> References: <1404495717-4239-1-git-send-email-dgilbert@redhat.com> Subject: [Qemu-devel] [PATCH 15/46] 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, lilei@linux.vnet.ibm.com, quintela@redhat.com 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 signal whether the parent should. loadvm_handlers is made static since it's lifetime is greater than the outer qemu_loadvm_state. Signed-off-by: Dr. David Alan Gilbert --- savevm.c | 136 +++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 52 deletions(-) diff --git a/savevm.c b/savevm.c index 662a910..c277d77 100644 --- a/savevm.c +++ b/savevm.c @@ -915,6 +915,26 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id) return NULL; } +/* These are ORable flags */ +const int LOADVM_EXITCODE_QUITLOOP = 1; +const int LOADVM_EXITCODE_QUITPARENT = 2; +const int LOADVM_EXITCODE_KEEPHANDLERS = 4; + +typedef struct LoadStateEntry { + QLIST_ENTRY(LoadStateEntry) entry; + SaveStateEntry *se; + int section_id; + int version_id; +} LoadStateEntry; + +typedef QLIST_HEAD(, LoadStateEntry) LoadStateEntry_Head; + +static LoadStateEntry_Head loadvm_handlers = + QLIST_HEAD_INITIALIZER(loadvm_handlers); + +static int qemu_loadvm_state_main(QEMUFile *f, + LoadStateEntry_Head *loadvm_handlers); + static int loadvm_process_command_simple_lencheck(const char *name, unsigned int actual, unsigned int expected) @@ -930,8 +950,11 @@ static int loadvm_process_command_simple_lencheck(const char *name, /* Process an incoming 'QEMU_VM_COMMAND' * -ve return on error (will issue error message) + * 0 just a normal return + * 1 All good, but exit the loop */ -static int loadvm_process_command(QEMUFile *f) +static int loadvm_process_command(QEMUFile *f, + LoadStateEntry_Head *loadvm_handlers) { MigrationIncomingState *mis = f->mis; uint16_t com; @@ -981,39 +1004,13 @@ static int loadvm_process_command(QEMUFile *f) return 0; } -typedef struct LoadStateEntry { - QLIST_ENTRY(LoadStateEntry) entry; - SaveStateEntry *se; - int section_id; - int version_id; -} LoadStateEntry; - -int qemu_loadvm_state(QEMUFile *f) +static int qemu_loadvm_state_main(QEMUFile *f, + LoadStateEntry_Head *loadvm_handlers) { - QLIST_HEAD(, LoadStateEntry) loadvm_handlers = - QLIST_HEAD_INITIALIZER(loadvm_handlers); - LoadStateEntry *le, *new_le; + LoadStateEntry *le; uint8_t section_type; - unsigned int v; int ret; - - if (qemu_savevm_state_blocked(NULL)) { - return -EINVAL; - } - - v = qemu_get_be32(f); - if (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"); - return -ENOTSUP; - } - if (v != QEMU_VM_FILE_VERSION) { - return -ENOTSUP; - } + int exitcode = 0; while ((section_type = qemu_get_byte(f)) != QEMU_VM_EOF) { uint32_t instance_id, version_id, section_id; @@ -1042,16 +1039,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 */ @@ -1060,14 +1055,14 @@ int qemu_loadvm_state(QEMUFile *f) le->se = se; le->section_id = section_id; le->version_id = version_id; - QLIST_INSERT_HEAD(&loadvm_handlers, le, entry); + QLIST_INSERT_HEAD(loadvm_handlers, le, entry); ret = vmstate_load(f, le->se, le->version_id); if (ret < 0) { error_report("qemu: error while loading state for" "instance 0x%x of device '%s'", instance_id, idstr); - goto out; + return ret; } break; case QEMU_VM_SECTION_PART: @@ -1075,47 +1070,84 @@ int qemu_loadvm_state(QEMUFile *f) section_id = qemu_get_be32(f); DPRINTF("QEMU_VM_SECTION_PART/END entry for id=%d", section_id); - QLIST_FOREACH(le, &loadvm_handlers, entry) { + QLIST_FOREACH(le, loadvm_handlers, entry) { if (le->section_id == section_id) { break; } } 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("qemu: error while loading state section" " id %d (%s)", section_id, le->se->idstr); - goto out; + return ret; } DPRINTF("QEMU_VM_SECTION_PART/END done for id=%d", section_id); break; case QEMU_VM_COMMAND: - ret = loadvm_process_command(f); - if (ret < 0) { - goto out; + ret = loadvm_process_command(f, loadvm_handlers); + DPRINTF("%s QEMU_VM_COMMAND ret: %d", __func__, ret); + if ((ret < 0) || (ret & LOADVM_EXITCODE_QUITLOOP)) { + return ret; } + exitcode |= ret; /* Lets us pass flags up to the parent */ break; default: error_report("Unknown savevm section type %d", section_type); - ret = -EINVAL; - goto out; + return -EINVAL; } } DPRINTF("qemu_loadvm_state loop: exited loop"); - cpu_synchronize_all_post_init(); + if (exitcode & LOADVM_EXITCODE_QUITPARENT) { + DPRINTF("loadvm_handlers_state_main: End of loop with QUITPARENT"); + exitcode &= ~LOADVM_EXITCODE_QUITPARENT; + exitcode &= LOADVM_EXITCODE_QUITLOOP; + } + + return exitcode; +} + +int qemu_loadvm_state(QEMUFile *f) +{ + LoadStateEntry *le, *new_le; + unsigned int v; + int ret; + + if (qemu_savevm_state_blocked(NULL)) { + return -EINVAL; + } + + v = qemu_get_be32(f); + if (v != QEMU_VM_FILE_MAGIC) { + return -EINVAL; + } - ret = 0; + 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) { + return -ENOTSUP; + } + + QLIST_INIT(&loadvm_handlers); + ret = qemu_loadvm_state_main(f, &loadvm_handlers); -out: - QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) { - QLIST_REMOVE(le, entry); - g_free(le); + if (ret == 0) { + cpu_synchronize_all_post_init(); + } + + if ((ret < 0) || !(ret & LOADVM_EXITCODE_KEEPHANDLERS)) { + QLIST_FOREACH_SAFE(le, &loadvm_handlers, entry, new_le) { + QLIST_REMOVE(le, entry); + g_free(le); + } } if (ret == 0) { -- 1.9.3