Currently cpr-exec uses a file to pass the VM and device state between the old and new QEMU processes. Support using memfd as a migration transport so this state can be passed without creating a state file.
Here is an example of using the new memfd transport with cpr-exec. (qemu) migrate_set_parameter mode cpr-exec (qemu) migrate_set_parameter cpr-exec-command qemu-kvm ... -incoming defer (qemu) migrate -d memfd: QEMU 11.1.50 monitor - type 'help' for more information (qemu) info status VM status: paused (inmigrate) (qemu) migrate_incoming memfd: (qemu) info status VM status: running Signed-off-by: Dongli Zhang <[email protected]> --- migration/channel.c | 7 +++++++ migration/cpr-exec.c | 9 +++++++++ migration/memfd.c | 23 +++++++++++++++++++++++ migration/memfd.h | 2 ++ migration/migration.c | 9 +++++++++ 5 files changed, 50 insertions(+) diff --git a/migration/channel.c b/migration/channel.c index 1e2935f926..96de40c108 100644 --- a/migration/channel.c +++ b/migration/channel.c @@ -18,6 +18,7 @@ #include "file.h" #include "io/channel-socket.h" #include "io/channel-tls.h" +#include "memfd.h" #include "migration.h" #include "multifd.h" #include "options.h" @@ -62,6 +63,8 @@ void migration_connect_outgoing(MigrationState *s, MigrationAddress *addr, ioc = exec_connect_outgoing(s, addr->u.exec.args, errp); } else if (addr->transport == MIGRATION_ADDRESS_TYPE_FILE) { ioc = file_connect_outgoing(s, &addr->u.file, errp); + } else if (addr->transport == MIGRATION_ADDRESS_TYPE_MEMFD) { + ioc = memfd_connect_outgoing(errp); } else { error_setg(errp, "uri is not a valid migration protocol"); } @@ -92,6 +95,8 @@ void migration_connect_incoming(MigrationAddress *addr, Error **errp) exec_connect_incoming(addr->u.exec.args, errp); } else if (addr->transport == MIGRATION_ADDRESS_TYPE_FILE) { file_connect_incoming(&addr->u.file, errp); + } else if (addr->transport == MIGRATION_ADDRESS_TYPE_MEMFD) { + memfd_connect_incoming(errp); } else { error_setg(errp, "unknown migration protocol"); } @@ -394,6 +399,8 @@ bool migrate_uri_parse(const char *uri, MigrationChannel **channel, errp)) { return false; } + } else if (g_str_equal(uri, "memfd:")) { + addr->transport = MIGRATION_ADDRESS_TYPE_MEMFD; } else { error_setg(errp, "unknown migration protocol: %s", uri); return false; diff --git a/migration/cpr-exec.c b/migration/cpr-exec.c index daa50916d2..388cfba80d 100644 --- a/migration/cpr-exec.c +++ b/migration/cpr-exec.c @@ -21,6 +21,7 @@ #include "migration/vmstate.h" #include "system/runstate.h" #include "trace.h" +#include "cpr-exec-memfd.h" #define CPR_EXEC_STATE_NAME "QEMU_CPR_EXEC_STATE" @@ -143,6 +144,11 @@ static void cpr_exec_cb(void *opaque) * earlier because they should not persist across miscellaneous fork and * exec calls that are performed during normal operation. */ + if (!cpr_exec_memfd_preserve_fd(&err)) { + g_clear_pointer(&argv, g_strfreev); + cpr_exec_memfd_cleanup(); + goto fail; + } cpr_exec_preserve_fds(); trace_cpr_exec(); @@ -155,7 +161,9 @@ static void cpr_exec_cb(void *opaque) error_setg_errno(&err, errno, "execvp %s failed", argv[0]); g_clear_pointer(&argv, g_strfreev); cpr_exec_unpreserve_fds(); + cpr_exec_memfd_cleanup(); +fail: error_report_err(error_copy(err)); migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED); @@ -189,6 +197,7 @@ static int cpr_exec_notifier(NotifierWithReturn *notifier, MigrationEvent *e, qemu_notify_event(); } else if (e->type == MIG_EVENT_FAILED) { cpr_exec_unpersist_state(); + cpr_exec_memfd_cleanup(); } return 0; } diff --git a/migration/memfd.c b/migration/memfd.c index 0b5ef0234f..4ed185d844 100644 --- a/migration/memfd.c +++ b/migration/memfd.c @@ -10,6 +10,9 @@ #include "qemu/cutils.h" #include "qemu/memfd.h" #include "memfd.h" +#include "cpr-exec-memfd.h" +#include "migration/cpr.h" +#include "options.h" QIOChannel *memfd_create_outgoing(const char *name, int *dup_fdp, Error **errp) @@ -65,3 +68,23 @@ QIOChannel *memfd_open_incoming(int fd, const char *name, Error **errp) qio_channel_set_name(ioc, name); return ioc; } + +QIOChannel *memfd_connect_outgoing(Error **errp) +{ + if (migrate_mode() == MIG_MODE_CPR_EXEC) { + return cpr_exec_memfd_connect_outgoing(errp); + } + + error_setg(errp, "memfd transport is only supported with cpr-exec"); + return NULL; +} + +void memfd_connect_incoming(Error **errp) +{ + if (cpr_get_incoming_mode() == MIG_MODE_CPR_EXEC) { + cpr_exec_memfd_connect_incoming(errp); + return; + } + + error_setg(errp, "memfd transport is only supported with cpr-exec"); +} diff --git a/migration/memfd.h b/migration/memfd.h index cb6afe3eeb..9c50c84ad5 100644 --- a/migration/memfd.h +++ b/migration/memfd.h @@ -13,5 +13,7 @@ QIOChannel *memfd_create_outgoing(const char *name, int *dup_fdp, Error **errp); QIOChannel *memfd_open_incoming(int fd, const char *name, Error **errp); +QIOChannel *memfd_connect_outgoing(Error **errp); +void memfd_connect_incoming(Error **errp); #endif diff --git a/migration/migration.c b/migration/migration.c index 9df6da131c..9f3afe5a3a 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -248,6 +248,15 @@ migration_channels_and_transport_compatible(MigrationAddress *addr, return false; } + if (addr->transport == MIGRATION_ADDRESS_TYPE_MEMFD) { + if (migrate_mode() != MIG_MODE_CPR_EXEC && + cpr_get_incoming_mode() != MIG_MODE_CPR_EXEC) { + error_setg(errp, + "memfd transport is only supported with cpr-exec"); + return false; + } + } + return true; } -- 2.43.5
