6ae9ed
From 5749f8cb78cea11e1247fdcd6108fc632c38a3bc Mon Sep 17 00:00:00 2001
6ae9ed
Message-Id: <5749f8cb78cea11e1247fdcd6108fc632c38a3bc@dist-git>
6ae9ed
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
6ae9ed
Date: Thu, 21 Jul 2016 15:57:53 +0200
6ae9ed
Subject: [PATCH] Reserve existing USB addresses
6ae9ed
MIME-Version: 1.0
6ae9ed
Content-Type: text/plain; charset=UTF-8
6ae9ed
Content-Transfer-Encoding: 8bit
6ae9ed
6ae9ed
Check if they fit on the USB controllers the domain has,
6ae9ed
and error out if two devices try to use the same address.
6ae9ed
6ae9ed
(cherry picked from commit ddd31fd7dce3ffaf07d31502c57e1ca940f454fa)
6ae9ed
Signed-off-by: Ján Tomko <jtomko@redhat.com>
6ae9ed
6ae9ed
https://bugzilla.redhat.com/show_bug.cgi?id=1215968
6ae9ed
---
6ae9ed
 src/conf/domain_addr.c                             | 42 ++++++++++++++++++++++
6ae9ed
 src/conf/domain_addr.h                             |  4 +++
6ae9ed
 src/libvirt_private.syms                           |  1 +
6ae9ed
 src/qemu/qemu_domain.c                             |  1 +
6ae9ed
 src/qemu/qemu_domain.h                             |  1 +
6ae9ed
 src/qemu/qemu_domain_address.c                     | 38 +++++++++++++++++++-
6ae9ed
 .../qemuxml2argv-usb-hub-conflict.xml              | 22 ++++++++++++
6ae9ed
 tests/qemuxml2argvtest.c                           |  3 ++
6ae9ed
 8 files changed, 111 insertions(+), 1 deletion(-)
6ae9ed
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub-conflict.xml
6ae9ed
6ae9ed
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
6ae9ed
index ad20fef..bbac399 100644
6ae9ed
--- a/src/conf/domain_addr.c
6ae9ed
+++ b/src/conf/domain_addr.c
6ae9ed
@@ -1562,3 +1562,45 @@ virDomainUSBAddressSetAddControllers(virDomainUSBAddressSetPtr addrs,
6ae9ed
     }
6ae9ed
     return 0;
6ae9ed
 }
6ae9ed
+
6ae9ed
+
6ae9ed
+int
6ae9ed
+virDomainUSBAddressReserve(virDomainDeviceInfoPtr info,
6ae9ed
+                           void *data)
6ae9ed
+{
6ae9ed
+    virDomainUSBAddressSetPtr addrs = data;
6ae9ed
+    virDomainUSBAddressHubPtr targetHub = NULL;
6ae9ed
+    char *portStr = NULL;
6ae9ed
+    int ret = -1;
6ae9ed
+    int targetPort;
6ae9ed
+
6ae9ed
+    if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB)
6ae9ed
+        return 0;
6ae9ed
+
6ae9ed
+    if (!virDomainUSBAddressPortIsValid(info->addr.usb.port))
6ae9ed
+        return 0;
6ae9ed
+
6ae9ed
+    portStr = virDomainUSBAddressPortFormat(info->addr.usb.port);
6ae9ed
+    if (!portStr)
6ae9ed
+        goto cleanup;
6ae9ed
+    VIR_DEBUG("Reserving USB address bus=%u port=%s", info->addr.usb.bus, portStr);
6ae9ed
+
6ae9ed
+    if (!(targetHub = virDomainUSBAddressFindPort(addrs, info, &targetPort,
6ae9ed
+                                                  portStr)))
6ae9ed
+        goto cleanup;
6ae9ed
+
6ae9ed
+    if (virBitmapIsBitSet(targetHub->portmap, targetPort)) {
6ae9ed
+        virReportError(VIR_ERR_XML_ERROR,
6ae9ed
+                       _("Duplicate USB address bus %u port %s"),
6ae9ed
+                       info->addr.usb.bus, portStr);
6ae9ed
+        goto cleanup;
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    ignore_value(virBitmapSetBit(targetHub->portmap, targetPort));
6ae9ed
+
6ae9ed
+    ret = 0;
6ae9ed
+
6ae9ed
+ cleanup:
6ae9ed
+    VIR_FREE(portStr);
6ae9ed
+    return ret;
6ae9ed
+}
6ae9ed
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
6ae9ed
index 2bd4a0d..a24d216 100644
6ae9ed
--- a/src/conf/domain_addr.h
6ae9ed
+++ b/src/conf/domain_addr.h
6ae9ed
@@ -275,4 +275,8 @@ int virDomainUSBAddressSetAddControllers(virDomainUSBAddressSetPtr addrs,
6ae9ed
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
6ae9ed
 void virDomainUSBAddressSetFree(virDomainUSBAddressSetPtr addrs);
6ae9ed
 
6ae9ed
+int
6ae9ed
+virDomainUSBAddressReserve(virDomainDeviceInfoPtr info,
6ae9ed
+                           void *data)
6ae9ed
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
6ae9ed
 #endif /* __DOMAIN_ADDR_H__ */
6ae9ed
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
6ae9ed
index f0fed8e..f66ccf5 100644
6ae9ed
--- a/src/libvirt_private.syms
6ae9ed
+++ b/src/libvirt_private.syms
6ae9ed
@@ -110,6 +110,7 @@ virDomainPCIControllerModelToConnectType;
6ae9ed
 virDomainUSBAddressPortFormat;
6ae9ed
 virDomainUSBAddressPortFormatBuf;
6ae9ed
 virDomainUSBAddressPortIsValid;
6ae9ed
+virDomainUSBAddressReserve;
6ae9ed
 virDomainUSBAddressSetAddControllers;
6ae9ed
 virDomainUSBAddressSetCreate;
6ae9ed
 virDomainUSBAddressSetFree;
6ae9ed
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
6ae9ed
index 5b4d7a3..8b0f847 100644
6ae9ed
--- a/src/qemu/qemu_domain.c
6ae9ed
+++ b/src/qemu/qemu_domain.c
6ae9ed
@@ -1244,6 +1244,7 @@ qemuDomainObjPrivateFree(void *data)
6ae9ed
     virDomainPCIAddressSetFree(priv->pciaddrs);
6ae9ed
     virDomainCCWAddressSetFree(priv->ccwaddrs);
6ae9ed
     virDomainVirtioSerialAddrSetFree(priv->vioserialaddrs);
6ae9ed
+    virDomainUSBAddressSetFree(priv->usbaddrs);
6ae9ed
     virDomainChrSourceDefFree(priv->monConfig);
6ae9ed
     qemuDomainObjFreeJob(priv);
6ae9ed
     VIR_FREE(priv->vcpupids);
6ae9ed
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
6ae9ed
index c87dcc7..b71a28d 100644
6ae9ed
--- a/src/qemu/qemu_domain.h
6ae9ed
+++ b/src/qemu/qemu_domain.h
6ae9ed
@@ -190,6 +190,7 @@ struct _qemuDomainObjPrivate {
6ae9ed
     virDomainPCIAddressSetPtr pciaddrs;
6ae9ed
     virDomainCCWAddressSetPtr ccwaddrs;
6ae9ed
     virDomainVirtioSerialAddrSetPtr vioserialaddrs;
6ae9ed
+    virDomainUSBAddressSetPtr usbaddrs;
6ae9ed
 
6ae9ed
     virQEMUCapsPtr qemuCaps;
6ae9ed
     char *lockState;
6ae9ed
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
6ae9ed
index ee44d45..f66b2f0 100644
6ae9ed
--- a/src/qemu/qemu_domain_address.c
6ae9ed
+++ b/src/qemu/qemu_domain_address.c
6ae9ed
@@ -1622,11 +1622,44 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
6ae9ed
 }
6ae9ed
 
6ae9ed
 
6ae9ed
+static int
6ae9ed
+qemuDomainAssignUSBAddresses(virDomainDefPtr def,
6ae9ed
+                             virDomainObjPtr obj)
6ae9ed
+{
6ae9ed
+    int ret = -1;
6ae9ed
+    virDomainUSBAddressSetPtr addrs = NULL;
6ae9ed
+    qemuDomainObjPrivatePtr priv = NULL;
6ae9ed
+
6ae9ed
+    if (!(addrs = virDomainUSBAddressSetCreate()))
6ae9ed
+        goto cleanup;
6ae9ed
+
6ae9ed
+    if (virDomainUSBAddressSetAddControllers(addrs, def) < 0)
6ae9ed
+        goto cleanup;
6ae9ed
+
6ae9ed
+    if (virDomainUSBDeviceDefForeach(def, virDomainUSBAddressReserve, addrs,
6ae9ed
+                                     true) < 0)
6ae9ed
+        goto cleanup;
6ae9ed
+
6ae9ed
+    VIR_DEBUG("Existing USB addresses have been reserved");
6ae9ed
+
6ae9ed
+    if (obj && obj->privateData) {
6ae9ed
+        priv = obj->privateData;
6ae9ed
+        priv->usbaddrs = addrs;
6ae9ed
+        addrs = NULL;
6ae9ed
+    }
6ae9ed
+    ret = 0;
6ae9ed
+
6ae9ed
+ cleanup:
6ae9ed
+    virDomainUSBAddressSetFree(addrs);
6ae9ed
+    return ret;
6ae9ed
+}
6ae9ed
+
6ae9ed
+
6ae9ed
 int
6ae9ed
 qemuDomainAssignAddresses(virDomainDefPtr def,
6ae9ed
                           virQEMUCapsPtr qemuCaps,
6ae9ed
                           virDomainObjPtr obj,
6ae9ed
-                          bool newDomain ATTRIBUTE_UNUSED)
6ae9ed
+                          bool newDomain)
6ae9ed
 {
6ae9ed
     if (qemuDomainAssignVirtioSerialAddresses(def, obj) < 0)
6ae9ed
         return -1;
6ae9ed
@@ -1642,6 +1675,9 @@ qemuDomainAssignAddresses(virDomainDefPtr def,
6ae9ed
     if (qemuDomainAssignPCIAddresses(def, qemuCaps, obj) < 0)
6ae9ed
         return -1;
6ae9ed
 
6ae9ed
+    if (newDomain && qemuDomainAssignUSBAddresses(def, obj) < 0)
6ae9ed
+        return -1;
6ae9ed
+
6ae9ed
     return 0;
6ae9ed
 }
6ae9ed
 
6ae9ed
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-conflict.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-conflict.xml
6ae9ed
new file mode 100644
6ae9ed
index 0000000..9a48ba0
6ae9ed
--- /dev/null
6ae9ed
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-conflict.xml
6ae9ed
@@ -0,0 +1,22 @@
6ae9ed
+<domain type='qemu'>
6ae9ed
+  <name>QEMUGuest1</name>
6ae9ed
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
6ae9ed
+  <memory unit='KiB'>219136</memory>
6ae9ed
+  <currentMemory unit='KiB'>219136</currentMemory>
6ae9ed
+  <vcpu placement='static'>1</vcpu>
6ae9ed
+  <os>
6ae9ed
+    <type arch='i686' machine='pc'>hvm</type>
6ae9ed
+    <boot dev='hd'/>
6ae9ed
+  </os>
6ae9ed
+  <devices>
6ae9ed
+    <emulator>/usr/bin/qemu</emulator>
6ae9ed
+    <controller type='usb' index='0'/>
6ae9ed
+    <memballoon model='virtio'/>
6ae9ed
+    <hub type='usb'>
6ae9ed
+      <address type='usb' bus='0' port='1'/>
6ae9ed
+    </hub>
6ae9ed
+    <input type='mouse' bus='usb'>
6ae9ed
+      <address type='usb' bus='0' port='1'/>
6ae9ed
+    </input>
6ae9ed
+  </devices>
6ae9ed
+</domain>
6ae9ed
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
6ae9ed
index 4389e24..9c18989 100644
6ae9ed
--- a/tests/qemuxml2argvtest.c
6ae9ed
+++ b/tests/qemuxml2argvtest.c
6ae9ed
@@ -1159,6 +1159,9 @@ mymain(void)
6ae9ed
     DO_TEST("usb-hub",
6ae9ed
             QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
6ae9ed
             QEMU_CAPS_NODEFCONFIG);
6ae9ed
+    DO_TEST_PARSE_ERROR("usb-hub-conflict",
6ae9ed
+            QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
6ae9ed
+            QEMU_CAPS_NODEFCONFIG);
6ae9ed
     DO_TEST("usb-port-missing",
6ae9ed
             QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
6ae9ed
             QEMU_CAPS_NODEFCONFIG);
6ae9ed
-- 
6ae9ed
2.9.2
6ae9ed