[v3,03/17] conf: Add <disk model='virtio-{non-}transitional'/>

Message ID 1c1384ef9b7c80c9e9c254d555e9dfd049d965c3.1549663396.git.crobinso@redhat.com
State New
Headers show
Series
  • qemu: virtio-{non-}transitional support
Related show

Commit Message

Cole Robinson Feb. 8, 2019, 10:11 p.m.
<disk> devices lack the model= attribute which is used by
most other device types. bus= mostly acts as one, but it
serves other purposes too like determing what target=
prefix to use, and for matching against controller type=
values.

Extending bus= to handle additional virtio transitional
devices will complicate apps lives, and it isn't a clean
mapping anyways. So let's bite the bullet and add a new
<disk model=X/> attribute, and wire up common handling
for virtio and virtio-{non-}transitional

Signed-off-by: Cole Robinson <crobinso@redhat.com>

---
 docs/formatdomain.html.in                     | 45 +++++++++++++++++++
 docs/schemas/domaincommon.rng                 |  9 ++++
 src/conf/domain_conf.c                        | 40 +++++++++++++++++
 src/conf/domain_conf.h                        | 11 +++++
 src/libvirt_private.syms                      |  2 +
 .../virtio-non-transitional.x86_64-3.1.0.args | 34 ++++++++++++++
 ...virtio-non-transitional.x86_64-latest.args | 34 ++++++++++++++
 .../virtio-non-transitional.xml               | 17 +++++++
 .../virtio-transitional.x86_64-3.1.0.args     | 34 ++++++++++++++
 .../virtio-transitional.x86_64-latest.args    | 34 ++++++++++++++
 .../qemuxml2argvdata/virtio-transitional.xml  | 17 +++++++
 tests/qemuxml2argvtest.c                      |  6 +++
 .../virtio-non-transitional.xml               | 42 +++++++++++++++++
 .../virtio-transitional.xml                   | 42 +++++++++++++++++
 tests/qemuxml2xmltest.c                       | 11 +++++
 15 files changed, 378 insertions(+)
 create mode 100644 tests/qemuxml2argvdata/virtio-non-transitional.x86_64-3.1.0.args
 create mode 100644 tests/qemuxml2argvdata/virtio-non-transitional.x86_64-latest.args
 create mode 100644 tests/qemuxml2argvdata/virtio-non-transitional.xml
 create mode 100644 tests/qemuxml2argvdata/virtio-transitional.x86_64-3.1.0.args
 create mode 100644 tests/qemuxml2argvdata/virtio-transitional.x86_64-latest.args
 create mode 100644 tests/qemuxml2argvdata/virtio-transitional.xml
 create mode 100644 tests/qemuxml2xmloutdata/virtio-non-transitional.xml
 create mode 100644 tests/qemuxml2xmloutdata/virtio-transitional.xml

-- 
2.20.1

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Comments

Andrea Bolognani Feb. 12, 2019, 2:29 p.m. | #1
On Fri, 2019-02-08 at 17:11 -0500, Cole Robinson wrote:
[...]
> +++ b/docs/formatdomain.html.in

> @@ -2922,6 +2922,17 @@

>              <span class="since">Since 0.1.4</span>

>              </p>

>              </dd>

> +          <dt><code>model</code></dt>

> +            <dd>

> +            Indicates the emulated device model of the disk. Typically

> +            this is indicated solely by the <code>bus</code> property but

> +            for <code>bus</code> "virtio" the model can be specified further

> +            with "virtio-transitional", "virtio-non-transitional", or

> +            "virtio", see


s/, see/. See/

[...]
> +      <dt><code>virtio-transitional</code></dt>

> +      <dd>This instructs libvirt to always place the device in a conventional

> +      PCI slot. The device can work with a virtio 0.9 or virtio 1.0

> +      guest driver.

> +      </dd>


I'd reword this a bit to highlight the fact that protocol
compatibility is the main point of these devices, and slot assignment
stems from it. Something like

  This device can work both with virtio 0.9 and virtio 1.0 guest
  drivers, so it's the best choice when compatibility with older
  guest operating systems is desired. libvirt will plug the device
  into a conventional PCI slot.

> +      <dt><code>virtio-non-transitional</code></dt>

> +      <dd>

> +      The device can only work with a virtio 1.0 guest driver.


In the same vein as the above,

  This device can only work with virtio 1.0 guest drivers, and it's
  the recommended option unless compatibility with older guest
  operating systems is necessary. libvirt will plug the device into
  either a PCI Express slot or a conventional PCI slot based on the
  machine type, resulting in a more optimized PCI topology.

> +      </dd>

> +      <dt><code>virtio</code></dt>

> +      <dd> If the device is plugged into a PCIe slot, it acts as a

> +      virtio-non-transitional device. If plugged into a conventional PCI slot,

> +      it will function as a virtio-transitional device. This logic only

> +      applies to devices that support the transitional models; for other

> +      devices, <code>virtio</code> behavior will be different.


And here too,

  This device will work like a <code>virtio-non-transitional</code>
  device when plugged into a PCI Express slot, and like a
  <code>virtio-transitional</code> device otherwise; libvirt will
  pick one or the other based on the machine type. This is the best
  choice when compatibility with libvirt versions older than 5.1.0
  is necessary, but it's otherwise not recommended to use it.

The idea behind these suggestions is that we should help the user
understand the various trade-offs and pick the value that better
suits their needs.

[...]
> +++ b/tests/qemuxml2argvdata/virtio-non-transitional.xml

> @@ -0,0 +1,17 @@

> +<domain type='qemu'>

> +  <name>QEMUGuest1</name>

> +  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>

> +  <memory unit='KiB'>219136</memory>

> +  <os>

> +    <type arch='x86_64' machine='q35'>hvm</type>

> +  </os>

> +  <devices>

> +    <disk type='block' device='disk' model='virtio-non-transitional'>

> +      <driver name='qemu' type='raw'/>

> +      <source dev='/dev/HostVG/QEMUGuest1'/>

> +      <target dev='vda' bus='virtio'/>

> +    </disk>

> +    <controller type='usb' index='0' model='none'/>


s/index='0' //

[...]
> +++ b/tests/qemuxml2argvdata/virtio-transitional.xml

> @@ -0,0 +1,17 @@

> +<domain type='qemu'>

> +  <name>QEMUGuest1</name>

> +  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>

> +  <memory unit='KiB'>219136</memory>

> +  <os>

> +    <type arch='x86_64' machine='q35'>hvm</type>

> +  </os>

> +  <devices>

> +    <disk type='block' device='disk' model='virtio-transitional'>

> +      <driver name='qemu' type='raw'/>

> +      <source dev='/dev/HostVG/QEMUGuest1'/>

> +      <target dev='vda' bus='virtio'/>

> +    </disk>

> +    <controller type='usb' index='0' model='none'/>


Here too.


Reviewed-by: Andrea Bolognani <abologna@redhat.com>


-- 
Andrea Bolognani / Red Hat / Virtualization

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Patch

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 2ae5006849..85bc6a9d0b 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2922,6 +2922,17 @@ 
             <span class="since">Since 0.1.4</span>
             </p>
             </dd>
+          <dt><code>model</code></dt>
+            <dd>
+            Indicates the emulated device model of the disk. Typically
+            this is indicated solely by the <code>bus</code> property but
+            for <code>bus</code> "virtio" the model can be specified further
+            with "virtio-transitional", "virtio-non-transitional", or
+            "virtio", see
+            <a href="#elementsVirtioTransitional">Virtio transitional devices</a>
+            for more details.
+            <span class="since">Since 5.1.0</span>
+            </dd>
           <dt><code>rawio</code></dt>
             <dd>
             Indicates whether the disk needs rawio capability. Valid
@@ -4074,6 +4085,40 @@ 
       <span class="since">Since 3.5.0</span>
     </p>
 
+    <h4><a id="elementsVirtioTransitional">Virtio transitional devices</a></h4>
+
+    <p>
+      <span class="since">Since 5.1.0</span>, some of QEMU's virtio devices,
+      when used with PCI/PCIe machine types, accept the following
+      <code>model</code> values:
+    </p>
+
+    <dl>
+      <dt><code>virtio-transitional</code></dt>
+      <dd>This instructs libvirt to always place the device in a conventional
+      PCI slot. The device can work with a virtio 0.9 or virtio 1.0
+      guest driver.
+      </dd>
+      <dt><code>virtio-non-transitional</code></dt>
+      <dd>
+      The device can only work with a virtio 1.0 guest driver.
+      </dd>
+      <dt><code>virtio</code></dt>
+      <dd> If the device is plugged into a PCIe slot, it acts as a
+      virtio-non-transitional device. If plugged into a conventional PCI slot,
+      it will function as a virtio-transitional device. This logic only
+      applies to devices that support the transitional models; for other
+      devices, <code>virtio</code> behavior will be different.
+      </dd>
+    </dl>
+
+    <p>
+      For more details see the
+      <a href="https://lists.gnu.org/archive/html/qemu-devel/2018-12/msg00923.html">qemu patch posting</a> and the
+      <a href="http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html">virtio-1.0 spec</a>.
+    </p>
+
+
     <h4><a id="elementsControllers">Controllers</a></h4>
 
     <p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index ba80440c72..8811cf7e45 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -1509,6 +1509,15 @@ 
           </interleave>
         </group>
       </choice>
+      <optional>
+        <attribute name="model">
+          <choice>
+            <value>virtio</value>
+            <value>virtio-transitional</value>
+            <value>virtio-non-transitional</value>
+          </choice>
+        </attribute>
+      </optional>
       <optional>
         <ref name="snapshot"/>
       </optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 6772c327ed..3768143b2c 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -985,6 +985,13 @@  VIR_ENUM_IMPL(virDomainDiskDetectZeroes, VIR_DOMAIN_DISK_DETECT_ZEROES_LAST,
               "unmap",
 );
 
+VIR_ENUM_IMPL(virDomainDiskModel, VIR_DOMAIN_DISK_MODEL_LAST,
+              "default",
+              "virtio",
+              "virtio-transitional",
+              "virtio-non-transitional",
+);
+
 VIR_ENUM_IMPL(virDomainDiskMirrorState, VIR_DOMAIN_DISK_MIRROR_STATE_LAST,
               "none",
               "yes",
@@ -5633,6 +5640,17 @@  virDomainDiskDefValidate(const virDomainDiskDef *disk)
         return -1;
     }
 
+    if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO &&
+        (disk->model == VIR_DOMAIN_DISK_MODEL_VIRTIO ||
+         disk->model == VIR_DOMAIN_DISK_MODEL_VIRTIO_TRANSITIONAL ||
+         disk->model == VIR_DOMAIN_DISK_MODEL_VIRTIO_NON_TRANSITIONAL)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("disk model '%s' not supported for bus '%s'"),
+                       virDomainDiskModelTypeToString(disk->model),
+                       virDomainDiskBusTypeToString(disk->bus));
+        return -1;
+    }
+
     return 0;
 }
 
@@ -9719,6 +9737,14 @@  virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
     }
     VIR_FREE(tmp);
 
+    if ((tmp = virXMLPropString(node, "model")) &&
+        (def->model = virDomainDiskModelTypeFromString(tmp)) < 0) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("unknown disk model '%s'"), tmp);
+        goto error;
+    }
+    VIR_FREE(tmp);
+
     snapshot = virXMLPropString(node, "snapshot");
 
     rawio = virXMLPropString(node, "rawio");
@@ -21960,6 +21986,14 @@  virDomainDiskDefCheckABIStability(virDomainDiskDefPtr src,
         return false;
     }
 
+    if (src->model != dst->model) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target disk model %s does not match source %s"),
+                       virDomainDiskModelTypeToString(dst->model),
+                       virDomainDiskModelTypeToString(src->model));
+        return false;
+    }
+
     if (src->virtio && dst->virtio &&
         !virDomainVirtioOptionsCheckABIStability(src->virtio, dst->virtio))
         return false;
@@ -24517,6 +24551,12 @@  virDomainDiskDefFormat(virBufferPtr buf,
     virBufferAsprintf(buf,
                       "<disk type='%s' device='%s'",
                       type, device);
+
+    if (def->model) {
+        virBufferAsprintf(buf, " model='%s'",
+                          virDomainDiskModelTypeToString(def->model));
+    }
+
     if (def->rawio) {
         virBufferAsprintf(buf, " rawio='%s'",
                           virTristateBoolTypeToString(def->rawio));
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 2bc3f879f7..ecf8b06c2e 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -567,6 +567,15 @@  typedef enum {
     VIR_DOMAIN_DISK_DETECT_ZEROES_LAST
 } virDomainDiskDetectZeroes;
 
+typedef enum {
+    VIR_DOMAIN_DISK_MODEL_DEFAULT = 0,
+    VIR_DOMAIN_DISK_MODEL_VIRTIO,
+    VIR_DOMAIN_DISK_MODEL_VIRTIO_TRANSITIONAL,
+    VIR_DOMAIN_DISK_MODEL_VIRTIO_NON_TRANSITIONAL,
+
+    VIR_DOMAIN_DISK_MODEL_LAST
+} virDomainDiskModel;
+
 typedef struct _virDomainBlockIoTuneInfo virDomainBlockIoTuneInfo;
 struct _virDomainBlockIoTuneInfo {
     unsigned long long total_bytes_sec;
@@ -674,6 +683,7 @@  struct _virDomainDiskDef {
     int detect_zeroes; /* enum virDomainDiskDetectZeroes */
     char *domain_name; /* backend domain name */
     unsigned int queues;
+    int model; /* enum virDomainDiskModel */
     virDomainVirtioOptionsPtr virtio;
 };
 
@@ -3416,6 +3426,7 @@  VIR_ENUM_DECL(virDomainDeviceSGIO);
 VIR_ENUM_DECL(virDomainDiskTray);
 VIR_ENUM_DECL(virDomainDiskDiscard);
 VIR_ENUM_DECL(virDomainDiskDetectZeroes);
+VIR_ENUM_DECL(virDomainDiskModel);
 VIR_ENUM_DECL(virDomainDiskMirrorState);
 VIR_ENUM_DECL(virDomainController);
 VIR_ENUM_DECL(virDomainControllerModelPCI);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 67579742fd..aeedb1834c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -344,6 +344,8 @@  virDomainDiskIoTypeFromString;
 virDomainDiskIoTypeToString;
 virDomainDiskMirrorStateTypeFromString;
 virDomainDiskMirrorStateTypeToString;
+virDomainDiskModelTypeFromString;
+virDomainDiskModelTypeToString;
 virDomainDiskPathByName;
 virDomainDiskRemove;
 virDomainDiskRemoveByName;
diff --git a/tests/qemuxml2argvdata/virtio-non-transitional.x86_64-3.1.0.args b/tests/qemuxml2argvdata/virtio-non-transitional.x86_64-3.1.0.args
new file mode 100644
index 0000000000..9e11e900da
--- /dev/null
+++ b/tests/qemuxml2argvdata/virtio-non-transitional.x86_64-3.1.0.args
@@ -0,0 +1,34 @@ 
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-x86_64 \
+-name guest=QEMUGuest1,debug-threads=on \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
+-machine pc-q35-3.1,accel=tcg,usb=off,dump-guest-core=off \
+-m 214 \
+-realtime mlock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-boot strict=on \
+-device pcie-root-port,port=0x8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,\
+addr=0x1 \
+-device pcie-root-port,port=0x9,chassis=2,id=pci.2,bus=pcie.0,addr=0x1.0x1 \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,scsi=off,bus=pci.1,addr=0x0,drive=drive-virtio-disk0,\
+id=virtio-disk0,bootindex=1 \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\
+resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxml2argvdata/virtio-non-transitional.x86_64-latest.args b/tests/qemuxml2argvdata/virtio-non-transitional.x86_64-latest.args
new file mode 100644
index 0000000000..070b4b8334
--- /dev/null
+++ b/tests/qemuxml2argvdata/virtio-non-transitional.x86_64-latest.args
@@ -0,0 +1,34 @@ 
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-x86_64 \
+-name guest=QEMUGuest1,debug-threads=on \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
+-machine q35,accel=tcg,usb=off,dump-guest-core=off \
+-m 214 \
+-realtime mlock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-boot strict=on \
+-device pcie-root-port,port=0x8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,\
+addr=0x1 \
+-device pcie-root-port,port=0x9,chassis=2,id=pci.2,bus=pcie.0,addr=0x1.0x1 \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,scsi=off,bus=pci.1,addr=0x0,drive=drive-virtio-disk0,\
+id=virtio-disk0,bootindex=1 \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\
+resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxml2argvdata/virtio-non-transitional.xml b/tests/qemuxml2argvdata/virtio-non-transitional.xml
new file mode 100644
index 0000000000..115ae48737
--- /dev/null
+++ b/tests/qemuxml2argvdata/virtio-non-transitional.xml
@@ -0,0 +1,17 @@ 
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <os>
+    <type arch='x86_64' machine='q35'>hvm</type>
+  </os>
+  <devices>
+    <disk type='block' device='disk' model='virtio-non-transitional'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='vda' bus='virtio'/>
+    </disk>
+    <controller type='usb' index='0' model='none'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/virtio-transitional.x86_64-3.1.0.args b/tests/qemuxml2argvdata/virtio-transitional.x86_64-3.1.0.args
new file mode 100644
index 0000000000..9e11e900da
--- /dev/null
+++ b/tests/qemuxml2argvdata/virtio-transitional.x86_64-3.1.0.args
@@ -0,0 +1,34 @@ 
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-x86_64 \
+-name guest=QEMUGuest1,debug-threads=on \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
+-machine pc-q35-3.1,accel=tcg,usb=off,dump-guest-core=off \
+-m 214 \
+-realtime mlock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-boot strict=on \
+-device pcie-root-port,port=0x8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,\
+addr=0x1 \
+-device pcie-root-port,port=0x9,chassis=2,id=pci.2,bus=pcie.0,addr=0x1.0x1 \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,scsi=off,bus=pci.1,addr=0x0,drive=drive-virtio-disk0,\
+id=virtio-disk0,bootindex=1 \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\
+resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxml2argvdata/virtio-transitional.x86_64-latest.args b/tests/qemuxml2argvdata/virtio-transitional.x86_64-latest.args
new file mode 100644
index 0000000000..070b4b8334
--- /dev/null
+++ b/tests/qemuxml2argvdata/virtio-transitional.x86_64-latest.args
@@ -0,0 +1,34 @@ 
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-x86_64 \
+-name guest=QEMUGuest1,debug-threads=on \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
+-machine q35,accel=tcg,usb=off,dump-guest-core=off \
+-m 214 \
+-realtime mlock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-boot strict=on \
+-device pcie-root-port,port=0x8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,\
+addr=0x1 \
+-device pcie-root-port,port=0x9,chassis=2,id=pci.2,bus=pcie.0,addr=0x1.0x1 \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,scsi=off,bus=pci.1,addr=0x0,drive=drive-virtio-disk0,\
+id=virtio-disk0,bootindex=1 \
+-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\
+resourcecontrol=deny \
+-msg timestamp=on
diff --git a/tests/qemuxml2argvdata/virtio-transitional.xml b/tests/qemuxml2argvdata/virtio-transitional.xml
new file mode 100644
index 0000000000..8febfc8423
--- /dev/null
+++ b/tests/qemuxml2argvdata/virtio-transitional.xml
@@ -0,0 +1,17 @@ 
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <os>
+    <type arch='x86_64' machine='q35'>hvm</type>
+  </os>
+  <devices>
+    <disk type='block' device='disk' model='virtio-transitional'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='vda' bus='virtio'/>
+    </disk>
+    <controller type='usb' index='0' model='none'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index dd4f73a5fb..de9eb6abdb 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -2996,6 +2996,12 @@  mymain(void)
     DO_TEST("riscv64-virt-pci",
             QEMU_CAPS_OBJECT_GPEX);
 
+    /* Older version checks disable-legacy usage */
+    DO_TEST_CAPS_VER("virtio-transitional", "3.1.0");
+    DO_TEST_CAPS_VER("virtio-non-transitional", "3.1.0");
+    DO_TEST_CAPS_LATEST("virtio-transitional");
+    DO_TEST_CAPS_LATEST("virtio-non-transitional");
+
     /* Simple headless guests for various architectures */
     DO_TEST_CAPS_ARCH_LATEST("aarch64-virt-headless", "aarch64");
     DO_TEST_CAPS_ARCH_LATEST("ppc64-pseries-headless", "ppc64");
diff --git a/tests/qemuxml2xmloutdata/virtio-non-transitional.xml b/tests/qemuxml2xmloutdata/virtio-non-transitional.xml
new file mode 100644
index 0000000000..7e4aa16b32
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/virtio-non-transitional.xml
@@ -0,0 +1,42 @@ 
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='q35'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <disk type='block' device='disk' model='virtio-non-transitional'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='vda' bus='virtio'/>
+      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+    </disk>
+    <controller type='usb' index='0' model='none'/>
+    <controller type='sata' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pcie-root'/>
+    <controller type='pci' index='1' model='pcie-root-port'>
+      <model name='pcie-root-port'/>
+      <target chassis='1' port='0x8'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+    </controller>
+    <controller type='pci' index='2' model='pcie-root-port'>
+      <model name='pcie-root-port'/>
+      <target chassis='2' port='0x9'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/virtio-transitional.xml b/tests/qemuxml2xmloutdata/virtio-transitional.xml
new file mode 100644
index 0000000000..1d28af9abb
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/virtio-transitional.xml
@@ -0,0 +1,42 @@ 
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='q35'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <disk type='block' device='disk' model='virtio-transitional'>
+      <driver name='qemu' type='raw'/>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='vda' bus='virtio'/>
+      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+    </disk>
+    <controller type='usb' index='0' model='none'/>
+    <controller type='sata' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pcie-root'/>
+    <controller type='pci' index='1' model='pcie-root-port'>
+      <model name='pcie-root-port'/>
+      <target chassis='1' port='0x8'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+    </controller>
+    <controller type='pci' index='2' model='pcie-root-port'>
+      <model name='pcie-root-port'/>
+      <target chassis='2' port='0x9'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index b38cbd6994..15f0ccffb1 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -1254,6 +1254,17 @@  mymain(void)
     DO_TEST("riscv64-virt-pci",
             QEMU_CAPS_OBJECT_GPEX);
 
+    DO_TEST("virtio-transitional",
+            QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
+            QEMU_CAPS_DEVICE_PCIE_PCI_BRIDGE,
+            QEMU_CAPS_DEVICE_PCIE_ROOT_PORT,
+            QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY);
+    DO_TEST("virtio-non-transitional",
+            QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
+            QEMU_CAPS_DEVICE_PCIE_PCI_BRIDGE,
+            QEMU_CAPS_DEVICE_PCIE_ROOT_PORT,
+            QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY);
+
     if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL)
         virFileDeleteTree(fakerootdir);