[PATCH 4/5] migration/cpr-exec: Support diskless memfd transport

Dongli Zhang <[email protected]>
Newsgroups org.nongnu.qemu-devel
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.