From c34ee3e681e9ac92ebc4655046c15e70fcd49a52 Mon Sep 17 00:00:00 2001
From: Chengfei Huang <huangchengfei3@huawei.com>
Date: Tue, 21 Oct 2025 18:28:29 +0800
Subject: [PATCH] migration: support vfio-pci device migration

add "migration" attribute to
Set migration='on' to enable migration.

Signed-off-by: Chengfei Huang <huangchengfei3@huawei.com>
---
 src/conf/domain_conf.c            | 8 ++++++++
 src/conf/domain_conf.h            | 1 +
 src/conf/schemas/domaincommon.rng | 5 +++++
 src/qemu/qemu_command.c           | 1 +
 src/qemu/qemu_migration.c         | 4 ++++
 5 files changed, 19 insertions(+)

diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e30ec0dca4..2b249b285a 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -6234,6 +6234,10 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node,
 
     model = virXMLPropString(node, "model");
 
+    if (virXMLPropTristateSwitch(node, "migration", VIR_XML_PROP_NONE,
+                                 &def->migration) < 0)
+        return -1;
+
     if (virXMLPropUInt(node, "iommufd", 10, VIR_XML_PROP_NONZERO,
                        &def->iommufd) < 0) {
         virReportError(VIR_ERR_XML_ERROR, "%s",
@@ -26421,6 +26425,10 @@ virDomainHostdevDefFormat(virBuffer *buf,
         virBufferAsprintf(buf, " managed='%s'",
                           def->managed ? "yes" : "no");
 
+        if (def->migration != VIR_TRISTATE_SWITCH_ABSENT)
+            virBufferAsprintf(buf, " migration='%s'",
+                              virTristateSwitchTypeToString(def->migration));
+
         if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
             scsisrc->sgio)
             virBufferAsprintf(buf, " sgio='%s'",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index cadca33246..3470b2b8f4 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -381,6 +381,7 @@ struct _virDomainHostdevDef {
     virDomainHostdevMode mode;
     virDomainStartupPolicy startupPolicy;
     virDomainDeviceNuma numa;
+    virTristateSwitch migration;
     bool managed;
     bool missing;
     bool readonly;
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index 78773f744b..304eccbedd 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -6242,6 +6242,11 @@
         <ref name="virYesNo"/>
       </attribute>
     </optional>
+    <optional>
+      <attribute name="migration">
+        <ref name="virOnOff"/>
+      </attribute>
+    </optional>
     <choice>
       <ref name="hostdevsubsyspci"/>
       <ref name="hostdevsubsysusb"/>
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index cc8ecfa9fb..33ed9f05d2 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4772,6 +4772,7 @@ qemuBuildPCIHostdevDevProps(const virDomainDef *def,
                               "s:id", dev->info->alias,
                               "p:bootindex", dev->info->effectiveBootIndex,
                               "S:failover_pair_id", failover_pair_id,
+                              "S:enable-migration", qemuOnOffAuto(dev->migration),
                               NULL) < 0)
         return NULL;
 
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 5853947e31..ada8bfecd1 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1332,6 +1332,10 @@ qemuMigrationSrcIsAllowedHostdev(const virDomainDef *def)
                     continue;
                 }
 
+                if (hostdev->migration == VIR_TRISTATE_SWITCH_ON) {
+                    continue;
+                }
+
                 /* all other PCI hostdevs can't be migrated */
                 if (hostdev->parentnet) {
                     virDomainNetType actualType = virDomainNetGetActualType(hostdev->parentnet);
-- 
2.33.0