Auto-add one hub if there are too many USB devices

When parsing a command line with USB devices that have
no address specified, QEMU automatically adds a USB hub
if the device would fill up all the available USB ports.

To help most of the users, add one hub if there are more
USB devices than available ports. For wilder configurations,
expect the user to provide us with more hubs and/or controllers.
This commit is contained in:
Ján Tomko 2016-06-17 09:49:54 +02:00
parent f2a781ceb0
commit 815d98ac0b
7 changed files with 125 additions and 0 deletions

View File

@ -1604,6 +1604,26 @@ virDomainUSBAddressFindFreePort(virDomainUSBAddressHubPtr hub,
}
size_t
virDomainUSBAddressCountAllPorts(virDomainDefPtr def)
{
size_t i, ret = 0;
for (i = 0; i < def->ncontrollers; i++) {
virDomainControllerDefPtr cont = def->controllers[i];
if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB)
ret += virDomainUSBAddressControllerModelToPorts(cont);
}
for (i = 0; i < def->nhubs; i++) {
virDomainHubDefPtr hub = def->hubs[i];
if (hub->type == VIR_DOMAIN_HUB_TYPE_USB)
ret += VIR_DOMAIN_USB_HUB_PORTS;
}
return ret;
}
/* Try to find a free port on bus @bus.
*
* Returns 0 on success

View File

@ -277,6 +277,8 @@ int
virDomainUSBAddressSetAddHub(virDomainUSBAddressSetPtr addrs,
virDomainHubDefPtr hub)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
size_t
virDomainUSBAddressCountAllPorts(virDomainDefPtr def);
void virDomainUSBAddressSetFree(virDomainUSBAddressSetPtr addrs);
int

View File

@ -108,6 +108,7 @@ virDomainPCIAddressSlotInUse;
virDomainPCIAddressValidate;
virDomainPCIControllerModelToConnectType;
virDomainUSBAddressAssign;
virDomainUSBAddressCountAllPorts;
virDomainUSBAddressEnsure;
virDomainUSBAddressPortFormat;
virDomainUSBAddressPortFormatBuf;

View File

@ -1679,6 +1679,51 @@ qemuDomainAssignUSBPorts(virDomainUSBAddressSetPtr addrs,
}
static int
qemuDomainAssignUSBPortsCounter(virDomainDeviceInfoPtr info ATTRIBUTE_UNUSED,
void *opaque)
{
struct qemuAssignUSBIteratorInfo *data = opaque;
data->count++;
return 0;
}
static int
qemuDomainUSBAddressAddHubs(virDomainDefPtr def)
{
struct qemuAssignUSBIteratorInfo data = { .count = 0 };
virDomainHubDefPtr hub = NULL;
size_t available_ports;
int ret = -1;
available_ports = virDomainUSBAddressCountAllPorts(def);
ignore_value(virDomainUSBDeviceDefForeach(def,
qemuDomainAssignUSBPortsCounter,
&data,
false));
VIR_DEBUG("Found %zu USB devices and %zu provided USB ports",
data.count, available_ports);
/* Add one hub if there are more devices than ports
* otherwise it's up to the user to specify more hubs/controllers */
if (data.count > available_ports) {
if (VIR_ALLOC(hub) < 0)
return -1;
hub->type = VIR_DOMAIN_HUB_TYPE_USB;
if (VIR_APPEND_ELEMENT(def->hubs, def->nhubs, hub) < 0)
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(hub);
return ret;
}
static int
qemuDomainAssignUSBAddresses(virDomainDefPtr def,
virDomainObjPtr obj)
@ -1690,6 +1735,9 @@ qemuDomainAssignUSBAddresses(virDomainDefPtr def,
if (!(addrs = virDomainUSBAddressSetCreate()))
goto cleanup;
if (qemuDomainUSBAddressAddHubs(def) < 0)
goto cleanup;
if (virDomainUSBAddressSetAddControllers(addrs, def) < 0)
goto cleanup;

View File

@ -0,0 +1,28 @@
LC_ALL=C \
PATH=/bin \
HOME=/home/test \
USER=test \
LOGNAME=test \
QEMU_AUDIO_DRV=none \
/usr/bin/qemu \
-name QEMUGuest1 \
-S \
-M pc \
-m 214 \
-smp 1,sockets=1,cores=1,threads=1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-nographic \
-nodefconfig \
-nodefaults \
-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
server,nowait \
-mon chardev=charmonitor,id=monitor,mode=readline \
-no-acpi \
-boot c \
-usb \
-device usb-hub,id=hub0,bus=usb.0,port=1 \
-device usb-mouse,id=input0,bus=usb.0,port=2 \
-device usb-mouse,id=input1,bus=usb.0,port=1.1 \
-device usb-mouse,id=input2,bus=usb.0,port=1.2 \
-device usb-tablet,id=input3,bus=usb.0,port=1.3 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3

View File

@ -0,0 +1,23 @@
<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='i686' machine='pc'>hvm</type>
<boot dev='hd'/>
</os>
<devices>
<emulator>/usr/bin/qemu</emulator>
<controller type='usb' index='0'/>
<memballoon model='virtio'/>
<input type='mouse' bus='usb'>
</input>
<input type='mouse' bus='usb'>
</input>
<input type='mouse' bus='usb'>
</input>
<input type='tablet' bus='usb'/>
</devices>
</domain>

View File

@ -1184,6 +1184,9 @@ mymain(void)
DO_TEST("usb-hub",
QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
QEMU_CAPS_NODEFCONFIG);
DO_TEST("usb-hub-autoadd",
QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
QEMU_CAPS_NODEFCONFIG);
DO_TEST_PARSE_ERROR("usb-hub-conflict",
QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
QEMU_CAPS_NODEFCONFIG);