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 <[email protected]> --- 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
