Reserve existing USB addresses

Check if they fit on the USB controllers the domain has,
and error out if two devices try to use the same address.
This commit is contained in:
Ján Tomko 2015-08-12 16:52:17 +02:00
parent 2f0813515e
commit ddd31fd7dc
8 changed files with 111 additions and 1 deletions

View File

@ -1562,3 +1562,45 @@ virDomainUSBAddressSetAddControllers(virDomainUSBAddressSetPtr addrs,
}
return 0;
}
int
virDomainUSBAddressReserve(virDomainDeviceInfoPtr info,
void *data)
{
virDomainUSBAddressSetPtr addrs = data;
virDomainUSBAddressHubPtr targetHub = NULL;
char *portStr = NULL;
int ret = -1;
int targetPort;
if (info->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB)
return 0;
if (!virDomainUSBAddressPortIsValid(info->addr.usb.port))
return 0;
portStr = virDomainUSBAddressPortFormat(info->addr.usb.port);
if (!portStr)
goto cleanup;
VIR_DEBUG("Reserving USB address bus=%u port=%s", info->addr.usb.bus, portStr);
if (!(targetHub = virDomainUSBAddressFindPort(addrs, info, &targetPort,
portStr)))
goto cleanup;
if (virBitmapIsBitSet(targetHub->portmap, targetPort)) {
virReportError(VIR_ERR_XML_ERROR,
_("Duplicate USB address bus %u port %s"),
info->addr.usb.bus, portStr);
goto cleanup;
}
ignore_value(virBitmapSetBit(targetHub->portmap, targetPort));
ret = 0;
cleanup:
VIR_FREE(portStr);
return ret;
}

View File

@ -275,4 +275,8 @@ int virDomainUSBAddressSetAddControllers(virDomainUSBAddressSetPtr addrs,
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
void virDomainUSBAddressSetFree(virDomainUSBAddressSetPtr addrs);
int
virDomainUSBAddressReserve(virDomainDeviceInfoPtr info,
void *data)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
#endif /* __DOMAIN_ADDR_H__ */

View File

@ -110,6 +110,7 @@ virDomainPCIControllerModelToConnectType;
virDomainUSBAddressPortFormat;
virDomainUSBAddressPortFormatBuf;
virDomainUSBAddressPortIsValid;
virDomainUSBAddressReserve;
virDomainUSBAddressSetAddControllers;
virDomainUSBAddressSetCreate;
virDomainUSBAddressSetFree;

View File

@ -1330,6 +1330,7 @@ qemuDomainObjPrivateFree(void *data)
virDomainPCIAddressSetFree(priv->pciaddrs);
virDomainCCWAddressSetFree(priv->ccwaddrs);
virDomainVirtioSerialAddrSetFree(priv->vioserialaddrs);
virDomainUSBAddressSetFree(priv->usbaddrs);
virDomainChrSourceDefFree(priv->monConfig);
qemuDomainObjFreeJob(priv);
VIR_FREE(priv->lockState);

View File

@ -187,6 +187,7 @@ struct _qemuDomainObjPrivate {
virDomainPCIAddressSetPtr pciaddrs;
virDomainCCWAddressSetPtr ccwaddrs;
virDomainVirtioSerialAddrSetPtr vioserialaddrs;
virDomainUSBAddressSetPtr usbaddrs;
virQEMUCapsPtr qemuCaps;
char *lockState;

View File

@ -1622,11 +1622,44 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
}
static int
qemuDomainAssignUSBAddresses(virDomainDefPtr def,
virDomainObjPtr obj)
{
int ret = -1;
virDomainUSBAddressSetPtr addrs = NULL;
qemuDomainObjPrivatePtr priv = NULL;
if (!(addrs = virDomainUSBAddressSetCreate()))
goto cleanup;
if (virDomainUSBAddressSetAddControllers(addrs, def) < 0)
goto cleanup;
if (virDomainUSBDeviceDefForeach(def, virDomainUSBAddressReserve, addrs,
true) < 0)
goto cleanup;
VIR_DEBUG("Existing USB addresses have been reserved");
if (obj && obj->privateData) {
priv = obj->privateData;
priv->usbaddrs = addrs;
addrs = NULL;
}
ret = 0;
cleanup:
virDomainUSBAddressSetFree(addrs);
return ret;
}
int
qemuDomainAssignAddresses(virDomainDefPtr def,
virQEMUCapsPtr qemuCaps,
virDomainObjPtr obj,
bool newDomain ATTRIBUTE_UNUSED)
bool newDomain)
{
if (qemuDomainAssignVirtioSerialAddresses(def, obj) < 0)
return -1;
@ -1642,6 +1675,9 @@ qemuDomainAssignAddresses(virDomainDefPtr def,
if (qemuDomainAssignPCIAddresses(def, qemuCaps, obj) < 0)
return -1;
if (newDomain && qemuDomainAssignUSBAddresses(def, obj) < 0)
return -1;
return 0;
}

View File

@ -0,0 +1,22 @@
<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'/>
<hub type='usb'>
<address type='usb' bus='0' port='1'/>
</hub>
<input type='mouse' bus='usb'>
<address type='usb' bus='0' port='1'/>
</input>
</devices>
</domain>

View File

@ -1180,6 +1180,9 @@ mymain(void)
DO_TEST("usb-hub",
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);
DO_TEST("usb-port-missing",
QEMU_CAPS_CHARDEV, QEMU_CAPS_USB_HUB,
QEMU_CAPS_NODEFCONFIG);