mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +00:00
move virHostdevPrepareHostUSBDevices to virhostdev.c
This commit is contained in:
parent
7972571142
commit
1c310c609c
@ -1300,6 +1300,7 @@ virHookPresent;
|
||||
#util/virhostdev.h
|
||||
virHostdevManagerGetDefault;
|
||||
virHostdevPreparePCIDevices;
|
||||
virHostdevPrepareUSBDevices;
|
||||
virHostdevReAttachPCIDevices;
|
||||
virHostdevUpdateActivePciHostdevs;
|
||||
virHostdevUpdateActiveScsiHostdevs;
|
||||
|
@ -232,223 +232,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virHostdevMarkUsbHostdevs(virHostdevManagerPtr mgr,
|
||||
const char *drv_name,
|
||||
const char *name,
|
||||
virUSBDeviceListPtr list)
|
||||
{
|
||||
size_t i, j;
|
||||
unsigned int count;
|
||||
virUSBDevicePtr tmp;
|
||||
|
||||
virObjectLock(mgr->activeUsbHostdevs);
|
||||
count = virUSBDeviceListCount(list);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
|
||||
if ((tmp = virUSBDeviceListFind(mgr->activeUsbHostdevs, usb))) {
|
||||
const char *other_drvname;
|
||||
const char *other_domname;
|
||||
|
||||
virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname);
|
||||
if (other_drvname && other_domname)
|
||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||
_("USB device %s is in use by "
|
||||
"driver %s, domain %s"),
|
||||
virUSBDeviceGetName(tmp),
|
||||
other_drvname, other_domname);
|
||||
else
|
||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||
_("USB device %s is already in use"),
|
||||
virUSBDeviceGetName(tmp));
|
||||
goto error;
|
||||
}
|
||||
|
||||
virUSBDeviceSetUsedBy(usb, drv_name, name);
|
||||
VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
|
||||
virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
|
||||
/*
|
||||
* The caller is responsible to steal these usb devices
|
||||
* from the virUSBDeviceList that passed in on success,
|
||||
* perform rollback on failure.
|
||||
*/
|
||||
if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
virObjectUnlock(mgr->activeUsbHostdevs);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
for (j = 0; j < i; j++) {
|
||||
tmp = virUSBDeviceListGet(list, i);
|
||||
virUSBDeviceListSteal(mgr->activeUsbHostdevs, tmp);
|
||||
}
|
||||
virObjectUnlock(mgr->activeUsbHostdevs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
|
||||
bool mandatory,
|
||||
virUSBDevicePtr *usb)
|
||||
{
|
||||
unsigned vendor = hostdev->source.subsys.u.usb.vendor;
|
||||
unsigned product = hostdev->source.subsys.u.usb.product;
|
||||
unsigned bus = hostdev->source.subsys.u.usb.bus;
|
||||
unsigned device = hostdev->source.subsys.u.usb.device;
|
||||
bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
|
||||
int rc;
|
||||
|
||||
*usb = NULL;
|
||||
|
||||
if (vendor && bus) {
|
||||
rc = virUSBDeviceFind(vendor, product, bus, device,
|
||||
NULL,
|
||||
autoAddress ? false : mandatory,
|
||||
usb);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
} else if (!autoAddress) {
|
||||
goto out;
|
||||
} else {
|
||||
VIR_INFO("USB device %x:%x could not be found at previous"
|
||||
" address (bus:%u device:%u)",
|
||||
vendor, product, bus, device);
|
||||
}
|
||||
}
|
||||
|
||||
/* When vendor is specified, its USB address is either unspecified or the
|
||||
* device could not be found at the USB device where it had been
|
||||
* automatically found before.
|
||||
*/
|
||||
if (vendor) {
|
||||
virUSBDeviceListPtr devs;
|
||||
|
||||
rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
if (rc == 1) {
|
||||
*usb = virUSBDeviceListGet(devs, 0);
|
||||
virUSBDeviceListSteal(devs, *usb);
|
||||
}
|
||||
virObjectUnref(devs);
|
||||
|
||||
if (rc == 0) {
|
||||
goto out;
|
||||
} else if (rc > 1) {
|
||||
if (autoAddress) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("Multiple USB devices for %x:%x were found,"
|
||||
" but none of them is at bus:%u device:%u"),
|
||||
vendor, product, bus, device);
|
||||
} else {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("Multiple USB devices for %x:%x, "
|
||||
"use <address> to specify one"),
|
||||
vendor, product);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
hostdev->source.subsys.u.usb.bus = virUSBDeviceGetBus(*usb);
|
||||
hostdev->source.subsys.u.usb.device = virUSBDeviceGetDevno(*usb);
|
||||
hostdev->source.subsys.u.usb.autoAddress = true;
|
||||
|
||||
if (autoAddress) {
|
||||
VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
|
||||
" from bus:%u device:%u)",
|
||||
vendor, product,
|
||||
hostdev->source.subsys.u.usb.bus,
|
||||
hostdev->source.subsys.u.usb.device,
|
||||
bus, device);
|
||||
}
|
||||
} else if (!vendor && bus) {
|
||||
if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!*usb)
|
||||
hostdev->missing = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr,
|
||||
const char *drv_name,
|
||||
const char *name,
|
||||
virDomainHostdevDefPtr *hostdevs,
|
||||
int nhostdevs,
|
||||
unsigned int flags)
|
||||
{
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
virUSBDeviceListPtr list;
|
||||
virUSBDevicePtr tmp;
|
||||
bool coldBoot = !!(flags & VIR_HOSTDEV_COLD_BOOT);
|
||||
|
||||
/* To prevent situation where USB device is assigned to two domains
|
||||
* we need to keep a list of currently assigned USB devices.
|
||||
* This is done in several loops which cannot be joined into one big
|
||||
* loop. See virHostdevPreparePCIDevices()
|
||||
*/
|
||||
if (!(list = virUSBDeviceListNew()))
|
||||
goto cleanup;
|
||||
|
||||
/* Loop 1: build temporary list
|
||||
*/
|
||||
for (i = 0; i < nhostdevs; i++) {
|
||||
virDomainHostdevDefPtr hostdev = hostdevs[i];
|
||||
bool required = true;
|
||||
virUSBDevicePtr usb;
|
||||
|
||||
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||
continue;
|
||||
if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
|
||||
continue;
|
||||
|
||||
if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
|
||||
(hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
|
||||
!coldBoot))
|
||||
required = false;
|
||||
|
||||
if (virHostdevFindUSBDevice(hostdev, required, &usb) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (usb && virUSBDeviceListAdd(list, usb) < 0) {
|
||||
virUSBDeviceFree(usb);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark devices in temporary list as used by @name
|
||||
* and add them do driver list. However, if something goes
|
||||
* wrong, perform rollback.
|
||||
*/
|
||||
if (virHostdevMarkUsbHostdevs(hostdev_mgr, drv_name, name, list) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Loop 2: Temporary list was successfully merged with
|
||||
* driver list, so steal all items to avoid freeing them
|
||||
* in cleanup label.
|
||||
*/
|
||||
while (virUSBDeviceListCount(list) > 0) {
|
||||
tmp = virUSBDeviceListGet(list, 0);
|
||||
virUSBDeviceListSteal(list, tmp);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virObjectUnref(list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
|
||||
const char *name,
|
||||
|
@ -924,3 +924,219 @@ cleanup:
|
||||
virObjectUnlock(mgr->activeScsiHostdevs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
virHostdevMarkUsbHostdevs(virHostdevManagerPtr mgr,
|
||||
const char *drv_name,
|
||||
const char *name,
|
||||
virUSBDeviceListPtr list)
|
||||
{
|
||||
size_t i, j;
|
||||
unsigned int count;
|
||||
virUSBDevicePtr tmp;
|
||||
|
||||
virObjectLock(mgr->activeUsbHostdevs);
|
||||
count = virUSBDeviceListCount(list);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
|
||||
if ((tmp = virUSBDeviceListFind(mgr->activeUsbHostdevs, usb))) {
|
||||
const char *other_drvname;
|
||||
const char *other_domname;
|
||||
|
||||
virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname);
|
||||
if (other_drvname && other_domname)
|
||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||
_("USB device %s is in use by "
|
||||
"driver %s, domain %s"),
|
||||
virUSBDeviceGetName(tmp),
|
||||
other_drvname, other_domname);
|
||||
else
|
||||
virReportError(VIR_ERR_OPERATION_INVALID,
|
||||
_("USB device %s is already in use"),
|
||||
virUSBDeviceGetName(tmp));
|
||||
goto error;
|
||||
}
|
||||
|
||||
virUSBDeviceSetUsedBy(usb, drv_name, name);
|
||||
VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
|
||||
virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
|
||||
/*
|
||||
* The caller is responsible to steal these usb devices
|
||||
* from the virUSBDeviceList that passed in on success,
|
||||
* perform rollback on failure.
|
||||
*/
|
||||
if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
virObjectUnlock(mgr->activeUsbHostdevs);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
for (j = 0; j < i; j++) {
|
||||
tmp = virUSBDeviceListGet(list, i);
|
||||
virUSBDeviceListSteal(mgr->activeUsbHostdevs, tmp);
|
||||
}
|
||||
virObjectUnlock(mgr->activeUsbHostdevs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
|
||||
bool mandatory,
|
||||
virUSBDevicePtr *usb)
|
||||
{
|
||||
unsigned vendor = hostdev->source.subsys.u.usb.vendor;
|
||||
unsigned product = hostdev->source.subsys.u.usb.product;
|
||||
unsigned bus = hostdev->source.subsys.u.usb.bus;
|
||||
unsigned device = hostdev->source.subsys.u.usb.device;
|
||||
bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
|
||||
int rc;
|
||||
|
||||
*usb = NULL;
|
||||
|
||||
if (vendor && bus) {
|
||||
rc = virUSBDeviceFind(vendor, product, bus, device,
|
||||
NULL,
|
||||
autoAddress ? false : mandatory,
|
||||
usb);
|
||||
if (rc < 0) {
|
||||
return -1;
|
||||
} else if (!autoAddress) {
|
||||
goto out;
|
||||
} else {
|
||||
VIR_INFO("USB device %x:%x could not be found at previous"
|
||||
" address (bus:%u device:%u)",
|
||||
vendor, product, bus, device);
|
||||
}
|
||||
}
|
||||
|
||||
/* When vendor is specified, its USB address is either unspecified or the
|
||||
* device could not be found at the USB device where it had been
|
||||
* automatically found before.
|
||||
*/
|
||||
if (vendor) {
|
||||
virUSBDeviceListPtr devs;
|
||||
|
||||
rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
|
||||
if (rc == 1) {
|
||||
*usb = virUSBDeviceListGet(devs, 0);
|
||||
virUSBDeviceListSteal(devs, *usb);
|
||||
}
|
||||
virObjectUnref(devs);
|
||||
|
||||
if (rc == 0) {
|
||||
goto out;
|
||||
} else if (rc > 1) {
|
||||
if (autoAddress) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("Multiple USB devices for %x:%x were found,"
|
||||
" but none of them is at bus:%u device:%u"),
|
||||
vendor, product, bus, device);
|
||||
} else {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("Multiple USB devices for %x:%x, "
|
||||
"use <address> to specify one"),
|
||||
vendor, product);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
hostdev->source.subsys.u.usb.bus = virUSBDeviceGetBus(*usb);
|
||||
hostdev->source.subsys.u.usb.device = virUSBDeviceGetDevno(*usb);
|
||||
hostdev->source.subsys.u.usb.autoAddress = true;
|
||||
|
||||
if (autoAddress) {
|
||||
VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
|
||||
" from bus:%u device:%u)",
|
||||
vendor, product,
|
||||
hostdev->source.subsys.u.usb.bus,
|
||||
hostdev->source.subsys.u.usb.device,
|
||||
bus, device);
|
||||
}
|
||||
} else if (!vendor && bus) {
|
||||
if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!*usb)
|
||||
hostdev->missing = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr,
|
||||
const char *drv_name,
|
||||
const char *name,
|
||||
virDomainHostdevDefPtr *hostdevs,
|
||||
int nhostdevs,
|
||||
unsigned int flags)
|
||||
{
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
virUSBDeviceListPtr list;
|
||||
virUSBDevicePtr tmp;
|
||||
bool coldBoot = !!(flags & VIR_HOSTDEV_COLD_BOOT);
|
||||
|
||||
/* To prevent situation where USB device is assigned to two domains
|
||||
* we need to keep a list of currently assigned USB devices.
|
||||
* This is done in several loops which cannot be joined into one big
|
||||
* loop. See virHostdevPreparePCIDevices()
|
||||
*/
|
||||
if (!(list = virUSBDeviceListNew()))
|
||||
goto cleanup;
|
||||
|
||||
/* Loop 1: build temporary list
|
||||
*/
|
||||
for (i = 0; i < nhostdevs; i++) {
|
||||
virDomainHostdevDefPtr hostdev = hostdevs[i];
|
||||
bool required = true;
|
||||
virUSBDevicePtr usb;
|
||||
|
||||
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||
continue;
|
||||
if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
|
||||
continue;
|
||||
|
||||
if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
|
||||
(hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
|
||||
!coldBoot))
|
||||
required = false;
|
||||
|
||||
if (virHostdevFindUSBDevice(hostdev, required, &usb) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (usb && virUSBDeviceListAdd(list, usb) < 0) {
|
||||
virUSBDeviceFree(usb);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark devices in temporary list as used by @name
|
||||
* and add them do driver list. However, if something goes
|
||||
* wrong, perform rollback.
|
||||
*/
|
||||
if (virHostdevMarkUsbHostdevs(hostdev_mgr, drv_name, name, list) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Loop 2: Temporary list was successfully merged with
|
||||
* driver list, so steal all items to avoid freeing them
|
||||
* in cleanup label.
|
||||
*/
|
||||
while (virUSBDeviceListCount(list) > 0) {
|
||||
tmp = virUSBDeviceListGet(list, 0);
|
||||
virUSBDeviceListSteal(list, tmp);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virObjectUnref(list);
|
||||
return ret;
|
||||
}
|
||||
|
@ -58,6 +58,13 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
|
||||
virDomainHostdevDefPtr *hostdevs,
|
||||
int nhostdevs,
|
||||
unsigned int flags);
|
||||
int
|
||||
virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr,
|
||||
const char *drv_name,
|
||||
const char *name,
|
||||
virDomainHostdevDefPtr *hostdevs,
|
||||
int nhostdevs,
|
||||
unsigned int flags);
|
||||
void
|
||||
virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
|
||||
const char *drv_name,
|
||||
|
Loading…
Reference in New Issue
Block a user