]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: Implement support for persistent reservation migration control
authorPeter Krempa <pkrempa@redhat.com>
Thu, 11 Dec 2025 18:47:16 +0000 (19:47 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Thu, 12 Feb 2026 15:38:01 +0000 (16:38 +0100)
The 'migration' attribute for the '<reservations>' element allows to
control the persistent reservation migration feature independently of
the machine type default.

Add the XML plumbing and qemu support.

We consider it ABI for now since it influences qemu migration protocol.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
docs/formatdomain.rst
src/conf/domain_conf.c
src/conf/schemas/storagecommon.rng
src/conf/storage_source_conf.c
src/conf/storage_source_conf.h
src/qemu/qemu_command.c
src/qemu/qemu_validate.c
tests/qemuxmlconfdata/disk-virtio-scsi-reservations.x86_64-latest.args
tests/qemuxmlconfdata/disk-virtio-scsi-reservations.xml

index f9f8719f1cb110f0781dd3ea8af3a6015f999700..d1352a8fb192283845f3d1373da2a86993746342 100644 (file)
@@ -3186,6 +3186,9 @@ paravirtualized driver is specified via the ``disk`` element.
       the socket, and finally ``mode`` which accepts one value ``client``
       specifying the role of hypervisor. It's recommended to allow libvirt
       manage the persistent reservations.
+      :since:`Since 12.1.0` the ``migration`` (values ``yes``, ``no``) controls
+      whether the hypervisor should attempt to migrate persistent reservations
+      during migration.
    ``initiator``
       :since:`Since 4.7.0`, the ``initiator`` element is supported for
       a disk ``type`` "network" that is using a ``source`` element with the
index 00b6e1970c077ba2e74ff44e2c1c0b2c5d7f3fd5..93b1175d21e4950b614ad07b3aaf79a38d489ce2 100644 (file)
@@ -21040,6 +21040,27 @@ virDomainDiskDefCheckABIStability(virDomainDiskDef *src,
         return false;
     }
 
+    /* While not guest visible it influences the qemu migration stream so
+     * we need to keep it identical */
+    if (src->src->pr || dst->src->pr) {
+        virTristateBool srcmig = VIR_TRISTATE_BOOL_ABSENT;
+        virTristateBool dstmig = VIR_TRISTATE_BOOL_ABSENT;
+
+        if (src->src->pr)
+            srcmig = src->src->pr->migration;
+
+        if (dst->src->pr)
+            dstmig = dst->src->pr->migration;
+
+        if (srcmig != dstmig) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Target disk reservations 'migration' property %1$s does not match source %2$s"),
+                           virTristateBoolTypeToString(dstmig),
+                           virTristateBoolTypeToString(srcmig));
+            return false;
+        }
+    }
+
     if (!virDomainVirtioOptionsCheckABIStability(src->virtio, dst->virtio))
         return false;
 
index 14704c737eff2040fdb7fae6f8d81619e5efca27..450d53131f21c23efbfd0dbc3b8fddc48d1e4275 100644 (file)
           <ref name="virYesNo"/>
         </attribute>
       </optional>
+      <optional>
+        <attribute name="migration">
+          <ref name="virYesNo"/>
+        </attribute>
+      </optional>
       <optional>
         <ref name="unixSocketSource"/>
       </optional>
index d7b9bdfecb08b9da14e6a343e897c92c39180f28..e5f20fba8031f5021098bbbf64aa2bb81caa6480 100644 (file)
@@ -331,6 +331,11 @@ virStoragePRDefParseXML(xmlXPathContextPtr ctxt)
                                &prd->managed) < 0)
         goto cleanup;
 
+    if (virXMLPropTristateBool(ctxt->node, "migration",
+                               VIR_XML_PROP_NONZERO,
+                               &prd->migration) < 0)
+        goto cleanup;
+
     type = virXPathString("string(./source[1]/@type)", ctxt);
     path = virXPathString("string(./source[1]/@path)", ctxt);
     mode = virXPathString("string(./source[1]/@mode)", ctxt);
@@ -385,6 +390,11 @@ virStoragePRDefFormat(virBuffer *buf,
 {
     virBufferAsprintf(buf, "<reservations managed='%s'",
                       virTristateBoolTypeToString(prd->managed));
+
+    if (prd->migration != VIR_TRISTATE_BOOL_ABSENT)
+        virBufferAsprintf(buf, " migration='%s'",
+                          virTristateBoolTypeToString(prd->migration));
+
     if (prd->path &&
         (prd->managed == VIR_TRISTATE_BOOL_NO || !migratable)) {
         virBufferAddLit(buf, ">\n");
index 22c35d420d4ce2f3345f5ffe173f0a8fcf2c59b4..d3a9b0e7a203b3779939ca9be711fd35444d32ea 100644 (file)
@@ -236,6 +236,8 @@ struct _virStoragePRDef {
     virTristateBool managed;
     char *path;
 
+    virTristateBool migration;
+
     /* manager object alias */
     char *mgralias;
 };
index 069211e13902042401b5585c134a8954f3351334..c09c883a28f8303211d94da9ac412cb011e346a1 100644 (file)
@@ -1692,6 +1692,7 @@ qemuBuildDiskDeviceProps(const virDomainDef *def,
     g_autofree char *usbdiskalias = NULL;
     const virDomainDeviceInfo *deviceinfo = &disk->info;
     g_autoptr(virJSONValue) statistics = NULL;
+    virTristateBool migrate_pr = VIR_TRISTATE_BOOL_ABSENT;
     virDomainDeviceInfo usbSCSIinfo = {
         .type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE,
         .addr.drive = { .diskbus = VIR_DOMAIN_DISK_BUS_USB },
@@ -1717,6 +1718,8 @@ qemuBuildDiskDeviceProps(const virDomainDef *def,
     case VIR_DOMAIN_DISK_BUS_SCSI:
         if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
             driver = "scsi-block";
+            if (disk->src->pr)
+                migrate_pr = disk->src->pr->migration;
         } else {
             if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                 driver = "scsi-cd";
@@ -1938,6 +1941,7 @@ qemuBuildDiskDeviceProps(const virDomainDef *def,
                               "S:rerror", rpolicy,
                               "A:stats-intervals", &statistics,
                               "T:dpofua", disk->dpofua, /* SCSI-only, ensured by validation */
+                              "T:migrate-pr", migrate_pr, /* 'scsi-block' only, ensured by validation */
                               NULL) < 0)
         return NULL;
 
index 0bad2999962457d84c55554775c98bfba0aa503b..2ca38db9f131c6659d8104c05a614de0c57b591c 100644 (file)
@@ -3226,6 +3226,22 @@ qemuValidateDomainDeviceDefDiskFrontend(const virDomainDiskDef *disk,
         }
     }
 
+    if (disk->src->pr &&
+        disk->src->pr->migration != VIR_TRISTATE_BOOL_ABSENT) {
+        if (disk->device != VIR_DOMAIN_DISK_DEVICE_LUN ||
+            disk->bus != VIR_DOMAIN_DISK_BUS_SCSI) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("persistent reservation migration supported only with 'lun' disks on 'scsi' bus"));
+            return -1;
+        }
+
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SCSI_BLOCK_MIGRATE_PR)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("persistent reservation migration not supported by this qemu"));
+            return -1;
+        }
+    }
+
     if (disk->rotation_rate) {
         if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI &&
             disk->bus != VIR_DOMAIN_DISK_BUS_IDE &&
index cbc2a0f3982b32adeefebe541fa7ab79f6d82501..f1d7a450eefdfd71e0a143afc70f5a3da862609b 100644 (file)
@@ -33,7 +33,7 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -device '{"driver":"scsi-block","bus":"scsi0.0","channel":0,"scsi-id":0,"lun":0,"drive":"libvirt-2-storage","id":"scsi0-0-0-0","bootindex":1}' \
 -object '{"qom-type":"pr-manager-helper","id":"pr-helper-libvirt-1-storage","path":"/path/to/qemu-pr-helper.sock"}' \
 -blockdev '{"driver":"host_device","filename":"/dev/HostVG/QEMUGuest2","pr-manager":"pr-helper-libvirt-1-storage","node-name":"libvirt-1-storage","read-only":false}' \
--device '{"driver":"scsi-block","bus":"scsi0.0","channel":0,"scsi-id":0,"lun":1,"drive":"libvirt-1-storage","id":"scsi0-0-0-1"}' \
+-device '{"driver":"scsi-block","bus":"scsi0.0","channel":0,"scsi-id":0,"lun":1,"drive":"libvirt-1-storage","id":"scsi0-0-0-1","migrate-pr":true}' \
 -audiodev '{"id":"audio1","driver":"none"}' \
 -device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","addr":"0x4"}' \
 -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
index 9c55d6ec3ece74a4ee6e9b7376acc3318a6fcd12..7f9160ff3aac18e896f7ca949d9962d80b58ca14 100644 (file)
@@ -28,7 +28,7 @@
     <disk type='block' device='lun'>
       <driver name='qemu' type='raw'/>
       <source dev='/dev/HostVG/QEMUGuest2'>
-        <reservations managed='no'>
+        <reservations managed='no' migration='yes'>
           <source type='unix' path='/path/to/qemu-pr-helper.sock' mode='client'/>
         </reservations>
       </source>