Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
---
src/libvirt_private.syms | 1 +
src/qemu/qemu_hostdev.c | 217 ----------------------------------------------
src/util/virhostdev.c | 216 +++++++++++++++++++++++++++++++++++++++++++++
src/util/virhostdev.h | 7 ++
4 files changed, 224 insertions(+), 217 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4417fdd..01f6c81 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1294,6 +1294,7 @@ virHookPresent;
#util/virhostdev.h
virHostdevManagerGetDefault;
virHostdevPreparePCIDevices;
+virHostdevPrepareUSBDevices;
virHostdevReAttachPCIDevices;
virHostdevUpdateActivePciHostdevs;
virHostdevUpdateActiveScsiHostdevs;
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
index a7e6c91..2934e65 100644
--- a/src/qemu/qemu_hostdev.c
+++ b/src/qemu/qemu_hostdev.c
@@ -245,223 +245,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 *dom_name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs,
- unsigned int flags)
-{
- size_t i;
- int ret = -1;
- virUSBDeviceListPtr list;
- virUSBDevicePtr tmp;
- bool coldBoot = !!(flags & VIR_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 qemuPrepareHostdevPCIDevices()
- */
- 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, dom_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 ATTRIBUTE_UNUSED,
virDomainDefPtr def,
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
index 5e7318f..896d451 100644
--- a/src/util/virhostdev.c
+++ b/src/util/virhostdev.c
@@ -902,3 +902,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 *dom_name,
+ virDomainHostdevDefPtr *hostdevs,
+ int nhostdevs,
+ unsigned int flags)
+{
+ size_t i;
+ int ret = -1;
+ virUSBDeviceListPtr list;
+ virUSBDevicePtr tmp;
+ bool coldBoot = !!(flags & VIR_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 qemuPrepareHostdevPCIDevices()
+ */
+ 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, dom_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;
+}
diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h
index 9773c6e..77e31fc 100644
--- a/src/util/virhostdev.h
+++ b/src/util/virhostdev.h
@@ -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 *dom_name,
+ virDomainHostdevDefPtr *hostdevs,
+ int nhostdevs,
+ unsigned int flags);
void
virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
const char *drv_name,
--
1.6.0.2