@samitouri / QOSamiQemu / commits / 6f23dde620

ui/vdagent: add migration blocker when machine version < 10.1

In QEMU 10.1, commit 5d56bff11e ("ui/vdagent: add migration support") added migration support for the vdagent chardev and commit 42000e0013 ("ui/vdagent: remove migration blocker") removed the migration blocker. No compat for older machine versions was added, so migration with pre-10.1 machine version, from a 10.1 binary to a pre-10.1 binary will result in a failure when loading the VM state in the target instance: > Unknown savevm section or instance 'vdagent' 0. Make sure that your > current VM setup matches your saved VM setup, including any > hotplugged devices Add a compat flag to block migration when the machine version is less than 10.1 to avoid this. Cc: qemu-stable@nongnu.org Fixes: 42000e0013 ("ui/vdagent: remove migration blocker") Signed-off-by: Fiona Ebner <f.ebner@proxmox.com> Reviewed-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-Id: <20260310142552.240877-1-f.ebner@proxmox.com>

Fiona Ebner committed Mar 10, 2026 at 15:25 UTC 6f23dde620efa2de1cf3c56dfb474a20d9ce876d
2 files changed +47
hw/core/machine.c
+1
@@ -57,6 +57,7 @@ GlobalProperty hw_compat_10_0[] = {
57 { "vfio-pci", "x-migration-load-config-after-iter", "off" },
58 { "ramfb", "use-legacy-x86-rom", "true"},
59 { "vfio-pci-nohotplug", "use-legacy-x86-rom", "true" },
60 + { "chardev-qemu-vdagent", "x-migration-blocked", "true" },
61 };
62 const size_t hw_compat_10_0_len = G_N_ELEMENTS(hw_compat_10_0);
63
ui/vdagent.c
+46
@@ -6,6 +6,8 @@
6 #include "qemu/option.h"
7 #include "qemu/units.h"
8 #include "hw/core/qdev.h"
9 +#include "hw/core/qdev-properties.h"
10 +#include "migration/blocker.h"
11 #include "ui/clipboard.h"
12 #include "ui/console.h"
13 #include "ui/input.h"
@@ -24,6 +26,10 @@
26 struct VDAgentChardev {
27 Chardev parent;
28
29 + /* needed for machine versions < 10.1 when migration was not supported */
30 + Error *migration_blocker;
31 + bool migration_blocked;
32 +
33 /* config */
34 bool mouse;
35 bool clipboard;
@@ -657,6 +663,12 @@ static bool vdagent_chr_open(Chardev *chr, ChardevBackend *backend,
663 return false;
664 #endif
665
666 + if (vd->migration_blocked) {
667 + if (migrate_add_blocker(&vd->migration_blocker, errp) != 0) {
668 + return false;
669 + }
670 + }
671 +
672 vd->mouse = VDAGENT_MOUSE_DEFAULT;
673 if (cfg->has_mouse) {
674 vd->mouse = cfg->mouse;
@@ -901,6 +913,19 @@ static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend,
913
914 /* ------------------------------------------------------------------ */
915
916 +static bool get_migration_blocked(Object *o, Error **errp)
917 +{
918 + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(o);
919 + return vd->migration_blocked;
920 +}
921 +
922 +static void set_migration_blocked(Object *o, bool migration_blocked,
923 + Error **errp)
924 +{
925 + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(o);
926 + vd->migration_blocked = migration_blocked;
927 +}
928 +
929 static void vdagent_chr_class_init(ObjectClass *oc, const void *data)
930 {
931 ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -910,6 +935,10 @@ static void vdagent_chr_class_init(ObjectClass *oc, const void *data)
935 cc->chr_write = vdagent_chr_write;
936 cc->chr_set_fe_open = vdagent_chr_set_fe_open;
937 cc->chr_accept_input = vdagent_chr_accept_input;
938 +
939 + object_class_property_add_bool(oc, "x-migration-blocked",
940 + get_migration_blocked,
941 + set_migration_blocked);
942 }
943
944 static int post_load(void *opaque, int version_id)
@@ -1064,10 +1093,26 @@ static void vdagent_chr_instance_init(Object *obj)
1093 vmstate_register_any(NULL, &vmstate_vdagent, vd);
1094 }
1095
1096 +static void vdagent_post_init(Object *obj)
1097 +{
1098 + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
1099 +
1100 + object_apply_compat_props(obj);
1101 +
1102 + if (vd->migration_blocked) {
1103 + error_setg(&vd->migration_blocker,
1104 + "The vdagent chardev doesn't support migration with machine"
1105 + " version less than 10.1");
1106 + }
1107 +}
1108 +
1109 static void vdagent_chr_fini(Object *obj)
1110 {
1111 VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj);
1112
1113 + if (vd->migration_blocked) {
1114 + migrate_del_blocker(&vd->migration_blocker);
1115 + }
1116 vdagent_disconnect(vd);
1117 if (vd->mouse_hs) {
1118 qemu_input_handler_unregister(vd->mouse_hs);
@@ -1080,6 +1125,7 @@ static const TypeInfo vdagent_chr_type_info = {
1125 .parent = TYPE_CHARDEV,
1126 .instance_size = sizeof(VDAgentChardev),
1127 .instance_init = vdagent_chr_instance_init,
1128 + .instance_post_init = vdagent_post_init,
1129 .instance_finalize = vdagent_chr_fini,
1130 .class_init = vdagent_chr_class_init,
1131 };