]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
domain_addr.c: Fix virtio console port autoassign on virtio-serial bus
authorAaron M. Brown <aaronmbr@linux.ibm.com>
Fri, 19 Sep 2025 19:26:19 +0000 (15:26 -0400)
committerPeter Krempa <pkrempa@redhat.com>
Mon, 24 Nov 2025 14:40:57 +0000 (15:40 +0100)
This change fixes an issue with virtio console port assignment on virtio-serial buses.
Currently, when trying to autoassign a virtio console device, the device cannot be
assigned to a port greater than 0 on virtio-serial buses.
You will receive the following error:

`virtio-serial-bus: A port already exists at id 0`

Therefore, the data needs to be passed back into info when allowZero is true.
We should also preserve the controller data when allowZero is true, and
propagate allowZero into virDomainVirtioSerialAddrNextFromController
to get an appropriate startPort.

Fixes: 16db8d2e ("Add functions to track virtio-serial addresses")
Signed-off-by: Aaron M. Brown <aaronmbr@linux.ibm.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
src/conf/domain_addr.c
tests/qemuxmlconfdata/console-virtio-serial-autoassign-address.x86_64-latest.args
tests/qemuxmlconfdata/console-virtio-serial-autoassign-address.x86_64-latest.xml

index 6aa5ac1b9facb3b9daaac66c4e57f58d02db5c6a..87c5973fabe5da96358e982a062218af1f41b972 100644 (file)
@@ -1717,12 +1717,17 @@ virDomainVirtioSerialAddrNext(virDomainDef *def,
 
 static int
 virDomainVirtioSerialAddrNextFromController(virDomainVirtioSerialAddrSet *addrs,
-                                            virDomainDeviceVirtioSerialAddress *addr)
+                                            virDomainDeviceVirtioSerialAddress *addr,
+                                            bool allowZero)
 {
+    ssize_t startPort = 0;
     ssize_t port;
     ssize_t i;
     virBitmap *map;
 
+    if (allowZero)
+        startPort = -1;
+
     i = virDomainVirtioSerialAddrFindController(addrs, addr->controller);
     if (i < 0) {
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1732,7 +1737,7 @@ virDomainVirtioSerialAddrNextFromController(virDomainVirtioSerialAddrSet *addrs,
     }
 
     map = addrs->controllers[i]->ports;
-    if ((port = virBitmapNextClearBit(map, 0)) <= 0) {
+    if ((port = virBitmapNextClearBit(map, startPort)) < 0) {
         virReportError(VIR_ERR_XML_ERROR,
                        _("Unable to find a free port on virtio-serial controller %1$u"),
                        addr->controller);
@@ -1755,13 +1760,33 @@ virDomainVirtioSerialAddrAssign(virDomainDef *def,
 {
     virDomainDeviceInfo nfo = { 0 };
     virDomainDeviceInfo *ptr = allowZero ? &nfo : info;
+    virBitmap *map;
+    ssize_t i;
 
     ptr->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL;
+    ptr->addr.vioserial.controller = info->addr.vioserial.controller;
 
     if (portOnly) {
         if (virDomainVirtioSerialAddrNextFromController(addrs,
-                                                        &ptr->addr.vioserial) < 0)
+                                                        &ptr->addr.vioserial,
+                                                        allowZero) < 0)
             return -1;
+
+        if (ptr == &nfo) {
+            /* pass the vioserial data back into info as info is used
+             * later for port assignment */
+            info->addr.vioserial = ptr->addr.vioserial;
+
+            /* if the next available port from the controller is zero,
+             * let's reserve it in the map and return */
+            if (ptr->addr.vioserial.port == 0) {
+                i = virDomainVirtioSerialAddrFindController(addrs, ptr->addr.vioserial.controller);
+                map = addrs->controllers[i]->ports;
+                ignore_value(virBitmapSetBit(map, 0));
+                return 0;
+            }
+        }
+
     } else {
         if (virDomainVirtioSerialAddrNext(def, addrs, &ptr->addr.vioserial,
                                           allowZero) < 0)
index 4fbd1e1a5e10cadb6557daa914e395300e2a2c43..8070b3e2af18a31c8db78f6f70910a5fcf860ca8 100644 (file)
@@ -33,9 +33,9 @@ XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-QEMUGuest1/.config \
 -chardev pty,id=charconsole1 \
 -device '{"driver":"virtconsole","bus":"virtio-serial0.0","nr":0,"chardev":"charconsole1","id":"console1"}' \
 -chardev pty,id=charconsole2 \
--device '{"driver":"virtconsole","bus":"virtio-serial0.0","nr":0,"chardev":"charconsole2","id":"console2"}' \
+-device '{"driver":"virtconsole","bus":"virtio-serial0.0","nr":1,"chardev":"charconsole2","id":"console2"}' \
 -chardev pty,id=charconsole3 \
--device '{"driver":"virtconsole","bus":"virtio-serial0.0","nr":0,"chardev":"charconsole3","id":"console3"}' \
+-device '{"driver":"virtconsole","bus":"virtio-serial0.0","nr":2,"chardev":"charconsole3","id":"console3"}' \
 -audiodev '{"id":"audio1","driver":"none"}' \
 -device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","addr":"0x3"}' \
 -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
index 9939584a9abce1ec17191239fbaffffcbcc53925..971443457ad444d05a29c32db9ab039fd88e7e08 100644 (file)
     </console>
     <console type='pty'>
       <target type='virtio' port='2'/>
-      <address type='virtio-serial' controller='0' bus='0' port='0'/>
+      <address type='virtio-serial' controller='0' bus='0' port='1'/>
     </console>
     <console type='pty'>
       <target type='virtio' port='3'/>
-      <address type='virtio-serial' controller='0' bus='0' port='0'/>
+      <address type='virtio-serial' controller='0' bus='0' port='2'/>
     </console>
     <input type='mouse' bus='ps2'/>
     <input type='keyboard' bus='ps2'/>