mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-22 22:13:18 +00:00
move virHostdevPrepareHostUSBDevices to virhostdev.c
This commit is contained in:
parent
7972571142
commit
1c310c609c
@ -1300,6 +1300,7 @@ virHookPresent;
|
|||||||
#util/virhostdev.h
|
#util/virhostdev.h
|
||||||
virHostdevManagerGetDefault;
|
virHostdevManagerGetDefault;
|
||||||
virHostdevPreparePCIDevices;
|
virHostdevPreparePCIDevices;
|
||||||
|
virHostdevPrepareUSBDevices;
|
||||||
virHostdevReAttachPCIDevices;
|
virHostdevReAttachPCIDevices;
|
||||||
virHostdevUpdateActivePciHostdevs;
|
virHostdevUpdateActivePciHostdevs;
|
||||||
virHostdevUpdateActiveScsiHostdevs;
|
virHostdevUpdateActiveScsiHostdevs;
|
||||||
|
@ -232,223 +232,6 @@ out:
|
|||||||
return ret;
|
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
|
int
|
||||||
qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
|
qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
@ -924,3 +924,219 @@ cleanup:
|
|||||||
virObjectUnlock(mgr->activeScsiHostdevs);
|
virObjectUnlock(mgr->activeScsiHostdevs);
|
||||||
return ret;
|
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,
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
int nhostdevs,
|
int nhostdevs,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
|
int
|
||||||
|
virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr,
|
||||||
|
const char *drv_name,
|
||||||
|
const char *name,
|
||||||
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
|
int nhostdevs,
|
||||||
|
unsigned int flags);
|
||||||
void
|
void
|
||||||
virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
|
virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
|
||||||
const char *drv_name,
|
const char *drv_name,
|
||||||
|
Loading…
Reference in New Issue
Block a user