6ae9ed
From 6c058183513069522ab1b622f2e08eb1de440def Mon Sep 17 00:00:00 2001
6ae9ed
Message-Id: <6c058183513069522ab1b622f2e08eb1de440def@dist-git>
6ae9ed
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
6ae9ed
Date: Thu, 21 Jul 2016 15:57:57 +0200
6ae9ed
Subject: [PATCH] Auto-add one hub if there are too many USB devices
6ae9ed
MIME-Version: 1.0
6ae9ed
Content-Type: text/plain; charset=UTF-8
6ae9ed
Content-Transfer-Encoding: 8bit
6ae9ed
6ae9ed
When parsing a command line with USB devices that have
6ae9ed
no address specified, QEMU automatically adds a USB hub
6ae9ed
if the device would fill up all the available USB ports.
6ae9ed
6ae9ed
To help most of the users, add one hub if there are more
6ae9ed
USB devices than available ports. For wilder configurations,
6ae9ed
expect the user to provide us with more hubs and/or controllers.
6ae9ed
6ae9ed
(cherry picked from commit 815d98ac0bb8a4b48a412e026cb6465309e4043c)
6ae9ed
Signed-off-by: Ján Tomko <jtomko@redhat.com>
6ae9ed
6ae9ed
https://bugzilla.redhat.com/show_bug.cgi?id=1215968
6ae9ed
6ae9ed
Conflicts:
6ae9ed
  downstream does not assume QEMU_CAPS_SMP_TOPOLOGY in tests
6ae9ed
---
6ae9ed
 src/conf/domain_addr.c                             | 20 +++++++++
6ae9ed
 src/conf/domain_addr.h                             |  2 +
6ae9ed
 src/libvirt_private.syms                           |  1 +
6ae9ed
 src/qemu/qemu_domain_address.c                     | 48 ++++++++++++++++++++++
6ae9ed
 .../qemuxml2argv-usb-hub-autoadd.args              | 28 +++++++++++++
6ae9ed
 .../qemuxml2argv-usb-hub-autoadd.xml               | 23 +++++++++++
6ae9ed
 tests/qemuxml2argvtest.c                           |  3 ++
6ae9ed
 7 files changed, 125 insertions(+)
6ae9ed
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.args
6ae9ed
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.xml
6ae9ed
6ae9ed
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
6ae9ed
index 365ee40..c3469ee 100644
6ae9ed
--- a/src/conf/domain_addr.c
6ae9ed
+++ b/src/conf/domain_addr.c
6ae9ed
@@ -1604,6 +1604,26 @@ virDomainUSBAddressFindFreePort(virDomainUSBAddressHubPtr hub,
6ae9ed
 }
6ae9ed
 
6ae9ed
 
6ae9ed
+size_t
6ae9ed
+virDomainUSBAddressCountAllPorts(virDomainDefPtr def)
6ae9ed
+{
6ae9ed
+    size_t i, ret = 0;
6ae9ed
+
6ae9ed
+    for (i = 0; i < def->ncontrollers; i++) {
6ae9ed
+        virDomainControllerDefPtr cont = def->controllers[i];
6ae9ed
+        if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
6ae9ed
+            ret += virDomainUSBAddressControllerModelToPorts(cont);
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    for (i = 0; i < def->nhubs; i++) {
6ae9ed
+        virDomainHubDefPtr hub = def->hubs[i];
6ae9ed
+        if (hub->type == VIR_DOMAIN_HUB_TYPE_USB)
6ae9ed
+            ret += VIR_DOMAIN_USB_HUB_PORTS;
6ae9ed
+    }
6ae9ed
+    return ret;
6ae9ed
+}
6ae9ed
+
6ae9ed
+
6ae9ed
 /* Try to find a free port on bus @bus.
6ae9ed
  *
6ae9ed
  * Returns  0 on success
6ae9ed
diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
6ae9ed
index cc36aed..ce94981 100644
6ae9ed
--- a/src/conf/domain_addr.h
6ae9ed
+++ b/src/conf/domain_addr.h
6ae9ed
@@ -277,6 +277,8 @@ int
6ae9ed
 virDomainUSBAddressSetAddHub(virDomainUSBAddressSetPtr addrs,
6ae9ed
                              virDomainHubDefPtr hub)
6ae9ed
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
6ae9ed
+size_t
6ae9ed
+virDomainUSBAddressCountAllPorts(virDomainDefPtr def);
6ae9ed
 void virDomainUSBAddressSetFree(virDomainUSBAddressSetPtr addrs);
6ae9ed
 
6ae9ed
 int
6ae9ed
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
6ae9ed
index e23bfe3..8cd1ba3 100644
6ae9ed
--- a/src/libvirt_private.syms
6ae9ed
+++ b/src/libvirt_private.syms
6ae9ed
@@ -108,6 +108,7 @@ virDomainPCIAddressSlotInUse;
6ae9ed
 virDomainPCIAddressValidate;
6ae9ed
 virDomainPCIControllerModelToConnectType;
6ae9ed
 virDomainUSBAddressAssign;
6ae9ed
+virDomainUSBAddressCountAllPorts;
6ae9ed
 virDomainUSBAddressEnsure;
6ae9ed
 virDomainUSBAddressPortFormat;
6ae9ed
 virDomainUSBAddressPortFormatBuf;
6ae9ed
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
6ae9ed
index 7499026..787b357 100644
6ae9ed
--- a/src/qemu/qemu_domain_address.c
6ae9ed
+++ b/src/qemu/qemu_domain_address.c
6ae9ed
@@ -1680,6 +1680,51 @@ qemuDomainAssignUSBPorts(virDomainUSBAddressSetPtr addrs,
6ae9ed
 
6ae9ed
 
6ae9ed
 static int
6ae9ed
+qemuDomainAssignUSBPortsCounter(virDomainDeviceInfoPtr info ATTRIBUTE_UNUSED,
6ae9ed
+                                void *opaque)
6ae9ed
+{
6ae9ed
+    struct qemuAssignUSBIteratorInfo *data = opaque;
6ae9ed
+
6ae9ed
+    data->count++;
6ae9ed
+    return 0;
6ae9ed
+}
6ae9ed
+
6ae9ed
+
6ae9ed
+static int
6ae9ed
+qemuDomainUSBAddressAddHubs(virDomainDefPtr def)
6ae9ed
+{
6ae9ed
+    struct qemuAssignUSBIteratorInfo data = { .count = 0 };
6ae9ed
+    virDomainHubDefPtr hub = NULL;
6ae9ed
+    size_t available_ports;
6ae9ed
+    int ret = -1;
6ae9ed
+
6ae9ed
+    available_ports = virDomainUSBAddressCountAllPorts(def);
6ae9ed
+    ignore_value(virDomainUSBDeviceDefForeach(def,
6ae9ed
+                                              qemuDomainAssignUSBPortsCounter,
6ae9ed
+                                              &data,
6ae9ed
+                                              false));
6ae9ed
+    VIR_DEBUG("Found %zu USB devices and %zu provided USB ports",
6ae9ed
+              data.count, available_ports);
6ae9ed
+
6ae9ed
+    /* Add one hub if there are more devices than ports
6ae9ed
+     * otherwise it's up to the user to specify more hubs/controllers */
6ae9ed
+    if (data.count > available_ports) {
6ae9ed
+        if (VIR_ALLOC(hub) < 0)
6ae9ed
+            return -1;
6ae9ed
+        hub->type = VIR_DOMAIN_HUB_TYPE_USB;
6ae9ed
+
6ae9ed
+        if (VIR_APPEND_ELEMENT(def->hubs, def->nhubs, hub) < 0)
6ae9ed
+            goto cleanup;
6ae9ed
+    }
6ae9ed
+
6ae9ed
+    ret = 0;
6ae9ed
+ cleanup:
6ae9ed
+    VIR_FREE(hub);
6ae9ed
+    return ret;
6ae9ed
+}
6ae9ed
+
6ae9ed
+
6ae9ed
+static int
6ae9ed
 qemuDomainAssignUSBAddresses(virDomainDefPtr def,
6ae9ed
                              virDomainObjPtr obj)
6ae9ed
 {
6ae9ed
@@ -1690,6 +1735,9 @@ qemuDomainAssignUSBAddresses(virDomainDefPtr def,
6ae9ed
     if (!(addrs = virDomainUSBAddressSetCreate()))
6ae9ed
         goto cleanup;
6ae9ed
 
6ae9ed
+    if (qemuDomainUSBAddressAddHubs(def) < 0)
6ae9ed
+        goto cleanup;
6ae9ed
+
6ae9ed
     if (virDomainUSBAddressSetAddControllers(addrs, def) < 0)
6ae9ed
         goto cleanup;
6ae9ed
 
6ae9ed
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.args
6ae9ed
new file mode 100644
6ae9ed
index 0000000..12c9691
6ae9ed
--- /dev/null
6ae9ed
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.args
6ae9ed
@@ -0,0 +1,28 @@
6ae9ed
+LC_ALL=C \
6ae9ed
+PATH=/bin \
6ae9ed
+HOME=/home/test \
6ae9ed
+USER=test \
6ae9ed
+LOGNAME=test \
6ae9ed
+QEMU_AUDIO_DRV=none \
6ae9ed
+/usr/bin/qemu \
6ae9ed
+-name QEMUGuest1 \
6ae9ed
+-S \
6ae9ed
+-M pc \
6ae9ed
+-m 214 \
6ae9ed
+-smp 1 \
6ae9ed
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
6ae9ed
+-nographic \
6ae9ed
+-nodefconfig \
6ae9ed
+-nodefaults \
6ae9ed
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
6ae9ed
+server,nowait \
6ae9ed
+-mon chardev=charmonitor,id=monitor,mode=readline \
6ae9ed
+-no-acpi \
6ae9ed
+-boot c \
6ae9ed
+-usb \
6ae9ed
+-device usb-hub,id=hub0,bus=usb.0,port=1 \
6ae9ed
+-device usb-mouse,id=input0,bus=usb.0,port=2 \
6ae9ed
+-device usb-mouse,id=input1,bus=usb.0,port=1.1 \
6ae9ed
+-device usb-mouse,id=input2,bus=usb.0,port=1.2 \
6ae9ed
+-device usb-tablet,id=input3,bus=usb.0,port=1.3 \
6ae9ed
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
6ae9ed
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.xml
6ae9ed
new file mode 100644
6ae9ed
index 0000000..43e0f1f
6ae9ed
--- /dev/null
6ae9ed
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-hub-autoadd.xml
6ae9ed
@@ -0,0 +1,23 @@
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
+    <input type='mouse' bus='usb'>
6ae9ed
+    </input>
6ae9ed
+    <input type='mouse' bus='usb'>
6ae9ed
+    </input>
6ae9ed
+    <input type='mouse' bus='usb'>
6ae9ed
+    </input>
6ae9ed
+    <input type='tablet' bus='usb'/>
6ae9ed
+  </devices>
6ae9ed
+</domain>
6ae9ed
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
6ae9ed
index e434470..51bab61 100644
6ae9ed
--- a/tests/qemuxml2argvtest.c
6ae9ed
+++ b/tests/qemuxml2argvtest.c
6ae9ed
@@ -1163,6 +1163,9 @@ mymain(void)
6ae9ed
     DO_TEST("usb-hub",
6ae9ed
             QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
6ae9ed
             QEMU_CAPS_NODEFCONFIG);
6ae9ed
+    DO_TEST("usb-hub-autoadd",
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
-- 
6ae9ed
2.9.2
6ae9ed