It is necessary to migrate fd information to the target QEMU instance.
cpr-exec preserves fd information in a memfd and uses an environment
variable to share the memfd with the target QEMU instance. cpr-transfer
uses a UNIX domain socket to pass fd information.

For cpr-luo, we save the fd information (i.e., names and tokens) in a
memfd and preserve the memfd using dedicated token 1.

Add helpers to create, preserve, and retrieve the cpr-luo state memfd.

Once the state memfd is preserved through LUO, it remains alive even if we
explicitly close it, until we explicitly close the session fd or terminate
the source QEMU instance.

The global session fd is stored at CprState.

Signed-off-by: Dongli Zhang <[email protected]>
---
 include/migration/cpr.h  |  5 ++++
 migration/cpr-luo-stub.c | 22 ++++++++++++++++
 migration/cpr-luo.c      | 57 ++++++++++++++++++++++++++++++++++++++++
 migration/cpr.c          |  4 ++-
 4 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/include/migration/cpr.h b/include/migration/cpr.h
index 23751fc015..4897d302f1 100644
--- a/include/migration/cpr.h
+++ b/include/migration/cpr.h
@@ -36,6 +36,7 @@ typedef QLIST_HEAD(CprVFIODeviceList, CprVFIODevice) 
CprVFIODeviceList;
 typedef struct CprState {
     CprFdList fds;
     CprVFIODeviceList vfio_devices;
+    int luo_session_fd;
 } CprState;
 
 extern CprState cpr_state;
@@ -88,4 +89,8 @@ int cpr_luo_retrieve_session(const char *name, Error **errp);
 int cpr_luo_preserve_fd(int session_fd, int fd, uint64_t token,
                         Error **errp);
 int cpr_luo_retrieve_fd(int session_fd, uint64_t token, Error **errp);
+QEMUFile *cpr_luo_output(Error **errp);
+QEMUFile *cpr_luo_input(int session_fd, Error **errp);
+bool cpr_luo_persist_state(int session_fd, QEMUFile *f, Error **errp);
+void cpr_luo_abort(void);
 #endif
diff --git a/migration/cpr-luo-stub.c b/migration/cpr-luo-stub.c
index ab64e1f99b..fb2e649534 100644
--- a/migration/cpr-luo-stub.c
+++ b/migration/cpr-luo-stub.c
@@ -35,3 +35,25 @@ int cpr_luo_retrieve_fd(int session_fd, uint64_t token, 
Error **errp)
 {
     return cpr_luo_unsupported(errp);
 }
+
+QEMUFile *cpr_luo_output(Error **errp)
+{
+    cpr_luo_unsupported(errp);
+    return NULL;
+}
+
+QEMUFile *cpr_luo_input(int fd, Error **errp)
+{
+    cpr_luo_unsupported(errp);
+    return NULL;
+}
+
+bool cpr_luo_persist_state(int fd, QEMUFile *f, Error **errp)
+{
+    cpr_luo_unsupported(errp);
+    return false;
+}
+
+void cpr_luo_abort(void)
+{
+}
diff --git a/migration/cpr-luo.c b/migration/cpr-luo.c
index f6e0e23657..5b6bd6e191 100644
--- a/migration/cpr-luo.c
+++ b/migration/cpr-luo.c
@@ -8,9 +8,15 @@
 
 #include <sys/ioctl.h>
 
+#include "io/channel-file.h"
 #include "linux-headers/linux/liveupdate.h"
 #include "migration/cpr.h"
+#include "migration/qemu-file.h"
 #include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "qemu/memfd.h"
+
+#define CPR_LUO_STATE_NAME "QEMU_CPR_LUO_STATE"
 
 static int luo_open(Error **errp)
 {
@@ -105,3 +111,54 @@ int cpr_luo_retrieve_fd(int session_fd, uint64_t token, 
Error **errp)
 
     return retrieve.fd;
 }
+
+QEMUFile *cpr_luo_output(Error **errp)
+{
+    int fd = qemu_memfd_create(CPR_LUO_STATE_NAME, 0, false, 0, 0, errp);
+
+    if (fd < 0) {
+        return NULL;
+    }
+
+    return cpr_file_new_fd_output(fd, CPR_LUO_STATE_NAME);
+}
+
+QEMUFile *cpr_luo_input(int session_fd, Error **errp)
+{
+    int fd = cpr_luo_retrieve_fd(session_fd, CPR_LUO_STATE_TOKEN, errp);
+
+    if (fd < 0) {
+        return NULL;
+    }
+
+    lseek(fd, 0, SEEK_SET);
+    return cpr_file_new_fd_input(fd, CPR_LUO_STATE_NAME);
+}
+
+bool cpr_luo_persist_state(int session_fd, QEMUFile *f, Error **errp)
+{
+    QIOChannelFile *fioc = QIO_CHANNEL_FILE(qemu_file_get_ioc(f));
+
+    /*
+     * The file size (the memfd in this case) cannot be changed after it
+     * is preserved. Flush all data before preserving the state fd.
+     */
+    if (qemu_fflush(f) < 0) {
+        error_setg(errp, "failed to flush cpr-luo state");
+        return false;
+    }
+
+    return cpr_luo_preserve_fd(session_fd, fioc->fd,
+                               CPR_LUO_STATE_TOKEN, errp) == 0;
+}
+
+void cpr_luo_abort(void)
+{
+    int session_fd = cpr_state.luo_session_fd;
+
+    if (session_fd >= 0) {
+        close(session_fd);
+    }
+
+    cpr_state.luo_session_fd = -1;
+}
diff --git a/migration/cpr.c b/migration/cpr.c
index 3e8e94e5fe..2253fddb42 100644
--- a/migration/cpr.c
+++ b/migration/cpr.c
@@ -24,7 +24,9 @@
 /*************************************************************************/
 /* cpr state container for all information to be saved. */
 
-CprState cpr_state;
+CprState cpr_state = {
+    .luo_session_fd = -1,
+};
 static GHashTable *cpr_fds_hash;
 
 /****************************************************************************/
-- 
2.43.5


Reply via email to