[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[XEN PATCH] libxl: Use fdset to provide migration saved state file



Since QEMU 11.0, `-incoming fd:` doesn't accept file descriptors of
plain file, only sockets and pipe are accepted. This has been
deprecated since QEMU 9.1

Instead, switch to use `-incoming file:` with an fdset.

`incoming file:` schema seems to have been only introduced in QEMU
8.2. And `-incoming` isn't present in `query-command-line-options` QMP
command output, so we'll use a check based on QEMU version instead.

QEMU keep the FD open when added as a fdset, so close it in
postconfig. And now we have two optional set QMP command to run after
starting QEMU, for VNC and for migration.

Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
 tools/libs/light/libxl_dm.c       | 98 ++++++++++++++++++++++++++++---
 tools/libs/light/libxl_internal.h |  1 +
 2 files changed, 90 insertions(+), 9 deletions(-)

diff --git a/tools/libs/light/libxl_dm.c b/tools/libs/light/libxl_dm.c
index 511ec76a65..0fdeded92b 100644
--- a/tools/libs/light/libxl_dm.c
+++ b/tools/libs/light/libxl_dm.c
@@ -24,6 +24,8 @@
 #include <pwd.h>
 #include <grp.h>
 
+#define QEMU_FDSET_SAVED_STATE 1
+
 static const char *libxl_tapif_script(libxl__gc *gc)
 {
 #if defined(__linux__) || defined(__FreeBSD__)
@@ -1546,8 +1548,21 @@ static int libxl__build_device_model_args_new(libxl__gc 
*gc,
         } else {
             /* This file descriptor is meant to be used by QEMU */
             *dm_state_fd = open(state->saved_state, O_RDONLY);
-            flexarray_append(dm_args, "-incoming");
-            flexarray_append(dm_args, GCSPRINTF("fd:%d",*dm_state_fd));
+            if (qemu_opts->use_incoming_file) {
+                flexarray_append_pair(dm_args, "-add-fd",
+                     GCSPRINTF("fd=%d,set="STR(QEMU_FDSET_SAVED_STATE)
+                               ",opaque=\"saved_state\"",
+                               *dm_state_fd));
+                flexarray_append_pair(dm_args, "-incoming",
+                                      "file:/dev/fdset/1");
+            } else {
+                /*
+                 * Passing a file descriptor of a plain file to `fd:` has
+                 * been deprecated in QEMU 9.1.
+                 */
+                flexarray_append(dm_args, "-incoming");
+                flexarray_append(dm_args, GCSPRINTF("fd:%d", *dm_state_fd));
+            }
         }
     }
     for (i = 0; b_info->extra && b_info->extra[i] != NULL; i++)
@@ -2631,6 +2646,12 @@ static void device_model_launch(libxl__egc *egc,
     libxl__dm_spawn_state *dmss, int rc);
 static void device_model_postconfig_chardev(libxl__egc *egc,
     libxl__ev_qmp *qmp, const libxl__json_object *response, int rc);
+static void device_model_postconfig_do_remove_fdset(libxl__egc *egc,
+    libxl__ev_qmp *qmp, int rc);
+static void device_model_postconfig_removed_fdset(libxl__egc *egc,
+    libxl__ev_qmp *qmp, const libxl__json_object *response, int rc);
+static void device_model_postconfig_do_vnc(libxl__egc *egc,
+    libxl__ev_qmp *qmp, int rc);
 static void device_model_postconfig_vnc(libxl__egc *egc,
     libxl__ev_qmp *qmp, const libxl__json_object *response, int rc);
 static void device_model_postconfig_vnc_passwd(libxl__egc *egc,
@@ -2832,6 +2853,13 @@ static void device_model_probe_cmdline(libxl__egc *egc,
         }
     }
 
+    /*
+     * Other checks based on QEMU's version
+     */
+    if (libxl__qmp_ev_qemu_compare_version(qmp, 9, 1, 0) >= 0) {
+        dmss->qemu_opts.use_incoming_file = true;
+    }
+
     qmp->callback = device_model_probe_quit;
     rc = libxl__ev_qmp_send(egc, qmp, "quit", NULL);
     if (rc) goto out;
@@ -3152,7 +3180,6 @@ static void device_model_postconfig_chardev(libxl__egc 
*egc,
 {
     EGC_GC;
     libxl__dm_spawn_state *dmss = CONTAINER_OF(qmp, *dmss, qmp);
-    const libxl_vnc_info *vnc = libxl__dm_vnc(dmss->guest_config);
     const libxl__json_object *item = NULL;
     const libxl__json_object *o = NULL;
     int i = 0;
@@ -3210,12 +3237,7 @@ static void device_model_postconfig_chardev(libxl__egc 
*egc,
         if (rc) goto out;
     }
 
-    if (!vnc)
-        goto out;
-
-    qmp->callback = device_model_postconfig_vnc;
-    rc = libxl__ev_qmp_send(egc, qmp, "query-vnc", NULL);
-    if (rc) goto out;
+    device_model_postconfig_do_remove_fdset(egc, qmp, rc); /* must be last */
     return;
 
 protocol_error:
@@ -3227,6 +3249,64 @@ static void device_model_postconfig_chardev(libxl__egc 
*egc,
     device_model_postconfig_done(egc, dmss, rc); /* must be last */
 }
 
+static void device_model_postconfig_do_remove_fdset(libxl__egc *egc,
+    libxl__ev_qmp *qmp, int rc)
+{
+    EGC_GC;
+    libxl__dm_spawn_state *dmss = CONTAINER_OF(qmp, *dmss, qmp);
+
+    /*
+     * If we used -add-fd for the `saved_state`, ask QEMU to close it.
+     */
+    if (dmss->qemu_opts.use_incoming_file && dmss->build_state->saved_state) {
+        libxl__json_object *args = NULL;
+        qmp->callback = device_model_postconfig_removed_fdset;
+        libxl__qmp_param_add_integer(gc, &args, "fdset-id",
+                                     QEMU_FDSET_SAVED_STATE);
+        rc = libxl__ev_qmp_send(egc, qmp, "remove-fd", args);
+        if (rc) goto out;
+        return;
+    }
+
+    device_model_postconfig_do_vnc(egc, qmp, rc); /* must be last */
+    return;
+
+out:
+    device_model_postconfig_done(egc, dmss, rc); /* must be last */
+}
+
+static void device_model_postconfig_removed_fdset(libxl__egc *egc,
+    libxl__ev_qmp *qmp, const libxl__json_object *response, int rc)
+{
+    libxl__dm_spawn_state *dmss = CONTAINER_OF(qmp, *dmss, qmp);
+
+    if (rc) goto out;
+
+    device_model_postconfig_do_vnc(egc, qmp, rc); /* must be last */
+    return;
+
+out:
+    device_model_postconfig_done(egc, dmss, rc); /* must be last */
+}
+
+static void device_model_postconfig_do_vnc(libxl__egc *egc,
+    libxl__ev_qmp *qmp, int rc)
+{
+    EGC_GC;
+    libxl__dm_spawn_state *dmss = CONTAINER_OF(qmp, *dmss, qmp);
+    const libxl_vnc_info *vnc = libxl__dm_vnc(dmss->guest_config);
+
+    if (vnc) {
+        qmp->callback = device_model_postconfig_vnc;
+        rc = libxl__ev_qmp_send(egc, qmp, "query-vnc", NULL);
+        if (rc) goto out;
+        return;
+    }
+
+out:
+    device_model_postconfig_done(egc, dmss, rc); /* must be last */
+}
+
 static void device_model_postconfig_vnc(libxl__egc *egc,
     libxl__ev_qmp *qmp, const libxl__json_object *response, int rc)
 {
diff --git a/tools/libs/light/libxl_internal.h 
b/tools/libs/light/libxl_internal.h
index b65e0064b9..7d916ee64a 100644
--- a/tools/libs/light/libxl_internal.h
+++ b/tools/libs/light/libxl_internal.h
@@ -4094,6 +4094,7 @@ typedef struct libxl__qemu_available_opts 
libxl__qemu_available_opts;
 struct libxl__qemu_available_opts {
     bool have_runwith_chroot;
     bool have_runwith_user;
+    bool use_incoming_file;
 };
 
 typedef void libxl__dm_spawn_cb(libxl__egc *egc, libxl__dm_spawn_state*,
-- 
Anthony PERARD



--
 | Vates

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.