As with cpr-exec and cpr-transfer, call the cpr-luo APIs to retrieve the LUO session and its state memfd before device creation. After loading the LUO CPR state, retrieve the preserved file descriptors by token.
Finish the LUO session after the incoming migration successfully loads. Accept "-incoming cpr-luo:defer" for deferred incoming migration and "-incoming cpr-luo:<URI>" to start an incoming migration immediately. Signed-off-by: Dongli Zhang <[email protected]> --- The mode management in existing code may need cleanup. There are duplicate cpr_set_incoming_mode(). There are unnecessary call of migrate_mode(). include/migration/cpr.h | 2 ++ migration/cpr-luo-stub.c | 10 ++++++++++ migration/cpr-luo.c | 35 +++++++++++++++++++++++++++++++++++ migration/cpr.c | 24 ++++++++++++++++++++---- migration/migration.c | 2 ++ system/vl.c | 9 +++++++++ 6 files changed, 78 insertions(+), 4 deletions(-) diff --git a/include/migration/cpr.h b/include/migration/cpr.h index 62426bd3e0..96529ab3a1 100644 --- a/include/migration/cpr.h +++ b/include/migration/cpr.h @@ -95,5 +95,7 @@ bool cpr_luo_persist_state(int session_fd, QEMUFile *f, Error **errp); bool cpr_luo_preserve_fds(Error **errp); bool cpr_luo_retrieve_fds(Error **errp); bool cpr_luo_save(QEMUFile *f, Error **errp); +QEMUFile *cpr_luo_load(Error **errp); +void cpr_luo_incoming_finish(void); void cpr_luo_abort(void); #endif diff --git a/migration/cpr-luo-stub.c b/migration/cpr-luo-stub.c index 04a5bd816a..22a7037c20 100644 --- a/migration/cpr-luo-stub.c +++ b/migration/cpr-luo-stub.c @@ -59,6 +59,16 @@ bool cpr_luo_save(QEMUFile *f, Error **errp) return cpr_luo_unsupported(errp); } +QEMUFile *cpr_luo_load(Error **errp) +{ + cpr_luo_unsupported(errp); + return NULL; +} + +void cpr_luo_incoming_finish(void) +{ +} + void cpr_luo_abort(void) { } diff --git a/migration/cpr-luo.c b/migration/cpr-luo.c index 1d112e7865..d9aba3bfc5 100644 --- a/migration/cpr-luo.c +++ b/migration/cpr-luo.c @@ -261,6 +261,41 @@ fail: return false; } +QEMUFile *cpr_luo_load(Error **errp) +{ + char name[LIVEUPDATE_SESSION_NAME_LENGTH]; + int session_fd; + + if (!cpr_luo_session_name(name, errp)) { + return NULL; + } + + session_fd = cpr_luo_retrieve_session(name, errp); + if (session_fd < 0) { + return NULL; + } + + cpr_state.luo_session_fd = session_fd; + return cpr_luo_input(session_fd, errp); +} + +void cpr_luo_incoming_finish(void) +{ + struct liveupdate_session_finish finish = { .size = sizeof(finish) }; + int session_fd = cpr_state.luo_session_fd; + + if (cpr_get_incoming_mode() != MIG_MODE_CPR_LUO || session_fd < 0) { + return; + } + + if (ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, &finish) < 0) { + warn_report("failed to finish LUO session: %s", strerror(errno)); + } + + close(session_fd); + cpr_state.luo_session_fd = -1; +} + void cpr_luo_abort(void) { int session_fd = cpr_state.luo_session_fd; diff --git a/migration/cpr.c b/migration/cpr.c index b91f2fdcd7..fdbb684798 100644 --- a/migration/cpr.c +++ b/migration/cpr.c @@ -391,11 +391,15 @@ bool cpr_state_load(MigrationChannel *channel, Error **errp) mode = MIG_MODE_CPR_TRANSFER; cpr_set_incoming_mode(mode); f = cpr_transfer_input(channel, errp); + } else if (cpr_get_incoming_mode() == MIG_MODE_CPR_LUO) { + mode = MIG_MODE_CPR_LUO; + f = cpr_luo_load(errp); } else { return true; } + if (!f) { - return false; + goto fail; } trace_cpr_state_load(MigMode_str(mode)); @@ -405,23 +409,28 @@ bool cpr_state_load(MigrationChannel *channel, Error **errp) if (v != QEMU_CPR_FILE_MAGIC) { error_setg(errp, "Not a migration stream (bad magic %x)", v); qemu_fclose(f); - return false; + goto fail; } v = qemu_get_be32(f); if (v != QEMU_CPR_FILE_VERSION) { error_setg(errp, "Unsupported migration stream version %d", v); qemu_fclose(f); - return false; + goto fail; } if (!vmstate_load_vmsd(f, cpr_state_vmsd(mode), &cpr_state, 1, errp)) { qemu_fclose(f); - return false; + goto fail; } if (migrate_mode() == MIG_MODE_CPR_EXEC) { /* Set cloexec to prevent fd leaks from fork until the next cpr-exec */ cpr_exec_unpreserve_fds(); + } else if (mode == MIG_MODE_CPR_LUO) { + if (!cpr_luo_retrieve_fds(errp)) { + qemu_fclose(f); + goto fail; + } } /* @@ -431,6 +440,13 @@ bool cpr_state_load(MigrationChannel *channel, Error **errp) cpr_state_file = f; return true; + +fail: + if (mode == MIG_MODE_CPR_LUO) { + cpr_luo_abort(); + } + + return false; } void cpr_state_close(void) diff --git a/migration/migration.c b/migration/migration.c index c8055a1d98..7c2bb982a5 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -687,6 +687,8 @@ static void process_incoming_migration_bh(void *opaque) dirty_bitmap_mig_before_vm_start(); + cpr_luo_incoming_finish(); + if (runstate_is_live(migration_get_target_runstate())) { if (autostart) { /* diff --git a/system/vl.c b/system/vl.c index 468a9fc247..b40f4803e1 100644 --- a/system/vl.c +++ b/system/vl.c @@ -1840,12 +1840,21 @@ static void incoming_option_parse(const char *str) { MigrationChannelType type = MIGRATION_CHANNEL_TYPE_MAIN; MigrationChannel *channel; + const char *uri; Visitor *v; if (!strcmp(str, "defer")) { channel = NULL; } else if (migrate_is_uri(str)) { migrate_uri_parse(str, &channel, &error_fatal); + } else if (strstart(str, "cpr-luo:", &uri)) { + cpr_set_incoming_mode(MIG_MODE_CPR_LUO); + if (!strcmp(uri, "defer")) { + channel = NULL; + str = "defer"; + } else { + migrate_uri_parse(uri, &channel, &error_fatal); + } } else { v = qobject_input_visitor_new_str(str, "channel-type", &error_fatal); visit_type_MigrationChannel(v, NULL, &channel, &error_fatal); -- 2.43.5
