[libvirt] [PATCH v13 00/49] write separate module for hostdev passthrough

These patches implements a separate module for hostdev passthrough so that it could be shared by different drivers and can maintain a global state of a host device. Patches 1~6 are to switch existing qemu and lxc driver to use common library lists, so that to maintain a global state of every host device. Patches 7~45 are to extract general code from qemu_hostdev.c piece by piece, make them reusable common APIs. Patches 46: unit test for the virhostdev common library Patches 47: add a hostdev backend type for xen Patches 48: add pci passthrough to libxl driver based on the common library Patches 49: change lxc to use common library APIs --- changes to v12: * split "add hostdev passthrough common library" patch into small patches for easier review. * fix v12 comments * rebase to libxl changes Chunyan Liu (49): add 'driver' info to used_by qemu: reuse hostdev interfaces to avoid duplicate qemu: remove functions now used internally only from qemu_hostdev.h add virhostdev files to maintain global state of host devices qemu: use general virhostdev lists instead of its own lxc: use general virhostdev lists instead of its own qemu_hostdev: move cfg->relaxedACS as a flag qemu_hostdev: move ColdBoot as a flag qemu_hostdev: move netconfig file location to virhostdev stateDir extract general code from qemuPrepareHostdevPCIDevices rename qemu*NetConfigRestore/Replace to virHostdevNetConfigRestore/Replace rename qemuGet*PciHostDeviceList to virHostdevGet*PciHostDeviceList pass driver name as a parameter to virHostdevPrepareHostdevPCIDevices extract general code from qemuDomainReAttachHostdevDevices pass driver name as a parameter to virHostdevReAttachPCIDevices rename qemuReAttachPciDevice to virHostdevReAttachPciDevice move virHostdevPrepare(ReAttach)PCIDevices to virhostdev.c extract general code from qemuUpdateActivePciHostdevs extract general code from qemuUpdateActiveUsbHostdevs extract general code from qemuUpdateActiveScsiHostdevs pass driver_name as parameter of virHostdevUpdate*Hostdevs functions move virHostdevUpdate* functions to virhostdev.c qemuPrepareUSBDevices: code adjustment for extracting general code extract general code from qemuPrepareHostUSBDevices rename qemu*USBDevices to virHostdev*USBDevices pass driver name to virHostdevPrepareUSBDevices move virHostdevPrepareHostUSBDevices to virhostdev.c extract general code from qemuPrepareHostSCSIDevices pass driver name as parameter to virHostdevPrepareSCSIDevices move virHostdevPrepareHostSCSIDevices to virhostdev.c extract general code from qemuDomainReAttachHostUsbDevices pass driver name as paramter to virHostdevReAttachUsbHostdevs move virHostdevDomainReAttachHostUsbDevices to virhostdev.c extract general code from qemuDomainReAttachHostScsiDevices pass driver name as parameter to virHostdevReAttachScciHostdevs move virHostdevReAttachHostScsiDevices to virhostdev.c extract general code of NodeDeviceDetach extract general code of NodeDeviceReAttach extract general code of NodeDeviceReset move virHostdevNodeDevice* to virhostdev.c improve parameter name to let it more meaningful rename some function names to keep consistency improve virHostdevUpdate* parameters to make it more widely used add 3 wrapper functions for prepare/reattach/update domain hostdevs add parameter checks to common interfaces add unit test for new virhostdev common library change lxc_hostdev.c to use virhostdev common library APIs add hostdev pci backend type for xen add pci passthrough to libxl driver .gitignore | 1 + docs/schemas/domaincommon.rng | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/conf/domain_conf.c | 3 +- src/conf/domain_conf.h | 1 + src/libvirt_private.syms | 19 + src/libxl/libxl_conf.c | 63 ++ src/libxl/libxl_conf.h | 4 + src/libxl/libxl_domain.c | 9 + src/libxl/libxl_driver.c | 447 +++++++++++- src/lxc/lxc_conf.h | 4 - src/lxc/lxc_driver.c | 17 +- src/lxc/lxc_hostdev.c | 315 +-------- src/qemu/qemu_command.c | 3 +- src/qemu/qemu_conf.h | 10 +- src/qemu/qemu_driver.c | 88 +-- src/qemu/qemu_hostdev.c | 1220 ++----------------------------- src/qemu/qemu_hostdev.h | 27 +- src/qemu/qemu_hotplug.c | 77 +-- src/qemu/qemu_process.c | 8 +- src/util/virhostdev.c | 1621 +++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 140 ++++ src/util/virpci.c | 31 +- src/util/virpci.h | 9 +- src/util/virscsi.c | 32 +- src/util/virscsi.h | 7 +- src/util/virusb.c | 31 +- src/util/virusb.h | 8 +- tests/Makefile.am | 5 + tests/virhostdevtest.c | 507 +++++++++++++ tests/virscsitest.c | 6 +- 32 files changed, 3081 insertions(+), 1635 deletions(-) create mode 100644 src/util/virhostdev.c create mode 100644 src/util/virhostdev.h create mode 100644 tests/virhostdevtest.c

Specify which driver and which domain in used_by area to avoid conflict among different drivers. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/lxc/lxc_hostdev.c | 24 +++++++++++------ src/qemu/qemu_conf.h | 2 + src/qemu/qemu_driver.c | 16 ++++++----- src/qemu/qemu_hostdev.c | 63 +++++++++++++++++++++++++++++------------------ src/util/virpci.c | 36 +++++++++++++++++++++------ src/util/virpci.h | 9 ++++-- src/util/virscsi.c | 32 ++++++++++++++++++------ src/util/virscsi.h | 7 +++- src/util/virusb.c | 31 ++++++++++++++++++----- src/util/virusb.h | 8 ++++- tests/virscsitest.c | 6 ++-- 11 files changed, 161 insertions(+), 73 deletions(-) diff --git a/src/lxc/lxc_hostdev.c b/src/lxc/lxc_hostdev.c index 3b371fc..b7248df 100644 --- a/src/lxc/lxc_hostdev.c +++ b/src/lxc/lxc_hostdev.c @@ -60,7 +60,7 @@ virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver, continue; } - virUSBDeviceSetUsedBy(usb, def->name); + virUSBDeviceSetUsedBy(usb, LXC_DRIVER_NAME, def->name); virObjectLock(driver->activeUsbHostdevs); if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) { @@ -90,12 +90,16 @@ virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver, for (i = 0; i < count; i++) { virUSBDevicePtr usb = virUSBDeviceListGet(list, i); if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) { - const char *other_name = virUSBDeviceGetUsedBy(tmp); + const char *other_drvname; + const char *other_domname; - if (other_name) + virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname); + if (other_drvname && other_domname) virReportError(VIR_ERR_OPERATION_INVALID, - _("USB device %s is in use by domain %s"), - virUSBDeviceGetName(tmp), other_name); + _("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"), @@ -103,7 +107,7 @@ virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver, goto error; } - virUSBDeviceSetUsedBy(usb, name); + virUSBDeviceSetUsedBy(usb, LXC_DRIVER_NAME, name); VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs", virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name); /* @@ -351,7 +355,8 @@ virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr driver, for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; virUSBDevicePtr usb, tmp; - const char *used_by = NULL; + const char *usedby_domname = NULL; + const char *usedby_drvname = NULL; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; @@ -389,8 +394,9 @@ virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr driver, continue; } - used_by = virUSBDeviceGetUsedBy(tmp); - if (STREQ_NULLABLE(used_by, name)) { + virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname); + if (STREQ_NULLABLE(LXC_DRIVER_NAME, usedby_drvname) && + STREQ_NULLABLE(name, usedby_domname)) { VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs", hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device, diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index c181dc2..ece185b 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -53,6 +53,8 @@ # error "Port me" # endif +# define QEMU_DRIVER_NAME "QEMU" + typedef struct _virQEMUDriver virQEMUDriver; typedef virQEMUDriver *virQEMUDriverPtr; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e04a328..f36a8b4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -98,8 +98,6 @@ #define VIR_FROM_THIS VIR_FROM_QEMU -#define QEMU_DRIVER_NAME "QEMU" - #define QEMU_NB_MEM_PARAM 3 #define QEMU_NB_BLOCK_IO_TUNE_PARAM 6 @@ -11352,12 +11350,16 @@ qemuNodeDeviceReAttach(virNodeDevicePtr dev) virObjectLock(driver->inactivePciHostdevs); other = virPCIDeviceListFind(driver->activePciHostdevs, pci); if (other) { - const char *other_name = virPCIDeviceGetUsedBy(other); + const char *other_drvname = NULL; + const char *other_domname = NULL; + virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname); - if (other_name) + if (other_drvname && other_domname) virReportError(VIR_ERR_OPERATION_INVALID, - _("PCI device %s is still in use by domain %s"), - virPCIDeviceGetName(pci), other_name); + _("PCI device %s is still in use by " + "driver %s, domain %s"), + virPCIDeviceGetName(pci), + other_drvname, other_domname); else virReportError(VIR_ERR_OPERATION_INVALID, _("PCI device %s is still in use"), @@ -16765,7 +16767,7 @@ static virDriver qemuDriver = { static virStateDriver qemuStateDriver = { - .name = "QEMU", + .name = QEMU_DRIVER_NAME, .stateInitialize = qemuStateInitialize, .stateAutoStart = qemuStateAutoStart, .stateCleanup = qemuStateCleanup, diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 1b16386..e4f6b1b 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -177,7 +177,7 @@ qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver, goto cleanup; } - virPCIDeviceSetUsedBy(dev, def->name); + virPCIDeviceSetUsedBy(dev, QEMU_DRIVER_NAME, def->name); /* Setup the original states for the PCI device */ virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub); @@ -230,7 +230,7 @@ qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver, continue; } - virUSBDeviceSetUsedBy(usb, def->name); + virUSBDeviceSetUsedBy(usb, QEMU_DRIVER_NAME, def->name); if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) { virUSBDeviceFree(usb); @@ -274,13 +274,13 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver, goto cleanup; if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) { - if (virSCSIDeviceSetUsedBy(tmp, def->name) < 0) { + if (virSCSIDeviceSetUsedBy(tmp, QEMU_DRIVER_NAME, def->name) < 0) { virSCSIDeviceFree(scsi); goto cleanup; } virSCSIDeviceFree(scsi); } else { - if (virSCSIDeviceSetUsedBy(scsi, def->name) < 0 || + if (virSCSIDeviceSetUsedBy(scsi, QEMU_DRIVER_NAME, def->name) < 0 || virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) { virSCSIDeviceFree(scsi); goto cleanup; @@ -693,12 +693,16 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, * the dev is in list driver->activePciHostdevs. */ if ((other = virPCIDeviceListFind(driver->activePciHostdevs, dev))) { - const char *other_name = virPCIDeviceGetUsedBy(other); + const char *other_drvname; + const char *other_domname; - if (other_name) + virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname); + if (other_drvname && other_domname) virReportError(VIR_ERR_OPERATION_INVALID, - _("PCI device %s is in use by domain %s"), - virPCIDeviceGetName(dev), other_name); + _("PCI device %s is in use by " + "driver %s, domain %s"), + virPCIDeviceGetName(dev), + other_drvname, other_domname); else virReportError(VIR_ERR_OPERATION_INVALID, _("PCI device %s is already in use"), @@ -766,7 +770,7 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev); if (activeDev) - virPCIDeviceSetUsedBy(activeDev, name); + virPCIDeviceSetUsedBy(activeDev, QEMU_DRIVER_NAME, name); } /* Loop 8: Now set the original states for hostdev def */ @@ -857,12 +861,16 @@ qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver, for (i = 0; i < count; i++) { virUSBDevicePtr usb = virUSBDeviceListGet(list, i); if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) { - const char *other_name = virUSBDeviceGetUsedBy(tmp); + const char *other_drvname; + const char *other_domname; - if (other_name) + virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname); + if (other_drvname && other_domname) virReportError(VIR_ERR_OPERATION_INVALID, - _("USB device %s is in use by domain %s"), - virUSBDeviceGetName(tmp), other_name); + _("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"), @@ -870,7 +878,7 @@ qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver, goto error; } - virUSBDeviceSetUsedBy(usb, name); + virUSBDeviceSetUsedBy(usb, QEMU_DRIVER_NAME, name); VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs", virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name); /* @@ -1140,10 +1148,10 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, goto error; } - if (virSCSIDeviceSetUsedBy(tmp, name) < 0) + if (virSCSIDeviceSetUsedBy(tmp, QEMU_DRIVER_NAME, name) < 0) goto error; } else { - if (virSCSIDeviceSetUsedBy(scsi, name) < 0) + if (virSCSIDeviceSetUsedBy(scsi, QEMU_DRIVER_NAME, name) < 0) goto error; VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); @@ -1275,10 +1283,15 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, * been used by this domain. */ activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev); - if (activeDev && - STRNEQ_NULLABLE(name, virPCIDeviceGetUsedBy(activeDev))) { - virPCIDeviceListDel(pcidevs, dev); - continue; + if (activeDev) { + const char *usedby_drvname; + const char *usedby_domname; + virPCIDeviceGetUsedBy(activeDev, &usedby_drvname, &usedby_domname); + if (STRNEQ_NULLABLE(QEMU_DRIVER_NAME, usedby_drvname) || + STRNEQ_NULLABLE(name, usedby_domname)) { + virPCIDeviceListDel(pcidevs, dev); + continue; + } } virPCIDeviceListDel(driver->activePciHostdevs, dev); @@ -1332,7 +1345,8 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; virUSBDevicePtr usb, tmp; - const char *used_by = NULL; + const char *usedby_drvname; + const char *usedby_domname; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; @@ -1370,8 +1384,9 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, continue; } - used_by = virUSBDeviceGetUsedBy(tmp); - if (STREQ_NULLABLE(used_by, name)) { + virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname); + if (STREQ_NULLABLE(QEMU_DRIVER_NAME, usedby_drvname) && + STREQ_NULLABLE(name, usedby_domname)) { VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs", hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device, @@ -1445,7 +1460,7 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, hostdev->source.subsys.u.scsi.unit, name); - virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp, name); + virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp, QEMU_DRIVER_NAME, name); virSCSIDeviceFree(scsi); } virObjectUnlock(driver->activeScsiHostdevs); diff --git a/src/util/virpci.c b/src/util/virpci.c index 00d1064..e6133a9 100644 --- a/src/util/virpci.c +++ b/src/util/virpci.c @@ -59,7 +59,10 @@ struct _virPCIDevice { char name[PCI_ADDR_LEN]; /* domain:bus:slot.function */ char id[PCI_ID_LEN]; /* product vendor */ char *path; - const char *used_by; /* The domain which uses the device */ + + /* The driver:domain which uses the device */ + char *used_by_drvname; + char *used_by_domname; unsigned int pcie_cap_pos; unsigned int pci_pm_cap_pos; @@ -1615,8 +1618,11 @@ virPCIDeviceCopy(virPCIDevicePtr dev) /* shallow copy to take care of most attributes */ *copy = *dev; copy->path = copy->stubDriver = NULL; + copy->used_by_drvname = copy->used_by_domname = NULL; if (VIR_STRDUP(copy->path, dev->path) < 0 || - VIR_STRDUP(copy->stubDriver, dev->stubDriver) < 0) { + VIR_STRDUP(copy->stubDriver, dev->stubDriver) < 0 || + VIR_STRDUP(copy->used_by_drvname, dev->used_by_drvname) < 0 || + VIR_STRDUP(copy->used_by_domname, dev->used_by_domname) < 0) { goto error; } return copy; @@ -1635,6 +1641,8 @@ virPCIDeviceFree(virPCIDevicePtr dev) VIR_DEBUG("%s %s: freeing", dev->id, dev->name); VIR_FREE(dev->path); VIR_FREE(dev->stubDriver); + VIR_FREE(dev->used_by_drvname); + VIR_FREE(dev->used_by_domname); VIR_FREE(dev); } @@ -1704,16 +1712,28 @@ virPCIDeviceSetReprobe(virPCIDevicePtr dev, bool reprobe) dev->reprobe = reprobe; } -void -virPCIDeviceSetUsedBy(virPCIDevicePtr dev, const char *name) +int +virPCIDeviceSetUsedBy(virPCIDevicePtr dev, + const char *drv_name, + const char *dom_name) { - dev->used_by = name; + VIR_FREE(dev->used_by_drvname); + VIR_FREE(dev->used_by_domname); + if (VIR_STRDUP(dev->used_by_drvname, drv_name) < 0) + return -1; + if (VIR_STRDUP(dev->used_by_domname, dom_name) < 0) + return -1; + + return 0; } -const char * -virPCIDeviceGetUsedBy(virPCIDevicePtr dev) +void +virPCIDeviceGetUsedBy(virPCIDevicePtr dev, + const char **drv_name, + const char **dom_name) { - return dev->used_by; + *drv_name = dev->used_by_drvname; + *dom_name = dev->used_by_domname; } void virPCIDeviceReattachInit(virPCIDevicePtr pci) diff --git a/src/util/virpci.h b/src/util/virpci.h index ac6dae1..20ffe54 100644 --- a/src/util/virpci.h +++ b/src/util/virpci.h @@ -66,9 +66,12 @@ int virPCIDeviceSetStubDriver(virPCIDevicePtr dev, const char *driver) ATTRIBUTE_NONNULL(2); const char *virPCIDeviceGetStubDriver(virPCIDevicePtr dev); -void virPCIDeviceSetUsedBy(virPCIDevice *dev, - const char *used_by); -const char *virPCIDeviceGetUsedBy(virPCIDevice *dev); +int virPCIDeviceSetUsedBy(virPCIDevice *dev, + const char *drv_name, + const char *dom_name); +void virPCIDeviceGetUsedBy(virPCIDevice *dev, + const char **drv_name, + const char **dom_name); unsigned int virPCIDeviceGetUnbindFromStub(virPCIDevicePtr dev); void virPCIDeviceSetUnbindFromStub(virPCIDevice *dev, bool unbind); diff --git a/src/util/virscsi.c b/src/util/virscsi.c index 2f469f2..69eae24 100644 --- a/src/util/virscsi.c +++ b/src/util/virscsi.c @@ -47,6 +47,11 @@ /* For virReportOOMError() and virReportSystemError() */ #define VIR_FROM_THIS VIR_FROM_NONE +struct _virUsedByInfo { + char *drvname; /* which driver */ + char *domname; /* which domain */ +}; +typedef struct _virUsedByInfo *virUsedByInfoPtr; struct _virSCSIDevice { unsigned int adapter; @@ -57,7 +62,7 @@ struct _virSCSIDevice { char *name; /* adapter:bus:target:unit */ char *id; /* model:vendor */ char *sg_path; /* e.g. /dev/sg2 */ - char **used_by; /* name of the domains using this dev */ + virUsedByInfoPtr *used_by; /* driver:domain(s) using this dev */ size_t n_used_by; /* how many domains are using this dev */ bool readonly; @@ -274,19 +279,26 @@ virSCSIDeviceFree(virSCSIDevicePtr dev) VIR_FREE(dev->id); VIR_FREE(dev->name); VIR_FREE(dev->sg_path); - for (i = 0; i < dev->n_used_by; i++) + for (i = 0; i < dev->n_used_by; i++) { + VIR_FREE(dev->used_by[i]->drvname); + VIR_FREE(dev->used_by[i]->domname); VIR_FREE(dev->used_by[i]); + } VIR_FREE(dev->used_by); VIR_FREE(dev); } int virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, - const char *name) + const char *drvname, + const char *domname) { - char *copy = NULL; - - if (VIR_STRDUP(copy, name) < 0) + virUsedByInfoPtr copy; + if (VIR_ALLOC(copy) < 0) + return -1; + if (VIR_STRDUP(copy->drvname, drvname) < 0) + return -1; + if (VIR_STRDUP(copy->domname, domname) < 0) return -1; return VIR_APPEND_ELEMENT(dev->used_by, dev->n_used_by, copy); @@ -427,14 +439,18 @@ virSCSIDeviceListSteal(virSCSIDeviceListPtr list, void virSCSIDeviceListDel(virSCSIDeviceListPtr list, virSCSIDevicePtr dev, - const char *name) + const char *drvname, + const char *domname) { virSCSIDevicePtr tmp = NULL; size_t i; for (i = 0; i < dev->n_used_by; i++) { - if (STREQ_NULLABLE(dev->used_by[i], name)) { + if (STREQ_NULLABLE(dev->used_by[i]->drvname, drvname) && + STREQ_NULLABLE(dev->used_by[i]->domname, domname)) { if (dev->n_used_by > 1) { + VIR_FREE(dev->used_by[i]->drvname); + VIR_FREE(dev->used_by[i]->domname); VIR_FREE(dev->used_by[i]); VIR_DELETE_ELEMENT(dev->used_by, i, dev->n_used_by); } else { diff --git a/src/util/virscsi.h b/src/util/virscsi.h index 1b685eb..c67837f 100644 --- a/src/util/virscsi.h +++ b/src/util/virscsi.h @@ -53,7 +53,9 @@ virSCSIDevicePtr virSCSIDeviceNew(const char *sysfs_prefix, bool shareable); void virSCSIDeviceFree(virSCSIDevicePtr dev); -int virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, const char *name); +int virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, + const char *drvname, + const char *domname); bool virSCSIDeviceIsAvailable(virSCSIDevicePtr dev); const char *virSCSIDeviceGetName(virSCSIDevicePtr dev); unsigned int virSCSIDeviceGetAdapter(virSCSIDevicePtr dev); @@ -87,7 +89,8 @@ virSCSIDevicePtr virSCSIDeviceListSteal(virSCSIDeviceListPtr list, virSCSIDevicePtr dev); void virSCSIDeviceListDel(virSCSIDeviceListPtr list, virSCSIDevicePtr dev, - const char *name); + const char *drvname, + const char *domname); virSCSIDevicePtr virSCSIDeviceListFind(virSCSIDeviceListPtr list, virSCSIDevicePtr dev); diff --git a/src/util/virusb.c b/src/util/virusb.c index bb5980d..90a0061 100644 --- a/src/util/virusb.c +++ b/src/util/virusb.c @@ -55,7 +55,10 @@ struct _virUSBDevice { char name[USB_ADDR_LEN]; /* domain:bus:slot.function */ char id[USB_ID_LEN]; /* product vendor */ char *path; - const char *used_by; /* name of the domain using this dev */ + + /* driver:domain using this dev */ + char *used_by_drvname; + char *used_by_domname; }; struct _virUSBDeviceList { @@ -375,19 +378,33 @@ virUSBDeviceFree(virUSBDevicePtr dev) return; VIR_DEBUG("%s %s: freeing", dev->id, dev->name); VIR_FREE(dev->path); + VIR_FREE(dev->used_by_drvname); + VIR_FREE(dev->used_by_domname); VIR_FREE(dev); } - -void virUSBDeviceSetUsedBy(virUSBDevicePtr dev, - const char *name) +int +virUSBDeviceSetUsedBy(virUSBDevicePtr dev, + const char *drv_name, + const char *dom_name) { - dev->used_by = name; + VIR_FREE(dev->used_by_drvname); + VIR_FREE(dev->used_by_domname); + if (VIR_STRDUP(dev->used_by_drvname, drv_name) < 0) + return -1; + if (VIR_STRDUP(dev->used_by_domname, dom_name) < 0) + return -1; + + return 0; } -const char * virUSBDeviceGetUsedBy(virUSBDevicePtr dev) +void +virUSBDeviceGetUsedBy(virUSBDevicePtr dev, + const char **drv_name, + const char **dom_name) { - return dev->used_by; + *drv_name = dev->used_by_drvname; + *dom_name = dev->used_by_domname; } const char *virUSBDeviceGetName(virUSBDevicePtr dev) diff --git a/src/util/virusb.h b/src/util/virusb.h index e0a7c4c..f98ea21 100644 --- a/src/util/virusb.h +++ b/src/util/virusb.h @@ -60,8 +60,12 @@ int virUSBDeviceFind(unsigned int vendor, virUSBDevicePtr *usb); void virUSBDeviceFree(virUSBDevicePtr dev); -void virUSBDeviceSetUsedBy(virUSBDevicePtr dev, const char *name); -const char *virUSBDeviceGetUsedBy(virUSBDevicePtr dev); +int virUSBDeviceSetUsedBy(virUSBDevicePtr dev, + const char *drv_name, + const char *dom_name); +void virUSBDeviceGetUsedBy(virUSBDevicePtr dev, + const char **drv_name, + const char **dom_name); const char *virUSBDeviceGetName(virUSBDevicePtr dev); unsigned int virUSBDeviceGetBus(virUSBDevicePtr dev); diff --git a/tests/virscsitest.c b/tests/virscsitest.c index d4b3e4a..586c41b 100644 --- a/tests/virscsitest.c +++ b/tests/virscsitest.c @@ -91,13 +91,13 @@ test2(const void *data ATTRIBUTE_UNUSED) if (!virSCSIDeviceIsAvailable(dev)) goto cleanup; - if (virSCSIDeviceSetUsedBy(dev, "fc18") < 0) + if (virSCSIDeviceSetUsedBy(dev, "QEMU", "fc18") < 0) goto cleanup; if (virSCSIDeviceIsAvailable(dev)) goto cleanup; - if (virSCSIDeviceSetUsedBy(dev, "fc20") < 0) + if (virSCSIDeviceSetUsedBy(dev, "QEMU", "fc20") < 0) goto cleanup; if (virSCSIDeviceIsAvailable(dev)) @@ -117,7 +117,7 @@ test2(const void *data ATTRIBUTE_UNUSED) if (!virSCSIDeviceListFind(list, dev)) goto cleanup; - virSCSIDeviceListDel(list, dev, "fc20"); + virSCSIDeviceListDel(list, dev, "QEMU", "fc20"); if (!virSCSIDeviceListFind(list, dev)) goto cleanup; -- 1.6.0.2

On Sat, Mar 01, 2014 at 02:28:56PM +0800, Chunyan Liu wrote:
Specify which driver and which domain in used_by area to avoid conflict among different drivers.
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/lxc/lxc_hostdev.c | 24 +++++++++++------ src/qemu/qemu_conf.h | 2 + src/qemu/qemu_driver.c | 16 ++++++----- src/qemu/qemu_hostdev.c | 63 +++++++++++++++++++++++++++++------------------ src/util/virpci.c | 36 +++++++++++++++++++++------ src/util/virpci.h | 9 ++++-- src/util/virscsi.c | 32 ++++++++++++++++++------ src/util/virscsi.h | 7 +++- src/util/virusb.c | 31 ++++++++++++++++++----- src/util/virusb.h | 8 ++++- tests/virscsitest.c | 6 ++-- 11 files changed, 161 insertions(+), 73 deletions(-)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Coverity found a memory leak... <...snip...>
int virSCSIDeviceSetUsedBy(virSCSIDevicePtr dev, - const char *name) + const char *drvname, + const char *domname) { - char *copy = NULL; - - if (VIR_STRDUP(copy, name) < 0) + virUsedByInfoPtr copy; + if (VIR_ALLOC(copy) < 0) + return -1; + if (VIR_STRDUP(copy->drvname, drvname) < 0) + return -1; + if (VIR_STRDUP(copy->domname, domname) < 0) return -1;
Either/both VIR_STRDUP() failures of return -1 will leak 'copy'. John

Same logic of preparing/reattaching hostdevs could be used in attach/detach hotplug places, so reuse hostdev interfaces to avoid duplicate, also for later extracting general code to common library. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 8 +++--- src/qemu/qemu_hostdev.h | 11 +++++++- src/qemu/qemu_hotplug.c | 61 +++------------------------------------------- 3 files changed, 18 insertions(+), 62 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index e4f6b1b..e9c33f8 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -847,7 +847,7 @@ cleanup: int -qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver, +qemuPrepareHostdevUSBDevices(virHostdevManagerPtr mgr, const char *name, virUSBDeviceListPtr list) { @@ -991,7 +991,7 @@ out: } -static int +int qemuPrepareHostUSBDevices(virQEMUDriverPtr driver, virDomainDefPtr def, bool coldBoot) @@ -1217,7 +1217,7 @@ qemuPrepareHostDevices(virQEMUDriverPtr driver, * are locked */ void -qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver) +qemuReattachPciDevice(virPCIDevicePtr dev, QEMUDriverPtr driver) { int retries = 100; @@ -1333,7 +1333,7 @@ cleanup: } -static void +void qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, const char *name, virDomainHostdevDefPtr *hostdevs, diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h index ffb3167..1567c1d 100644 --- a/src/qemu/qemu_hostdev.h +++ b/src/qemu/qemu_hostdev.h @@ -47,6 +47,10 @@ int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev, int qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver, const char *name, virUSBDeviceListPtr list); +int +qemuPrepareHostUSBDevices(virQEMUDriverPtr driver, + virDomainDefPtr def, + bool coldBoot); int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, const char *name, virDomainHostdevDefPtr *hostdevs, @@ -55,11 +59,16 @@ int qemuPrepareHostDevices(virQEMUDriverPtr driver, virDomainDefPtr def, virQEMUCapsPtr qemuCaps, bool coldBoot); +void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver); +void +qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs); -void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver); void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, const char *name, virDomainHostdevDefPtr *hostdevs, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 6703c92..5546693 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1454,28 +1454,16 @@ qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver, virDomainHostdevDefPtr hostdev) { qemuDomainObjPrivatePtr priv = vm->privateData; - virUSBDeviceList *list = NULL; - virUSBDevicePtr usb = NULL; char *devstr = NULL; bool added = false; bool teardowncgroup = false; bool teardownlabel = false; int ret = -1; - if (qemuFindHostdevUSBDevice(hostdev, true, &usb) < 0) - return -1; - - if (!(list = virUSBDeviceListNew())) - goto cleanup; - - if (virUSBDeviceListAdd(list, usb) < 0) - goto cleanup; - - if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, list) < 0) + if (qemuPrepareHostUSBDevices(driver, vm->def, 0) < 0) goto cleanup; added = true; - virUSBDeviceListSteal(list, usb); if (qemuSetupHostdevCGroup(vm, hostdev) < 0) goto cleanup; @@ -1520,13 +1508,8 @@ cleanup: vm->def, hostdev, NULL) < 0) VIR_WARN("Unable to restore host device labelling on hotplug fail"); if (added) - virUSBDeviceListSteal(driver->activeUsbHostdevs, usb); + qemuDomainReAttachHostUsbDevices(driver, vm->def->name, &hostdev, 1); } - if (list && usb && - !virUSBDeviceListFind(list, usb) && - !virUSBDeviceListFind(driver->activeUsbHostdevs, usb)) - virUSBDeviceFree(usb); - virObjectUnref(list); VIR_FREE(devstr); return ret; } @@ -2531,29 +2514,7 @@ qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev) { - virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; - virPCIDevicePtr pci; - virPCIDevicePtr activePci; - - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); - pci = virPCIDeviceNew(subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, - subsys->u.pci.addr.slot, subsys->u.pci.addr.function); - if (pci) { - activePci = virPCIDeviceListSteal(driver->activePciHostdevs, pci); - if (activePci && - virPCIDeviceReset(activePci, driver->activePciHostdevs, - driver->inactivePciHostdevs) == 0) { - qemuReattachPciDevice(activePci, driver); - } else { - /* reset of the device failed, treat it as if it was returned */ - virPCIDeviceFree(activePci); - } - virPCIDeviceFree(pci); - } - virObjectUnlock(driver->activePciHostdevs); - virObjectUnlock(driver->inactivePciHostdevs); - + qemuDomainReAttachHostdevDevices(driver, vm->def->name, &hostdev, 1); qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL); } @@ -2562,19 +2523,7 @@ qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver, virDomainObjPtr vm ATTRIBUTE_UNUSED, virDomainHostdevDefPtr hostdev) { - virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; - virUSBDevicePtr usb; - - usb = virUSBDeviceNew(subsys->u.usb.bus, subsys->u.usb.device, NULL); - if (usb) { - virObjectLock(driver->activeUsbHostdevs); - virUSBDeviceListDel(driver->activeUsbHostdevs, usb); - virObjectUnlock(driver->activeUsbHostdevs); - virUSBDeviceFree(usb); - } else { - VIR_WARN("Unable to find device %03d.%03d in list of used USB devices", - subsys->u.usb.bus, subsys->u.usb.device); - } + qemuDomainReAttachHostUsbDevices(driver, vm->def->name, &hostdev, 1); } static void @@ -2622,8 +2571,6 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver, virDomainAuditHostdev(vm, hostdev, "detach", true); - qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir); - switch ((enum virDomainHostdevSubsysType) hostdev->source.subsys.type) { case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: qemuDomainRemovePCIHostDevice(driver, vm, hostdev); -- 1.6.0.2

On Sat, Mar 01, 2014 at 02:28:57PM +0800, Chunyan Liu wrote:
Same logic of preparing/reattaching hostdevs could be used in attach/detach hotplug places, so reuse hostdev interfaces to avoid duplicate, also for later extracting general code to common library.
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 8 +++--- src/qemu/qemu_hostdev.h | 11 +++++++- src/qemu/qemu_hotplug.c | 61 +++------------------------------------------- 3 files changed, 18 insertions(+), 62 deletions(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 6703c92..5546693 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1454,28 +1454,16 @@ qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver, virDomainHostdevDefPtr hostdev) { qemuDomainObjPrivatePtr priv = vm->privateData; - virUSBDeviceList *list = NULL; - virUSBDevicePtr usb = NULL; char *devstr = NULL; bool added = false; bool teardowncgroup = false; bool teardownlabel = false; int ret = -1;
- if (qemuFindHostdevUSBDevice(hostdev, true, &usb) < 0) - return -1; - - if (!(list = virUSBDeviceListNew())) - goto cleanup; - - if (virUSBDeviceListAdd(list, usb) < 0) - goto cleanup; - - if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, list) < 0)
This code you're deleting took the 'hostdev' parameter that was passed into this method, and runs the 'qemuPrepareHostdevUSBDevices' method on it.
+ if (qemuPrepareHostUSBDevices(driver, vm->def, 0) < 0) goto cleanup;
This code you're adding takes the list of existing hostdevs in the virDomainDefPtr and runs the 'qemuPrepareHostdevUSBDevices' method on it. I don't see how this can possibly be correct, since the before and after code processes totally different hostdev device instances.
@@ -2531,29 +2514,7 @@ qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev) { - virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; - virPCIDevicePtr pci; - virPCIDevicePtr activePci; - - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); - pci = virPCIDeviceNew(subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, - subsys->u.pci.addr.slot, subsys->u.pci.addr.function); - if (pci) { - activePci = virPCIDeviceListSteal(driver->activePciHostdevs, pci); - if (activePci && - virPCIDeviceReset(activePci, driver->activePciHostdevs, - driver->inactivePciHostdevs) == 0) { - qemuReattachPciDevice(activePci, driver); - } else { - /* reset of the device failed, treat it as if it was returned */ - virPCIDeviceFree(activePci); - } - virPCIDeviceFree(pci); - } - virObjectUnlock(driver->activePciHostdevs); - virObjectUnlock(driver->inactivePciHostdevs); - + qemuDomainReAttachHostdevDevices(driver, vm->def->name, &hostdev, 1); qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL); }
@@ -2562,19 +2523,7 @@ qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver, virDomainObjPtr vm ATTRIBUTE_UNUSED, virDomainHostdevDefPtr hostdev) { - virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; - virUSBDevicePtr usb; - - usb = virUSBDeviceNew(subsys->u.usb.bus, subsys->u.usb.device, NULL); - if (usb) { - virObjectLock(driver->activeUsbHostdevs); - virUSBDeviceListDel(driver->activeUsbHostdevs, usb); - virObjectUnlock(driver->activeUsbHostdevs); - virUSBDeviceFree(usb); - } else { - VIR_WARN("Unable to find device %03d.%03d in list of used USB devices", - subsys->u.usb.bus, subsys->u.usb.device); - } + qemuDomainReAttachHostUsbDevices(driver, vm->def->name, &hostdev, 1); }
static void @@ -2622,8 +2571,6 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
virDomainAuditHostdev(vm, hostdev, "detach", true);
- qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir); -
This doesn't look valid to remove. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

2014-03-04 20:17 GMT+08:00 Daniel P. Berrange <berrange@redhat.com>:
On Sat, Mar 01, 2014 at 02:28:57PM +0800, Chunyan Liu wrote:
Same logic of preparing/reattaching hostdevs could be used in attach/detach hotplug places, so reuse hostdev interfaces to avoid duplicate, also for later extracting general code to common library.
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 8 +++--- src/qemu/qemu_hostdev.h | 11 +++++++- src/qemu/qemu_hotplug.c | 61 +++------------------------------------------- 3 files changed, 18 insertions(+), 62 deletions(-)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 6703c92..5546693 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1454,28 +1454,16 @@ qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver, virDomainHostdevDefPtr hostdev) { qemuDomainObjPrivatePtr priv = vm->privateData; - virUSBDeviceList *list = NULL; - virUSBDevicePtr usb = NULL; char *devstr = NULL; bool added = false; bool teardowncgroup = false; bool teardownlabel = false; int ret = -1;
- if (qemuFindHostdevUSBDevice(hostdev, true, &usb) < 0) - return -1; - - if (!(list = virUSBDeviceListNew())) - goto cleanup; - - if (virUSBDeviceListAdd(list, usb) < 0) - goto cleanup; - - if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, list) < 0)
This code you're deleting took the 'hostdev' parameter that was passed into this method, and runs the 'qemuPrepareHostdevUSBDevices' method on it.
+ if (qemuPrepareHostUSBDevices(driver, vm->def, 0) < 0) goto cleanup;
This code you're adding takes the list of existing hostdevs in the virDomainDefPtr and runs the 'qemuPrepareHostdevUSBDevices' method on it.
I don't see how this can possibly be correct, since the before and after code processes totally different hostdev device instances.
My mistake. It should be: qemuPrepareHostUSBDevices(driver, vm->def->name,driver, &hostdev, 1, 0); qemuPrepareHostUSBDevices interface shoule be updated a bit, just to be consistency with *PreparePCIDevices and *PrepareSCSIDevices. Will update.
@@ -2531,29 +2514,7 @@ qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm, virDomainHostdevDefPtr hostdev) { - virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; - virPCIDevicePtr pci; - virPCIDevicePtr activePci; - - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); - pci = virPCIDeviceNew(subsys->u.pci.addr.domain,
- subsys->u.pci.addr.slot, subsys->u.pci.addr.function); - if (pci) { - activePci = virPCIDeviceListSteal(driver->activePciHostdevs,
subsys->u.pci.addr.bus, pci);
- if (activePci && - virPCIDeviceReset(activePci, driver->activePciHostdevs, - driver->inactivePciHostdevs) == 0) { - qemuReattachPciDevice(activePci, driver); - } else { - /* reset of the device failed, treat it as if it was returned */ - virPCIDeviceFree(activePci); - } - virPCIDeviceFree(pci); - } - virObjectUnlock(driver->activePciHostdevs); - virObjectUnlock(driver->inactivePciHostdevs); - + qemuDomainReAttachHostdevDevices(driver, vm->def->name, &hostdev, 1); qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL); }
@@ -2562,19 +2523,7 @@ qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver, virDomainObjPtr vm ATTRIBUTE_UNUSED, virDomainHostdevDefPtr hostdev) { - virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; - virUSBDevicePtr usb; - - usb = virUSBDeviceNew(subsys->u.usb.bus, subsys->u.usb.device, NULL); - if (usb) { - virObjectLock(driver->activeUsbHostdevs); - virUSBDeviceListDel(driver->activeUsbHostdevs, usb); - virObjectUnlock(driver->activeUsbHostdevs); - virUSBDeviceFree(usb); - } else { - VIR_WARN("Unable to find device %03d.%03d in list of used USB devices", - subsys->u.usb.bus, subsys->u.usb.device); - } + qemuDomainReAttachHostUsbDevices(driver, vm->def->name, &hostdev, 1); }
static void @@ -2622,8 +2571,6 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
virDomainAuditHostdev(vm, hostdev, "detach", true);
- qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir); -
This doesn't look valid to remove.
qemuDomainHostdevNetConfigRestore will be done in qemuDomainReAttachHostdevDevices after using the latter in qemuDomainRemovePCIHostDevice. So, it's not needed here.
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/:| |: http://libvirt.org -o- http://virt-manager.org:| |: http://autobuild.org -o- http://search.cpan.org/~danberr/:| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc:|

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 12 ++++++------ src/qemu/qemu_hostdev.h | 13 ------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index e9c33f8..d37d3fe 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -310,7 +310,7 @@ qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, } -int +static int qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev) { char *sysfs_path = NULL; @@ -396,7 +396,7 @@ qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf, } -int +static int qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, const unsigned char *uuid, char *stateDir) @@ -465,7 +465,7 @@ cleanup: } -int +static int qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, char *stateDir) { @@ -846,7 +846,7 @@ cleanup: } -int +static int qemuPrepareHostdevUSBDevices(virHostdevManagerPtr mgr, const char *name, virUSBDeviceListPtr list) @@ -903,7 +903,7 @@ error: } -int +static int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev, bool mandatory, virUSBDevicePtr *usb) @@ -1216,7 +1216,7 @@ qemuPrepareHostDevices(virQEMUDriverPtr driver, * Pre-condition: driver->inactivePciHostdevs & driver->activePciHostdevs * are locked */ -void +static void qemuReattachPciDevice(virPCIDevicePtr dev, QEMUDriverPtr driver) { int retries = 100; diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h index 1567c1d..5b34245 100644 --- a/src/qemu/qemu_hostdev.h +++ b/src/qemu/qemu_hostdev.h @@ -41,12 +41,6 @@ int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, virDomainHostdevDefPtr *hostdevs, int nhostdevs, virQEMUCapsPtr qemuCaps); -int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev, - bool mandatory, - virUSBDevicePtr *usb); -int qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver, - const char *name, - virUSBDeviceListPtr list); int qemuPrepareHostUSBDevices(virQEMUDriverPtr driver, virDomainDefPtr def, @@ -59,7 +53,6 @@ int qemuPrepareHostDevices(virQEMUDriverPtr driver, virDomainDefPtr def, virQEMUCapsPtr qemuCaps, bool coldBoot); -void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver); void qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, const char *name, @@ -75,11 +68,5 @@ void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, int nhostdevs); void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver, virDomainDefPtr def); -int qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev); -int qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, - const unsigned char *uuid, - char *stateDir); -int qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, - char *stateDir); #endif /* __QEMU_HOSTDEV_H__ */ -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 4 ++ src/util/virhostdev.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 44 +++++++++++++++++++ 5 files changed, 153 insertions(+), 0 deletions(-) create mode 100644 src/util/virhostdev.c create mode 100644 src/util/virhostdev.h diff --git a/po/POTFILES.in b/po/POTFILES.in index c565771..bcc0ee0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -164,6 +164,7 @@ src/util/vireventpoll.c src/util/virfile.c src/util/virhash.c src/util/virhook.c +src/util/virhostdev.c src/util/viridentity.c src/util/virinitctl.c src/util/viriptables.c diff --git a/src/Makefile.am b/src/Makefile.am index 6ef32ee..25d0370 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -104,6 +104,7 @@ UTIL_SOURCES = \ util/virhash.c util/virhash.h \ util/virhashcode.c util/virhashcode.h \ util/virhook.c util/virhook.h \ + util/virhostdev.c util/virhostdev.h \ util/viridentity.c util/viridentity.h \ util/virinitctl.c util/virinitctl.h \ util/viriptables.c util/viriptables.h \ diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3d8f2e3..bc048a1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1291,6 +1291,10 @@ virHookInitialize; virHookPresent; +#util/virhostdev.h +virHostdevManagerGetDefault; + + # util/viridentity.h virIdentityGetAttr; virIdentityGetCurrent; diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c new file mode 100644 index 0000000..83124e9 --- /dev/null +++ b/src/util/virhostdev.c @@ -0,0 +1,103 @@ +/* virhostdev.c: hostdev management + * + * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Chunyan Liu <cyliu@suse.com> + */ + +#include <config.h> + +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +#include "virhostdev.h" +#include "viralloc.h" +#include "virstring.h" +#include "virfile.h" +#include "virerror.h" +#include "virlog.h" +#include "virutil.h" +#include "configmake.h" + +#define VIR_FROM_THIS VIR_FROM_NONE +#define HOSTDEV_STATE_DIR LOCALSTATEDIR "/run/libvirt/hostdevmgr" + +static virHostdevManagerPtr hostdevMgr; + +static void +virHostdevManagerCleanup(void) +{ + if (!hostdevMgr) + return; + + virObjectUnref(hostdevMgr->activePciHostdevs); + virObjectUnref(hostdevMgr->inactivePciHostdevs); + virObjectUnref(hostdevMgr->activeUsbHostdevs); + VIR_FREE(hostdevMgr->stateDir); + + VIR_FREE(hostdevMgr); +} + +static int +virHostdevOnceInit(void) +{ + if (VIR_ALLOC(hostdevMgr) < 0) + goto error; + + if ((hostdevMgr->activePciHostdevs = virPCIDeviceListNew()) == NULL) + goto error; + + if ((hostdevMgr->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) + goto error; + + if ((hostdevMgr->inactivePciHostdevs = virPCIDeviceListNew()) == NULL) + goto error; + + if ((hostdevMgr->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL) + goto error; + + if (VIR_STRDUP(hostdevMgr->stateDir, HOSTDEV_STATE_DIR) < 0) + goto error; + + if (virFileMakePath(hostdevMgr->stateDir) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Failed to create state dir '%s'"), + hostdevMgr->stateDir); + goto error; + } + + return 0; + +error: + virHostdevManagerCleanup(); + return -1; +} + +VIR_ONCE_GLOBAL_INIT(virHostdev) + +virHostdevManagerPtr +virHostdevManagerGetDefault(void) +{ + if (virHostdevInitialize() < 0) + return NULL; + return hostdevMgr; +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h new file mode 100644 index 0000000..dba5e3e --- /dev/null +++ b/src/util/virhostdev.h @@ -0,0 +1,44 @@ +/* virhostdev.h: hostdev management + * + * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Chunyan Liu <cyliu@suse.com> + */ + +#ifndef __VIR_HOSTDEV_H__ +# define __VIR_HOSTDEV_H__ + +# include "internal.h" + +# include "virpci.h" +# include "virusb.h" +# include "virscsi.h" + +typedef struct _virHostdevManager virHostdevManager; +typedef virHostdevManager *virHostdevManagerPtr; +struct _virHostdevManager{ + char *stateDir; + + virPCIDeviceListPtr activePciHostdevs; + virPCIDeviceListPtr inactivePciHostdevs; + virUSBDeviceListPtr activeUsbHostdevs; + virSCSIDeviceListPtr activeScsiHostdevs; +}; + +virHostdevManagerPtr virHostdevManagerGetDefault(void); + +#endif /* __VIR_HOSTDEV_H__ */ -- 1.6.0.2

On Sat, Mar 01, 2014 at 02:28:59PM +0800, Chunyan Liu wrote:
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 4 ++ src/util/virhostdev.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 44 +++++++++++++++++++ 5 files changed, 153 insertions(+), 0 deletions(-) create mode 100644 src/util/virhostdev.c create mode 100644 src/util/virhostdev.h
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Sat, Mar 01, 2014 at 02:28:59PM +0800, Chunyan Liu wrote:
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/libvirt_private.syms | 4 ++ src/util/virhostdev.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 44 +++++++++++++++++++ 5 files changed, 153 insertions(+), 0 deletions(-) create mode 100644 src/util/virhostdev.c create mode 100644 src/util/virhostdev.h
+static void +virHostdevManagerCleanup(void) +{ + if (!hostdevMgr) + return; + + virObjectUnref(hostdevMgr->activePciHostdevs); + virObjectUnref(hostdevMgr->inactivePciHostdevs); + virObjectUnref(hostdevMgr->activeUsbHostdevs);
Missing unref of activeScsiHostdevs that I'll push before pushing
+ VIR_FREE(hostdevMgr->stateDir); + + VIR_FREE(hostdevMgr); +} + +static int +virHostdevOnceInit(void) +{ + if (VIR_ALLOC(hostdevMgr) < 0) + goto error; + + if ((hostdevMgr->activePciHostdevs = virPCIDeviceListNew()) == NULL) + goto error; + + if ((hostdevMgr->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) + goto error; + + if ((hostdevMgr->inactivePciHostdevs = virPCIDeviceListNew()) == NULL) + goto error; + + if ((hostdevMgr->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL) + goto error; + + if (VIR_STRDUP(hostdevMgr->stateDir, HOSTDEV_STATE_DIR) < 0) + goto error; + + if (virFileMakePath(hostdevMgr->stateDir) < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Failed to create state dir '%s'"), + hostdevMgr->stateDir); + goto error; + } + + return 0; + +error: + virHostdevManagerCleanup(); + return -1; +}
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_conf.h | 8 -- src/qemu/qemu_driver.c | 74 +++++++++---------- src/qemu/qemu_hostdev.c | 192 ++++++++++++++++++++++++++++------------------- src/qemu/qemu_hotplug.c | 1 + 4 files changed, 151 insertions(+), 124 deletions(-) diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index ece185b..2ac88fb 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -215,14 +215,6 @@ struct _virQEMUDriver { /* Immutable pointer. self-locking APIs */ virSecurityManagerPtr securityManager; - /* Immutable pointers. Requires locks to be held before - * calling APIs. activePciHostdevs must be locked before - * inactivePciHostdevs */ - virPCIDeviceListPtr activePciHostdevs; - virPCIDeviceListPtr inactivePciHostdevs; - virUSBDeviceListPtr activeUsbHostdevs; - virSCSIDeviceListPtr activeScsiHostdevs; - /* Immutable pointer. Unsafe APIs. XXX */ virHashTablePtr sharedDevices; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f36a8b4..7d924b2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -95,6 +95,7 @@ #include "viraccessapicheck.h" #include "viraccessapicheckqemu.h" #include "storage/storage_driver.h" +#include "virhostdev.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -695,18 +696,6 @@ qemuStateInitialize(bool privileged, if (qemuSecurityInit(qemu_driver) < 0) goto error; - if ((qemu_driver->activePciHostdevs = virPCIDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL) - goto error; - if (!(qemu_driver->sharedDevices = virHashCreate(30, qemuSharedDeviceEntryFree))) goto error; @@ -983,10 +972,6 @@ qemuStateCleanup(void) { virNWFilterUnRegisterCallbackDriver(&qemuCallbackDriver); virObjectUnref(qemu_driver->config); - virObjectUnref(qemu_driver->activePciHostdevs); - virObjectUnref(qemu_driver->inactivePciHostdevs); - virObjectUnref(qemu_driver->activeUsbHostdevs); - virObjectUnref(qemu_driver->activeScsiHostdevs); virHashFree(qemu_driver->sharedDevices); virObjectUnref(qemu_driver->caps); virQEMUCapsCacheFree(qemu_driver->qemuCapsCache); @@ -11226,7 +11211,6 @@ qemuNodeDeviceDetachFlags(virNodeDevicePtr dev, const char *driverName, unsigned int flags) { - virQEMUDriverPtr driver = dev->conn->privateData; virPCIDevicePtr pci = NULL; unsigned domain = 0, bus = 0, slot = 0, function = 0; int ret = -1; @@ -11234,6 +11218,7 @@ qemuNodeDeviceDetachFlags(virNodeDevicePtr dev, char *xml = NULL; bool legacy = qemuHostdevHostSupportsPassthroughLegacy(); bool vfio = qemuHostdevHostSupportsPassthroughVFIO(); + virHostdevManagerPtr hostdev_mgr; virCheckFlags(0, -1); @@ -11292,18 +11277,21 @@ qemuNodeDeviceDetachFlags(virNodeDevicePtr dev, goto cleanup; } - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto cleanup; + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); - if (virPCIDeviceDetach(pci, driver->activePciHostdevs, - driver->inactivePciHostdevs) < 0) { + if (virPCIDeviceDetach(pci, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) { goto out; } ret = 0; out: - virObjectUnlock(driver->inactivePciHostdevs); - virObjectUnlock(driver->activePciHostdevs); + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); cleanup: virPCIDeviceFree(pci); virNodeDeviceDefFree(def); @@ -11320,13 +11308,13 @@ qemuNodeDeviceDettach(virNodeDevicePtr dev) static int qemuNodeDeviceReAttach(virNodeDevicePtr dev) { - virQEMUDriverPtr driver = dev->conn->privateData; virPCIDevicePtr pci = NULL; virPCIDevicePtr other; unsigned domain = 0, bus = 0, slot = 0, function = 0; int ret = -1; virNodeDeviceDefPtr def = NULL; char *xml = NULL; + virHostdevManagerPtr hostdev_mgr; xml = virNodeDeviceGetXMLDesc(dev, 0); if (!xml) @@ -11346,9 +11334,13 @@ qemuNodeDeviceReAttach(virNodeDevicePtr dev) if (!pci) goto cleanup; - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); - other = virPCIDeviceListFind(driver->activePciHostdevs, pci); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto cleanup_pci; + + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); + other = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, pci); if (other) { const char *other_drvname = NULL; const char *other_domname = NULL; @@ -11369,14 +11361,15 @@ qemuNodeDeviceReAttach(virNodeDevicePtr dev) virPCIDeviceReattachInit(pci); - if (virPCIDeviceReattach(pci, driver->activePciHostdevs, - driver->inactivePciHostdevs) < 0) + if (virPCIDeviceReattach(pci, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) goto out; ret = 0; out: - virObjectUnlock(driver->inactivePciHostdevs); - virObjectUnlock(driver->activePciHostdevs); + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); +cleanup_pci: virPCIDeviceFree(pci); cleanup: virNodeDeviceDefFree(def); @@ -11387,12 +11380,12 @@ cleanup: static int qemuNodeDeviceReset(virNodeDevicePtr dev) { - virQEMUDriverPtr driver = dev->conn->privateData; virPCIDevicePtr pci; unsigned domain = 0, bus = 0, slot = 0, function = 0; int ret = -1; virNodeDeviceDefPtr def = NULL; char *xml = NULL; + virHostdevManagerPtr hostdev_mgr; xml = virNodeDeviceGetXMLDesc(dev, 0); if (!xml) @@ -11412,17 +11405,20 @@ qemuNodeDeviceReset(virNodeDevicePtr dev) if (!pci) goto cleanup; - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); - - if (virPCIDeviceReset(pci, driver->activePciHostdevs, - driver->inactivePciHostdevs) < 0) + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto cleanup_pci; + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); + if (virPCIDeviceReset(pci, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) goto out; ret = 0; out: - virObjectUnlock(driver->inactivePciHostdevs); - virObjectUnlock(driver->activePciHostdevs); + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); +cleanup_pci: virPCIDeviceFree(pci); cleanup: virNodeDeviceDefFree(def); diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index d37d3fe..54ac973 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -37,6 +37,7 @@ #include "virscsi.h" #include "virnetdev.h" #include "virfile.h" +#include "virhostdev.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -99,10 +100,10 @@ qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) * * Return the new list, or NULL if there was a failure. * - * Pre-condition: driver->activePciHostdevs is locked + * Pre-condition: activePciHostdevs is locked */ static virPCIDeviceListPtr -qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver, +qemuGetActivePciHostDeviceList(virHostdevManagerPtr mgr, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { @@ -123,7 +124,7 @@ qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver, continue; addr = &hostdev->source.subsys.u.pci.addr; - activeDev = virPCIDeviceListFindByIDs(driver->activePciHostdevs, + activeDev = virPCIDeviceListFindByIDs(mgr->activePciHostdevs, addr->domain, addr->bus, addr->slot, addr->function); if (activeDev && virPCIDeviceListAddCopy(list, activeDev) < 0) { @@ -137,19 +138,22 @@ qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver, int -qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver, +qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) { virDomainHostdevDefPtr hostdev = NULL; virPCIDevicePtr dev = NULL; size_t i; int ret = -1; + virHostdevManagerPtr mgr; if (!def->nhostdevs) return 0; - - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); + mgr = virHostdevManagerGetDefault(); + if (mgr == NULL) + return -1; + virObjectLock(mgr->activePciHostdevs); + virObjectLock(mgr->inactivePciHostdevs); for (i = 0; i < def->nhostdevs; i++) { hostdev = def->hostdevs[i]; @@ -184,7 +188,7 @@ qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver, virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot); virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe); - if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0) + if (virPCIDeviceListAdd(mgr->activePciHostdevs, dev) < 0) goto cleanup; dev = NULL; } @@ -192,24 +196,26 @@ qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver, ret = 0; cleanup: virPCIDeviceFree(dev); - virObjectUnlock(driver->activePciHostdevs); - virObjectUnlock(driver->inactivePciHostdevs); + virObjectUnlock(mgr->activePciHostdevs); + virObjectUnlock(mgr->inactivePciHostdevs); return ret; } - int -qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver, +qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) { virDomainHostdevDefPtr hostdev = NULL; size_t i; int ret = -1; + virHostdevManagerPtr mgr; if (!def->nhostdevs) return 0; - - virObjectLock(driver->activeUsbHostdevs); + mgr = virHostdevManagerGetDefault(); + if (mgr == NULL) + return -1; + virObjectLock(mgr->activeUsbHostdevs); for (i = 0; i < def->nhostdevs; i++) { virUSBDevicePtr usb = NULL; hostdev = def->hostdevs[i]; @@ -232,19 +238,19 @@ qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver, virUSBDeviceSetUsedBy(usb, QEMU_DRIVER_NAME, def->name); - if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) { + if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0) { virUSBDeviceFree(usb); goto cleanup; } } ret = 0; cleanup: - virObjectUnlock(driver->activeUsbHostdevs); + virObjectUnlock(mgr->activeUsbHostdevs); return ret; } int -qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver, +qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) { virDomainHostdevDefPtr hostdev = NULL; @@ -252,11 +258,14 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver, int ret = -1; virSCSIDevicePtr scsi = NULL; virSCSIDevicePtr tmp = NULL; + virHostdevManagerPtr mgr; if (!def->nhostdevs) return 0; - - virObjectLock(driver->activeScsiHostdevs); + mgr = virHostdevManagerGetDefault(); + if (mgr == NULL) + return -1; + virObjectLock(mgr->activeScsiHostdevs); for (i = 0; i < def->nhostdevs; i++) { hostdev = def->hostdevs[i]; @@ -273,7 +282,7 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver, hostdev->shareable))) goto cleanup; - if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) { + if ((tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi))) { if (virSCSIDeviceSetUsedBy(tmp, QEMU_DRIVER_NAME, def->name) < 0) { virSCSIDeviceFree(scsi); goto cleanup; @@ -281,7 +290,7 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver, virSCSIDeviceFree(scsi); } else { if (virSCSIDeviceSetUsedBy(scsi, QEMU_DRIVER_NAME, def->name) < 0 || - virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) { + virSCSIDeviceListAdd(mgr->activeScsiHostdevs, scsi) < 0) { virSCSIDeviceFree(scsi); goto cleanup; } @@ -290,7 +299,7 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver, ret = 0; cleanup: - virObjectUnlock(driver->activeScsiHostdevs); + virObjectUnlock(mgr->activeScsiHostdevs); return ret; } @@ -657,12 +666,16 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, size_t i; int ret = -1; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + virHostdevManagerPtr hostdev_mgr; if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps)) - goto cleanup; + goto out; - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto out; + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs))) goto cleanup; @@ -690,9 +703,9 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, goto cleanup; } /* The device is in use by other active domain if - * the dev is in list driver->activePciHostdevs. + * the dev is in list activePciHostdevs. */ - if ((other = virPCIDeviceListFind(driver->activePciHostdevs, dev))) { + if ((other = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev))) { const char *other_drvname; const char *other_domname; @@ -715,7 +728,7 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); if (virPCIDeviceGetManaged(dev) && - virPCIDeviceDetach(dev, driver->activePciHostdevs, NULL) < 0) + virPCIDeviceDetach(dev, hostdev_mgr->activePciHostdevs, NULL) < 0) goto reattachdevs; } @@ -724,8 +737,8 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - if (virPCIDeviceReset(dev, driver->activePciHostdevs, - driver->inactivePciHostdevs) < 0) + if (virPCIDeviceReset(dev, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) goto reattachdevs; } @@ -750,24 +763,24 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, /* Loop 5: Now mark all the devices as active */ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0) + if (virPCIDeviceListAdd(hostdev_mgr->activePciHostdevs, dev) < 0) goto inactivedevs; } /* Loop 6: Now remove the devices from inactive list. */ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - virPCIDeviceListDel(driver->inactivePciHostdevs, dev); + virPCIDeviceListDel(hostdev_mgr->inactivePciHostdevs, dev); } /* Loop 7: Now set the used_by_domain of the device in - * driver->activePciHostdevs as domain name. + * activePciHostdevs as domain name. */ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev, activeDev; dev = virPCIDeviceListGet(pcidevs, i); - activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev); + activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev); if (activeDev) virPCIDeviceSetUsedBy(activeDev, QEMU_DRIVER_NAME, name); @@ -813,12 +826,12 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, goto cleanup; inactivedevs: - /* Only steal all the devices from driver->activePciHostdevs. We will + /* Only steal all the devices from activePciHostdevs. We will * free them in virObjectUnref(). */ for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - virPCIDeviceListSteal(driver->activePciHostdevs, dev); + virPCIDeviceListSteal(hostdev_mgr->activePciHostdevs, dev); } resetvfnetconfig: @@ -833,14 +846,15 @@ reattachdevs: /* NB: This doesn't actually re-bind to original driver, just * unbinds from the stub driver */ - ignore_value(virPCIDeviceReattach(dev, driver->activePciHostdevs, + ignore_value(virPCIDeviceReattach(dev, hostdev_mgr->activePciHostdevs, NULL)); } cleanup: - virObjectUnlock(driver->activePciHostdevs); - virObjectUnlock(driver->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); virObjectUnref(pcidevs); +out: virObjectUnref(cfg); return ret; } @@ -855,12 +869,12 @@ qemuPrepareHostdevUSBDevices(virHostdevManagerPtr mgr, unsigned int count; virUSBDevicePtr tmp; - virObjectLock(driver->activeUsbHostdevs); + virObjectLock(mgr->activeUsbHostdevs); count = virUSBDeviceListCount(list); for (i = 0; i < count; i++) { virUSBDevicePtr usb = virUSBDeviceListGet(list, i); - if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) { + if ((tmp = virUSBDeviceListFind(mgr->activeUsbHostdevs, usb))) { const char *other_drvname; const char *other_domname; @@ -886,19 +900,19 @@ qemuPrepareHostdevUSBDevices(virHostdevManagerPtr mgr, * from the virUSBDeviceList that passed in on success, * perform rollback on failure. */ - if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) + if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0) goto error; } - virObjectUnlock(driver->activeUsbHostdevs); + virObjectUnlock(mgr->activeUsbHostdevs); return 0; error: for (j = 0; j < i; j++) { tmp = virUSBDeviceListGet(list, i); - virUSBDeviceListSteal(driver->activeUsbHostdevs, tmp); + virUSBDeviceListSteal(mgr->activeUsbHostdevs, tmp); } - virObjectUnlock(driver->activeUsbHostdevs); + virObjectUnlock(mgr->activeUsbHostdevs); return -1; } @@ -992,7 +1006,7 @@ out: int -qemuPrepareHostUSBDevices(virQEMUDriverPtr driver, +qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def, bool coldBoot) { @@ -1002,6 +1016,7 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver, virUSBDevicePtr tmp; virDomainHostdevDefPtr *hostdevs = def->hostdevs; int nhostdevs = def->nhostdevs; + virHostdevManagerPtr hostdev_mgr; /* To prevent situation where USB device is assigned to two domains * we need to keep a list of currently assigned USB devices. @@ -1041,7 +1056,10 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver, * and add them do driver list. However, if something goes * wrong, perform rollback. */ - if (qemuPrepareHostdevUSBDevices(driver, def->name, list) < 0) + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto cleanup; + if (qemuPrepareHostdevUSBDevices(hostdev_mgr, def->name, list) < 0) goto cleanup; /* Loop 2: Temporary list was successfully merged with @@ -1071,6 +1089,7 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, int count; virSCSIDeviceListPtr list; virSCSIDevicePtr tmp; + virHostdevManagerPtr hostdev_mgr; /* Loop 1: Add the shared scsi host device to shared device * table. @@ -1130,12 +1149,16 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, * and add them to driver list. However, if something goes * wrong, perform rollback. */ - virObjectLock(driver->activeScsiHostdevs); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto cleanup; + virObjectLock(hostdev_mgr->activeScsiHostdevs); count = virSCSIDeviceListCount(list); for (i = 0; i < count; i++) { virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i); - if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) { + if ((tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, + scsi))) { bool scsi_shareable = virSCSIDeviceGetShareable(scsi); bool tmp_shareable = virSCSIDeviceGetShareable(tmp); @@ -1156,12 +1179,12 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); - if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) + if (virSCSIDeviceListAdd(hostdev_mgr->activeScsiHostdevs, scsi) < 0) goto error; } } - virObjectUnlock(driver->activeScsiHostdevs); + virObjectUnlock(hostdev_mgr->activeScsiHostdevs); /* Loop 4: Temporary list was successfully merged with * driver list, so steal all items to avoid freeing them @@ -1178,9 +1201,9 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, error: for (j = 0; j < i; j++) { tmp = virSCSIDeviceListGet(list, i); - virSCSIDeviceListSteal(driver->activeScsiHostdevs, tmp); + virSCSIDeviceListSteal(hostdev_mgr->activeScsiHostdevs, tmp); } - virObjectUnlock(driver->activeScsiHostdevs); + virObjectUnlock(hostdev_mgr->activeScsiHostdevs); cleanup: virObjectUnref(list); return -1; @@ -1213,11 +1236,11 @@ qemuPrepareHostDevices(virQEMUDriverPtr driver, /* - * Pre-condition: driver->inactivePciHostdevs & driver->activePciHostdevs + * Pre-condition: inactivePciHostdevs & activePciHostdevs * are locked */ static void -qemuReattachPciDevice(virPCIDevicePtr dev, QEMUDriverPtr driver) +qemuReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) { int retries = 100; @@ -1225,7 +1248,7 @@ qemuReattachPciDevice(virPCIDevicePtr dev, QEMUDriverPtr driver) * successfully, it must have been inactive. */ if (!virPCIDeviceGetManaged(dev)) { - if (virPCIDeviceListAdd(driver->inactivePciHostdevs, dev) < 0) + if (virPCIDeviceListAdd(mgr->inactivePciHostdevs, dev) < 0) virPCIDeviceFree(dev); return; } @@ -1236,8 +1259,8 @@ qemuReattachPciDevice(virPCIDevicePtr dev, QEMUDriverPtr driver) retries--; } - if (virPCIDeviceReattach(dev, driver->activePciHostdevs, - driver->inactivePciHostdevs) < 0) { + if (virPCIDeviceReattach(dev, mgr->activePciHostdevs, + mgr->inactivePciHostdevs) < 0) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to re-attach PCI device: %s"), err ? err->message : _("unknown error")); @@ -1256,11 +1279,15 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, virPCIDeviceListPtr pcidevs; size_t i; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + virHostdevManagerPtr hostdev_mgr; - virObjectLock(driver->activePciHostdevs); - virObjectLock(driver->inactivePciHostdevs); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto out; + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); - if (!(pcidevs = qemuGetActivePciHostDeviceList(driver, + if (!(pcidevs = qemuGetActivePciHostDeviceList(hostdev_mgr, hostdevs, nhostdevs))) { virErrorPtr err = virGetLastError(); @@ -1282,7 +1309,7 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, * other domain. Or delete it from activePciHostDevs if it had * been used by this domain. */ - activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev); + activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev); if (activeDev) { const char *usedby_drvname; const char *usedby_domname; @@ -1294,7 +1321,7 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, } } - virPCIDeviceListDel(driver->activePciHostdevs, dev); + virPCIDeviceListDel(hostdev_mgr->activePciHostdevs, dev); } /* At this point, any device that had been used by the guest is in @@ -1311,8 +1338,8 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - if (virPCIDeviceReset(dev, driver->activePciHostdevs, - driver->inactivePciHostdevs) < 0) { + if (virPCIDeviceReset(dev, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to reset PCI device: %s"), err ? err->message : _("unknown error")); @@ -1322,26 +1349,32 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, while (virPCIDeviceListCount(pcidevs) > 0) { virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0); - qemuReattachPciDevice(dev, driver); + qemuReattachPciDevice(dev, hostdev_mgr); } virObjectUnref(pcidevs); cleanup: - virObjectUnlock(driver->activePciHostdevs); - virObjectUnlock(driver->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); +out: virObjectUnref(cfg); } void -qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, +qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { size_t i; + virHostdevManagerPtr hostdev_mgr; - virObjectLock(driver->activeUsbHostdevs); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return; + + virObjectLock(hostdev_mgr->activeUsbHostdevs); for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; virUSBDevicePtr usb, tmp; @@ -1373,7 +1406,7 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, * Therefore we want to steal only those devices from * the list which were taken by @name */ - tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb); + tmp = virUSBDeviceListFind(hostdev_mgr->activeUsbHostdevs, usb); virUSBDeviceFree(usb); if (!tmp) { @@ -1392,10 +1425,10 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, hostdev->source.subsys.u.usb.device, name); - virUSBDeviceListDel(driver->activeUsbHostdevs, tmp); + virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, tmp); } } - virObjectUnlock(driver->activeUsbHostdevs); + virObjectUnlock(hostdev_mgr->activeUsbHostdevs); } @@ -1406,8 +1439,13 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, int nhostdevs) { size_t i; + virHostdevManagerPtr hostdev_mgr; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return; - virObjectLock(driver->activeScsiHostdevs); + virObjectLock(hostdev_mgr->activeScsiHostdevs); for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; virSCSIDevicePtr scsi; @@ -1442,7 +1480,7 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, /* Only delete the devices which are marked as being used by @name, * because qemuProcessStart could fail on the half way. */ - if (!(tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) { + if (!(tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, scsi))) { VIR_WARN("Unable to find device %s:%d:%d:%d " "in list of active SCSI devices", hostdev->source.subsys.u.scsi.adapter, @@ -1460,10 +1498,10 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, hostdev->source.subsys.u.scsi.unit, name); - virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp, QEMU_DRIVER_NAME, name); + virSCSIDeviceListDel(hostdev_mgr->activeScsiHostdevs, tmp, QEMU_DRIVER_NAME, name); virSCSIDeviceFree(scsi); } - virObjectUnlock(driver->activeScsiHostdevs); + virObjectUnlock(hostdev_mgr->activeScsiHostdevs); } void diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 5546693..eeb1f24 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -50,6 +50,7 @@ #include "virstoragefile.h" #include "virstring.h" #include "virtime.h" +#include "virhostdev.h" #define VIR_FROM_THIS VIR_FROM_QEMU #define CHANGE_MEDIA_RETRIES 10 -- 1.6.0.2

On Sat, Mar 01, 2014 at 02:29:00PM +0800, Chunyan Liu wrote:
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_conf.h | 8 -- src/qemu/qemu_driver.c | 74 +++++++++---------- src/qemu/qemu_hostdev.c | 192 ++++++++++++++++++++++++++++------------------- src/qemu/qemu_hotplug.c | 1 + 4 files changed, 151 insertions(+), 124 deletions(-)
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index ece185b..2ac88fb 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -215,14 +215,6 @@ struct _virQEMUDriver { /* Immutable pointer. self-locking APIs */ virSecurityManagerPtr securityManager;
- /* Immutable pointers. Requires locks to be held before - * calling APIs. activePciHostdevs must be locked before - * inactivePciHostdevs */ - virPCIDeviceListPtr activePciHostdevs; - virPCIDeviceListPtr inactivePciHostdevs; - virUSBDeviceListPtr activeUsbHostdevs; - virSCSIDeviceListPtr activeScsiHostdevs; - /* Immutable pointer. Unsafe APIs. XXX */ virHashTablePtr sharedDevices;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f36a8b4..7d924b2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -95,6 +95,7 @@ #include "viraccessapicheck.h" #include "viraccessapicheckqemu.h" #include "storage/storage_driver.h" +#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -695,18 +696,6 @@ qemuStateInitialize(bool privileged, if (qemuSecurityInit(qemu_driver) < 0) goto error;
- if ((qemu_driver->activePciHostdevs = virPCIDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL) - goto error; -
I think we should obtain the hostdev manager instance here, and save a reference to it, so that later functions do not need to worry about failure of virHostdevManagerGetDefault()
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 5546693..eeb1f24 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -50,6 +50,7 @@ #include "virstoragefile.h" #include "virstring.h" #include "virtime.h" +#include "virhostdev.h"
This seems bogus as you're not adding any code to this file which would use those APIs Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

2014-03-04 20:38 GMT+08:00 Daniel P. Berrange <berrange@redhat.com>:
On Sat, Mar 01, 2014 at 02:29:00PM +0800, Chunyan Liu wrote:
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_conf.h | 8 -- src/qemu/qemu_driver.c | 74 +++++++++---------- src/qemu/qemu_hostdev.c | 192
++++++++++++++++++++++++++++-------------------
src/qemu/qemu_hotplug.c | 1 + 4 files changed, 151 insertions(+), 124 deletions(-)
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index ece185b..2ac88fb 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -215,14 +215,6 @@ struct _virQEMUDriver { /* Immutable pointer. self-locking APIs */ virSecurityManagerPtr securityManager;
- /* Immutable pointers. Requires locks to be held before - * calling APIs. activePciHostdevs must be locked before - * inactivePciHostdevs */ - virPCIDeviceListPtr activePciHostdevs; - virPCIDeviceListPtr inactivePciHostdevs; - virUSBDeviceListPtr activeUsbHostdevs; - virSCSIDeviceListPtr activeScsiHostdevs; - /* Immutable pointer. Unsafe APIs. XXX */ virHashTablePtr sharedDevices;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f36a8b4..7d924b2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -95,6 +95,7 @@ #include "viraccessapicheck.h" #include "viraccessapicheckqemu.h" #include "storage/storage_driver.h" +#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -695,18 +696,6 @@ qemuStateInitialize(bool privileged, if (qemuSecurityInit(qemu_driver) < 0) goto error;
- if ((qemu_driver->activePciHostdevs = virPCIDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL) - goto error; -
I think we should obtain the hostdev manager instance here, and save a reference to it, so that later functions do not need to worry about failure of virHostdevManagerGetDefault()
we could: add .hostdev_mgr to _virQEMUDriver, and add qemu_driver->hostdev_mgr = virHostdevManagerGetDefault() here. Is that OK?
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 5546693..eeb1f24 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -50,6 +50,7 @@ #include "virstoragefile.h" #include "virstring.h" #include "virtime.h" +#include "virhostdev.h"
This seems bogus as you're not adding any code to this file which would use those APIs
Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/:| |: http://libvirt.org -o- http://virt-manager.org:| |: http://autobuild.org -o- http://search.cpan.org/~danberr/:| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc:|

On Wed, Mar 05, 2014 at 04:03:19PM +0800, Chunyan Liu wrote:
2014-03-04 20:38 GMT+08:00 Daniel P. Berrange <berrange@redhat.com>:
On Sat, Mar 01, 2014 at 02:29:00PM +0800, Chunyan Liu wrote:
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_conf.h | 8 -- src/qemu/qemu_driver.c | 74 +++++++++---------- src/qemu/qemu_hostdev.c | 192
++++++++++++++++++++++++++++-------------------
src/qemu/qemu_hotplug.c | 1 + 4 files changed, 151 insertions(+), 124 deletions(-)
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index ece185b..2ac88fb 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -215,14 +215,6 @@ struct _virQEMUDriver { /* Immutable pointer. self-locking APIs */ virSecurityManagerPtr securityManager;
- /* Immutable pointers. Requires locks to be held before - * calling APIs. activePciHostdevs must be locked before - * inactivePciHostdevs */ - virPCIDeviceListPtr activePciHostdevs; - virPCIDeviceListPtr inactivePciHostdevs; - virUSBDeviceListPtr activeUsbHostdevs; - virSCSIDeviceListPtr activeScsiHostdevs; - /* Immutable pointer. Unsafe APIs. XXX */ virHashTablePtr sharedDevices;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f36a8b4..7d924b2 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -95,6 +95,7 @@ #include "viraccessapicheck.h" #include "viraccessapicheckqemu.h" #include "storage/storage_driver.h" +#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -695,18 +696,6 @@ qemuStateInitialize(bool privileged, if (qemuSecurityInit(qemu_driver) < 0) goto error;
- if ((qemu_driver->activePciHostdevs = virPCIDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL) - goto error; - - if ((qemu_driver->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL) - goto error; -
I think we should obtain the hostdev manager instance here, and save a reference to it, so that later functions do not need to worry about failure of virHostdevManagerGetDefault()
we could: add .hostdev_mgr to _virQEMUDriver, and add qemu_driver->hostdev_mgr = virHostdevManagerGetDefault() here. Is that OK?
Yes, that would be good, and the same for LXC + libxl drivers too. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/lxc/lxc_conf.h | 4 ---- src/lxc/lxc_driver.c | 17 +++++++++-------- src/lxc/lxc_hostdev.c | 49 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index e04dcdd..5be159b 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -93,10 +93,6 @@ struct _virLXCDriver { /* Immutable pointer, self-locking APIs */ virDomainObjListPtr domains; - /* Immutable pointer. Requires lock to be held before - * calling APIs. */ - virUSBDeviceListPtr activeUsbHostdevs; - /* Immutable pointer, self-locking APIs */ virObjectEventStatePtr domainEventState; diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 10e0fbb..f67a236 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -71,6 +71,7 @@ #include "virstring.h" #include "viraccessapicheck.h" #include "viraccessapichecklxc.h" +#include "virhostdev.h" #define VIR_FROM_THIS VIR_FROM_LXC @@ -1557,9 +1558,6 @@ static int lxcStateInitialize(bool privileged, if (!(lxc_driver->securityManager = lxcSecurityInit(cfg))) goto cleanup; - if ((lxc_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) - goto cleanup; - if ((virLXCDriverGetCapabilities(lxc_driver, true)) == NULL) goto cleanup; @@ -1674,7 +1672,6 @@ static int lxcStateCleanup(void) virSysinfoDefFree(lxc_driver->hostsysinfo); - virObjectUnref(lxc_driver->activeUsbHostdevs); virObjectUnref(lxc_driver->caps); virObjectUnref(lxc_driver->securityManager); virObjectUnref(lxc_driver->xmlopt); @@ -4688,7 +4685,7 @@ cleanup: static int -lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, +lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver ATTRIBUTE_UNUSED, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { @@ -4697,6 +4694,7 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, int idx, ret = -1; char *dst = NULL; virUSBDevicePtr usb = NULL; + virHostdevManagerPtr hostdev_mgr; if ((idx = virDomainHostdevFind(vm->def, dev->data.hostdev, @@ -4733,9 +4731,12 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, VIR_WARN("cannot deny device %s for domain %s", dst, vm->def->name); - virObjectLock(driver->activeUsbHostdevs); - virUSBDeviceListDel(driver->activeUsbHostdevs, usb); - virObjectUnlock(driver->activeUsbHostdevs); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto cleanup; + virObjectLock(hostdev_mgr->activeUsbHostdevs); + virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, usb); + virObjectUnlock(hostdev_mgr->activeUsbHostdevs); virDomainHostdevRemove(vm->def, idx); virDomainHostdevDefFree(def); diff --git a/src/lxc/lxc_hostdev.c b/src/lxc/lxc_hostdev.c index b7248df..8398646 100644 --- a/src/lxc/lxc_hostdev.c +++ b/src/lxc/lxc_hostdev.c @@ -27,19 +27,25 @@ #include "viralloc.h" #include "virlog.h" #include "virerror.h" +#include "virhostdev.h" #define VIR_FROM_THIS VIR_FROM_LXC int -virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver, +virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) { virDomainHostdevDefPtr hostdev = NULL; size_t i; + virHostdevManagerPtr hostdev_mgr; if (!def->nhostdevs) return 0; + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return -1; + for (i = 0; i < def->nhostdevs; i++) { virUSBDevicePtr usb = NULL; hostdev = def->hostdevs[i]; @@ -62,13 +68,13 @@ virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver, virUSBDeviceSetUsedBy(usb, LXC_DRIVER_NAME, def->name); - virObjectLock(driver->activeUsbHostdevs); - if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) { - virObjectUnlock(driver->activeUsbHostdevs); + virObjectLock(hostdev_mgr->activeUsbHostdevs); + if (virUSBDeviceListAdd(hostdev_mgr->activeUsbHostdevs, usb) < 0) { + virObjectUnlock(hostdev_mgr->activeUsbHostdevs); virUSBDeviceFree(usb); return -1; } - virObjectUnlock(driver->activeUsbHostdevs); + virObjectUnlock(hostdev_mgr->activeUsbHostdevs); } return 0; @@ -76,20 +82,24 @@ virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver, int -virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver, +virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver ATTRIBUTE_UNUSED, const char *name, virUSBDeviceList *list) { size_t i, j; unsigned int count; virUSBDevicePtr tmp; + virHostdevManagerPtr hostdev_mgr; count = virUSBDeviceListCount(list); - virObjectLock(driver->activeUsbHostdevs); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return -1; + virObjectLock(hostdev_mgr->activeUsbHostdevs); for (i = 0; i < count; i++) { virUSBDevicePtr usb = virUSBDeviceListGet(list, i); - if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) { + if ((tmp = virUSBDeviceListFind(hostdev_mgr->activeUsbHostdevs, usb))) { const char *other_drvname; const char *other_domname; @@ -115,18 +125,18 @@ virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver, * from the virUSBDeviceList that passed in on success, * perform rollback on failure. */ - if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) + if (virUSBDeviceListAdd(hostdev_mgr->activeUsbHostdevs, usb) < 0) goto error; } - virObjectUnlock(driver->activeUsbHostdevs); + virObjectUnlock(hostdev_mgr->activeUsbHostdevs); return 0; error: for (j = 0; j < i; j++) { tmp = virUSBDeviceListGet(list, i); - virUSBDeviceListSteal(driver->activeUsbHostdevs, tmp); + virUSBDeviceListSteal(hostdev_mgr->activeUsbHostdevs, tmp); } - virObjectUnlock(driver->activeUsbHostdevs); + virObjectUnlock(hostdev_mgr->activeUsbHostdevs); return -1; } @@ -344,14 +354,19 @@ int virLXCPrepareHostDevices(virLXCDriverPtr driver, static void -virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr driver, +virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr driver ATTRIBUTE_UNUSED, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { size_t i; + virHostdevManagerPtr hostdev_mgr; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return; - virObjectLock(driver->activeUsbHostdevs); + virObjectLock(hostdev_mgr->activeUsbHostdevs); for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; virUSBDevicePtr usb, tmp; @@ -383,7 +398,7 @@ virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr driver, * Therefore we want to steal only those devices from * the list which were taken by @name */ - tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb); + tmp = virUSBDeviceListFind(hostdev_mgr->activeUsbHostdevs, usb); virUSBDeviceFree(usb); if (!tmp) { @@ -402,10 +417,10 @@ virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr driver, hostdev->source.subsys.u.usb.device, name); - virUSBDeviceListDel(driver->activeUsbHostdevs, tmp); + virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, tmp); } } - virObjectUnlock(driver->activeUsbHostdevs); + virObjectUnlock(hostdev_mgr->activeUsbHostdevs); } void virLXCDomainReAttachHostDevices(virLXCDriverPtr driver, -- 1.6.0.2

On Sat, Mar 01, 2014 at 02:29:01PM +0800, Chunyan Liu wrote:
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/lxc/lxc_conf.h | 4 ---- src/lxc/lxc_driver.c | 17 +++++++++-------- src/lxc/lxc_hostdev.c | 49 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 41 insertions(+), 29 deletions(-)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Sat, Mar 01, 2014 at 02:29:01PM +0800, Chunyan Liu wrote:
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/lxc/lxc_conf.h | 4 ---- src/lxc/lxc_driver.c | 17 +++++++++-------- src/lxc/lxc_hostdev.c | 49 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 41 insertions(+), 29 deletions(-)
diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index e04dcdd..5be159b 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -93,10 +93,6 @@ struct _virLXCDriver { /* Immutable pointer, self-locking APIs */ virDomainObjListPtr domains;
- /* Immutable pointer. Requires lock to be held before - * calling APIs. */ - virUSBDeviceListPtr activeUsbHostdevs; - /* Immutable pointer, self-locking APIs */ virObjectEventStatePtr domainEventState;
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index 10e0fbb..f67a236 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -71,6 +71,7 @@ #include "virstring.h" #include "viraccessapicheck.h" #include "viraccessapichecklxc.h" +#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_LXC
@@ -1557,9 +1558,6 @@ static int lxcStateInitialize(bool privileged, if (!(lxc_driver->securityManager = lxcSecurityInit(cfg))) goto cleanup;
- if ((lxc_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) - goto cleanup;
I think it would be desirable to call virHostdevManagerGetDefault() here and save the pointer to the mgr in lxc_driver->hostdevmgr. That avoids the later functions having to worry about failure of the virHostdevManagerGetDefault function
- if ((virLXCDriverGetCapabilities(lxc_driver, true)) == NULL) goto cleanup;
@@ -1674,7 +1672,6 @@ static int lxcStateCleanup(void)
virSysinfoDefFree(lxc_driver->hostsysinfo);
- virObjectUnref(lxc_driver->activeUsbHostdevs); virObjectUnref(lxc_driver->caps); virObjectUnref(lxc_driver->securityManager); virObjectUnref(lxc_driver->xmlopt); @@ -4688,7 +4685,7 @@ cleanup:
static int -lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, +lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver ATTRIBUTE_UNUSED, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { @@ -4697,6 +4694,7 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, int idx, ret = -1; char *dst = NULL; virUSBDevicePtr usb = NULL; + virHostdevManagerPtr hostdev_mgr;
if ((idx = virDomainHostdevFind(vm->def, dev->data.hostdev, @@ -4733,9 +4731,12 @@ lxcDomainDetachDeviceHostdevUSBLive(virLXCDriverPtr driver, VIR_WARN("cannot deny device %s for domain %s", dst, vm->def->name);
- virObjectLock(driver->activeUsbHostdevs); - virUSBDeviceListDel(driver->activeUsbHostdevs, usb); - virObjectUnlock(driver->activeUsbHostdevs); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto cleanup; + virObjectLock(hostdev_mgr->activeUsbHostdevs); + virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, usb); + virObjectUnlock(hostdev_mgr->activeUsbHostdevs);
Hmm, on second look, this 'goto cleanup' here is a problem - we've already done the detach at this point, so we can't tolerate failure. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

For extracting hostdev codes from qemu_hostdev.c to common library, change qemu specific cfg->relaxedACS handling to be a flag, and pass it to hostdev functions. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 11 +++++++---- src/qemu/qemu_hostdev.h | 10 ++++++++-- src/qemu/qemu_hotplug.c | 11 +++++++++-- src/qemu/qemu_process.c | 5 ++++- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 54ac973..5f2dc44 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -659,7 +659,8 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, const unsigned char *uuid, virDomainHostdevDefPtr *hostdevs, int nhostdevs, - virQEMUCapsPtr qemuCaps) + virQEMUCapsPtr qemuCaps, + unsigned int flags) { virPCIDeviceListPtr pcidevs = NULL; int last_processed_hostdev_vf = -1; @@ -695,8 +696,9 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); virPCIDevicePtr other; + bool strict_acs_check = !!(flags & VIR_STRICT_ACS_CHECK); - if (!virPCIDeviceIsAssignable(dev, !cfg->relaxedACS)) { + if (!virPCIDeviceIsAssignable(dev, strict_acs_check)) { virReportError(VIR_ERR_OPERATION_INVALID, _("PCI device %s is not assignable"), virPCIDeviceGetName(dev)); @@ -1214,14 +1216,15 @@ int qemuPrepareHostDevices(virQEMUDriverPtr driver, virDomainDefPtr def, virQEMUCapsPtr qemuCaps, - bool coldBoot) + bool coldBoot, + unsigned int flags) { if (!def->nhostdevs) return 0; if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid, def->hostdevs, def->nhostdevs, - qemuCaps) < 0) + qemuCaps, flags) < 0) return -1; if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0) diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h index 5b34245..48ca610 100644 --- a/src/qemu/qemu_hostdev.h +++ b/src/qemu/qemu_hostdev.h @@ -27,6 +27,10 @@ # include "qemu_conf.h" # include "domain_conf.h" +typedef enum { + VIR_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */ +} virHostdevFlag; + int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver, virDomainDefPtr def); int qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver, @@ -40,7 +44,8 @@ int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, const unsigned char *uuid, virDomainHostdevDefPtr *hostdevs, int nhostdevs, - virQEMUCapsPtr qemuCaps); + virQEMUCapsPtr qemuCaps, + unsigned int flags); int qemuPrepareHostUSBDevices(virQEMUDriverPtr driver, virDomainDefPtr def, @@ -52,7 +57,8 @@ int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, int qemuPrepareHostDevices(virQEMUDriverPtr driver, virDomainDefPtr def, virQEMUCapsPtr qemuCaps, - bool coldBoot); + bool coldBoot, + unsigned int flags); void qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, const char *name, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index eeb1f24..a213929 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1155,13 +1155,17 @@ qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver, bool teardownlabel = false; int backend; unsigned long long memKB; + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + unsigned int flags = 0; if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0) return -1; + if (!cfg->relaxedACS) + flags |= VIR_STRICT_ACS_CHECK; if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid, - &hostdev, 1, priv->qemuCaps) < 0) - return -1; + &hostdev, 1, priv->qemuCaps, flags) < 0) + goto cleanup; /* this could have been changed by qemuPrepareHostdevPCIDevices */ backend = hostdev->source.subsys.u.pci.backend; @@ -1255,6 +1259,7 @@ qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver, VIR_FREE(devstr); VIR_FREE(configfd_name); VIR_FORCE_CLOSE(configfd); + virObjectUnref(cfg); return 0; @@ -1275,6 +1280,8 @@ error: VIR_FREE(configfd_name); VIR_FORCE_CLOSE(configfd); +cleanup: + virObjectUnref(cfg); return -1; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index ffa939a..47ecfe4 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3596,6 +3596,7 @@ int qemuProcessStart(virConnectPtr conn, unsigned int stop_flags; virQEMUDriverConfigPtr cfg; virCapsPtr caps = NULL; + unsigned int hostdev_flags = 0; VIR_DEBUG("vm=%p name=%s id=%d pid=%llu", vm, vm->def->name, vm->def->id, @@ -3685,8 +3686,10 @@ int qemuProcessStart(virConnectPtr conn, /* Must be run before security labelling */ VIR_DEBUG("Preparing host devices"); + if (!cfg->relaxedACS) + hostdev_flags |= VIR_STRICT_ACS_CHECK; if (qemuPrepareHostDevices(driver, vm->def, priv->qemuCaps, - !migrateFrom) < 0) + !migrateFrom, hostdev_flags) < 0) goto cleanup; VIR_DEBUG("Preparing chr devices"); -- 1.6.0.2

On Sat, Mar 01, 2014 at 02:29:02PM +0800, Chunyan Liu wrote:
For extracting hostdev codes from qemu_hostdev.c to common library, change qemu specific cfg->relaxedACS handling to be a flag, and pass it to hostdev functions.
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 11 +++++++---- src/qemu/qemu_hostdev.h | 10 ++++++++-- src/qemu/qemu_hotplug.c | 11 +++++++++-- src/qemu/qemu_process.c | 5 ++++- 4 files changed, 28 insertions(+), 9 deletions(-)
ACK Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

For extracting hostdev codes from qemu_hostdev.c to common library, change qemu specific COLD_BOOT handling to be a flag, and pass it to hostdev functions. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 6 +++--- src/qemu/qemu_hostdev.h | 4 ++-- src/qemu/qemu_process.c | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 5f2dc44..6be58ef 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -1010,7 +1010,7 @@ out: int qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def, - bool coldBoot) + unsigned int flags) { size_t i; int ret = -1; @@ -1019,6 +1019,7 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainHostdevDefPtr *hostdevs = def->hostdevs; int nhostdevs = def->nhostdevs; virHostdevManagerPtr hostdev_mgr; + 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. @@ -1216,7 +1217,6 @@ int qemuPrepareHostDevices(virQEMUDriverPtr driver, virDomainDefPtr def, virQEMUCapsPtr qemuCaps, - bool coldBoot, unsigned int flags) { if (!def->nhostdevs) @@ -1227,7 +1227,7 @@ qemuPrepareHostDevices(virQEMUDriverPtr driver, qemuCaps, flags) < 0) return -1; - if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0) + if (qemuPrepareHostUSBDevices(driver, def, flags) < 0) return -1; if (qemuPrepareHostdevSCSIDevices(driver, def->name, diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h index 48ca610..c137302 100644 --- a/src/qemu/qemu_hostdev.h +++ b/src/qemu/qemu_hostdev.h @@ -29,6 +29,7 @@ typedef enum { VIR_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */ + VIR_COLD_BOOT = (1 << 1), /* cold boot */ } virHostdevFlag; int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver, @@ -49,7 +50,7 @@ int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, int qemuPrepareHostUSBDevices(virQEMUDriverPtr driver, virDomainDefPtr def, - bool coldBoot); + unsigned int flags); int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, const char *name, virDomainHostdevDefPtr *hostdevs, @@ -57,7 +58,6 @@ int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, int qemuPrepareHostDevices(virQEMUDriverPtr driver, virDomainDefPtr def, virQEMUCapsPtr qemuCaps, - bool coldBoot, unsigned int flags); void qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 47ecfe4..3fbe4d1 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3688,8 +3688,10 @@ int qemuProcessStart(virConnectPtr conn, VIR_DEBUG("Preparing host devices"); if (!cfg->relaxedACS) hostdev_flags |= VIR_STRICT_ACS_CHECK; + if (!migrateFrom) + hostdev_flags |= VIR_COLD_BOOT; if (qemuPrepareHostDevices(driver, vm->def, priv->qemuCaps, - !migrateFrom, hostdev_flags) < 0) + hostdev_flags) < 0) goto cleanup; VIR_DEBUG("Preparing chr devices"); -- 1.6.0.2

On Sat, Mar 01, 2014 at 02:29:03PM +0800, Chunyan Liu wrote:
For extracting hostdev codes from qemu_hostdev.c to common library, change qemu specific COLD_BOOT handling to be a flag, and pass it to hostdev functions.
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 6 +++--- src/qemu/qemu_hostdev.h | 4 ++-- src/qemu/qemu_process.c | 4 +++- 3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 5f2dc44..6be58ef 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -1010,7 +1010,7 @@ out: int qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def, - bool coldBoot) + unsigned int flags) { size_t i; int ret = -1; @@ -1019,6 +1019,7 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainHostdevDefPtr *hostdevs = def->hostdevs; int nhostdevs = def->nhostdevs; virHostdevManagerPtr hostdev_mgr; + 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. @@ -1216,7 +1217,6 @@ int qemuPrepareHostDevices(virQEMUDriverPtr driver, virDomainDefPtr def, virQEMUCapsPtr qemuCaps, - bool coldBoot, unsigned int flags) { if (!def->nhostdevs) @@ -1227,7 +1227,7 @@ qemuPrepareHostDevices(virQEMUDriverPtr driver, qemuCaps, flags) < 0) return -1;
- if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0) + if (qemuPrepareHostUSBDevices(driver, def, flags) < 0) return -1;
if (qemuPrepareHostdevSCSIDevices(driver, def->name, diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h index 48ca610..c137302 100644 --- a/src/qemu/qemu_hostdev.h +++ b/src/qemu/qemu_hostdev.h @@ -29,6 +29,7 @@
typedef enum { VIR_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */ + VIR_COLD_BOOT = (1 << 1), /* cold boot */ } virHostdevFlag;
Hmm, please namespace these flags properly eg VIR_HOSTDEV_STRICT_ACS_CHECK VIR_HOSTDEV_COLD_BOOT Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

Hi Daniel, Chunyan, On Tue, 2014-03-04 at 12:41 +0000, Daniel P. Berrange wrote:
On Sat, Mar 01, 2014 at 02:29:03PM +0800, Chunyan Liu wrote:
typedef enum { VIR_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */ + VIR_COLD_BOOT = (1 << 1), /* cold boot */ } virHostdevFlag;
Hmm, please namespace these flags properly eg
VIR_HOSTDEV_STRICT_ACS_CHECK VIR_HOSTDEV_COLD_BOOT
Fixed and rebased the whole series on my github branch. -- Cedric

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 27 +++++++++++++++++++-------- 1 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 6be58ef..4a36417 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -473,10 +473,17 @@ cleanup: return ret; } - +/* @oldStateDir: + * For upgrade purpose: + * To an existing VM on QEMU, the hostdev netconfig file is originally stored + * in cfg->stateDir (/var/run/libvirt/qemu). Switch to new version, it uses new + * location (hostdev_mgr->stateDir) but certainly will not find it. In this + * case, try to find in the old state dir. + */ static int qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, - char *stateDir) + char *stateDir, + char *oldStateDir) { char *linkdev = NULL; virNetDevVPortProfilePtr virtPort; @@ -511,8 +518,11 @@ qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, &hostdev->parent.data.net->mac, NULL, port_profile_associate); - else + else { ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir); + if (ret < 0 && oldStateDir != NULL) + ret = virNetDevRestoreNetConfig(linkdev, vf, oldStateDir); + } VIR_FREE(linkdev); @@ -666,7 +676,6 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, int last_processed_hostdev_vf = -1; size_t i; int ret = -1; - virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virHostdevManagerPtr hostdev_mgr; if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps)) @@ -755,7 +764,7 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && hostdev->parent.data.net) { if (qemuDomainHostdevNetConfigReplace(hostdev, uuid, - cfg->stateDir) < 0) { + hostdev_mgr->stateDir) < 0) { goto resetvfnetconfig; } } @@ -839,7 +848,8 @@ inactivedevs: resetvfnetconfig: for (i = 0; last_processed_hostdev_vf != -1 && i < last_processed_hostdev_vf; i++) - qemuDomainHostdevNetConfigRestore(hostdevs[i], cfg->stateDir); + qemuDomainHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, + NULL); reattachdevs: for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { @@ -857,7 +867,6 @@ cleanup: virObjectUnlock(hostdev_mgr->inactivePciHostdevs); virObjectUnref(pcidevs); out: - virObjectUnref(cfg); return ret; } @@ -1282,6 +1291,7 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, virPCIDeviceListPtr pcidevs; size_t i; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + char *oldStateDir = cfg->stateDir; virHostdevManagerPtr hostdev_mgr; hostdev_mgr = virHostdevManagerGetDefault(); @@ -1336,7 +1346,8 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, * reset and reattach device */ for (i = 0; i < nhostdevs; i++) - qemuDomainHostdevNetConfigRestore(hostdevs[i], cfg->stateDir); + qemuDomainHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, + oldStateDir); for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); -- 1.6.0.2

Extract general code from qemuPrepareHostdevPCIDevices to virHostdevPrepareHostdevPCIDevices. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 49 +++++++++++++++++++++++++++++++--------------- 1 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 4a36417..76e3978 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -662,28 +662,19 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs, return true; } - -int -qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver, - const char *name, - const unsigned char *uuid, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs, - virQEMUCapsPtr qemuCaps, - unsigned int flags) +static int +virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, + const char *name, + const unsigned char *uuid, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + unsigned int flags) { virPCIDeviceListPtr pcidevs = NULL; int last_processed_hostdev_vf = -1; size_t i; int ret = -1; - virHostdevManagerPtr hostdev_mgr; - if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps)) - goto out; - - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) - goto out; virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); @@ -866,6 +857,32 @@ cleanup: virObjectUnlock(hostdev_mgr->activePciHostdevs); virObjectUnlock(hostdev_mgr->inactivePciHostdevs); virObjectUnref(pcidevs); + return ret; + +} + +int +qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + const char *name, + const unsigned char *uuid, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + virQEMUCapsPtr qemuCaps, + unsigned int flags) +{ + int ret = -1; + virHostdevManagerPtr hostdev_mgr; + + if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps)) + goto out; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto out; + + ret = virHostdevPreparePCIDevices(hostdev_mgr, name, uuid, hostdevs, + nhostdevs, flags); + out: return ret; } -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 59 +++++++++++++++++++++++------------------------ 1 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 76e3978..cdad2db 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -305,8 +305,8 @@ cleanup: static int -qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, - char **sysfs_path) +virHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, + char **sysfs_path) { virPCIDeviceAddress config_address; @@ -320,12 +320,12 @@ qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, static int -qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev) +virHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev) { char *sysfs_path = NULL; int ret = -1; - if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) + if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) return ret; ret = virPCIIsVirtualFunction(sysfs_path); @@ -337,13 +337,13 @@ qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev) static int -qemuDomainHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev, - int *vf) +virHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev, + int *vf) { int ret = -1; char *sysfs_path = NULL; - if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) + if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) return ret; if (virPCIIsVirtualFunction(sysfs_path) == 1) { @@ -366,11 +366,11 @@ cleanup: static int -qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf, - virNetDevVPortProfilePtr virtPort, - const virMacAddr *macaddr, - const unsigned char *uuid, - bool associate) +virHostdevNetConfigVirtPortProfile(const char *linkdev, int vf, + virNetDevVPortProfilePtr virtPort, + const virMacAddr *macaddr, + const unsigned char *uuid, + bool associate) { int ret = -1; @@ -406,9 +406,9 @@ qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf, static int -qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, - const unsigned char *uuid, - char *stateDir) +virHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, + const unsigned char *uuid, + char *stateDir) { char *linkdev = NULL; virNetDevVlanPtr vlan; @@ -419,7 +419,7 @@ qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, bool port_profile_associate = true; int isvf; - isvf = qemuDomainHostdevIsVirtualFunction(hostdev); + isvf = virHostdevIsVirtualFunction(hostdev); if (isvf <= 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Interface type hostdev is currently supported on" @@ -427,7 +427,7 @@ qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, return ret; } - if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0) + if (virHostdevNetDevice(hostdev, &linkdev, &vf) < 0) return ret; vlan = virDomainNetGetActualVlan(hostdev->parent.data.net); @@ -441,7 +441,7 @@ qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, virNetDevVPortTypeToString(virtPort->virtPortType)); goto cleanup; } - ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, + ret = virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, &hostdev->parent.data.net->mac, uuid, port_profile_associate); } else { @@ -481,9 +481,9 @@ cleanup: * case, try to find in the old state dir. */ static int -qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, - char *stateDir, - char *oldStateDir) +virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, + char *stateDir, + char *oldStateDir) { char *linkdev = NULL; virNetDevVPortProfilePtr virtPort; @@ -501,7 +501,7 @@ qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, !hostdev->parent.data.net) return 0; - isvf = qemuDomainHostdevIsVirtualFunction(hostdev); + isvf = virHostdevIsVirtualFunction(hostdev); if (isvf <= 0) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Interface type hostdev is currently supported on" @@ -509,13 +509,13 @@ qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, return ret; } - if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0) + if (virHostdevNetDevice(hostdev, &linkdev, &vf) < 0) return ret; virtPort = virDomainNetGetActualVirtPortProfile( hostdev->parent.data.net); if (virtPort) - ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, + ret = virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, &hostdev->parent.data.net->mac, NULL, port_profile_associate); else { @@ -754,8 +754,8 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, continue; if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && hostdev->parent.data.net) { - if (qemuDomainHostdevNetConfigReplace(hostdev, uuid, - hostdev_mgr->stateDir) < 0) { + if (virHostdevNetConfigReplace(hostdev, uuid, + hostdev_mgr->stateDir) < 0) { goto resetvfnetconfig; } } @@ -839,8 +839,7 @@ inactivedevs: resetvfnetconfig: for (i = 0; last_processed_hostdev_vf != -1 && i < last_processed_hostdev_vf; i++) - qemuDomainHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, - NULL); + virHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, NULL); reattachdevs: for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { @@ -1363,8 +1362,8 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, * reset and reattach device */ for (i = 0; i < nhostdevs; i++) - qemuDomainHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, - oldStateDir); + virHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, + oldStateDir); for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 18 +++++++++--------- 1 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index cdad2db..0b1be8f 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -42,7 +42,7 @@ #define VIR_FROM_THIS VIR_FROM_QEMU static virPCIDeviceListPtr -qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) +virHostdevGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) { virPCIDeviceListPtr list; size_t i; @@ -94,7 +94,7 @@ qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) /* - * qemuGetActivePciHostDeviceList - make a new list with a *copy* of + * virHostdevGetActivePciHostDeviceList - make a new list with a *copy* of * every virPCIDevice object that is found on the activePciHostdevs * list *and* is in the hostdev list for this domain. * @@ -103,9 +103,9 @@ qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) * Pre-condition: activePciHostdevs is locked */ static virPCIDeviceListPtr -qemuGetActivePciHostDeviceList(virHostdevManagerPtr mgr, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) +virHostdevGetActivePciHostDeviceList(virHostdevManagerPtr mgr, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) { virPCIDeviceListPtr list; size_t i; @@ -678,7 +678,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); - if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs))) + if (!(pcidevs = virHostdevGetPciHostDeviceList(hostdevs, nhostdevs))) goto cleanup; /* We have to use 9 loops here. *All* devices must @@ -1316,9 +1316,9 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); - if (!(pcidevs = qemuGetActivePciHostDeviceList(hostdev_mgr, - hostdevs, - nhostdevs))) { + if (!(pcidevs = virHostdevGetActivePciHostDeviceList(hostdev_mgr, + hostdevs, + nhostdevs))) { virErrorPtr err = virGetLastError(); VIR_ERROR(_("Failed to allocate PCI device list: %s"), err ? err->message : _("unknown error")); -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 0b1be8f..bbc85bc 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -664,6 +664,7 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs, static int virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, const char *name, const unsigned char *uuid, virDomainHostdevDefPtr *hostdevs, @@ -785,7 +786,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev); if (activeDev) - virPCIDeviceSetUsedBy(activeDev, QEMU_DRIVER_NAME, name); + virPCIDeviceSetUsedBy(activeDev, drv_name, name); } /* Loop 8: Now set the original states for hostdev def */ @@ -879,7 +880,8 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (hostdev_mgr == NULL) goto out; - ret = virHostdevPreparePCIDevices(hostdev_mgr, name, uuid, hostdevs, + ret = virHostdevPreparePCIDevices(hostdev_mgr, QEMU_DRIVER_NAME, + name, uuid, hostdevs, nhostdevs, flags); out: -- 1.6.0.2

Extract general code from qemuDomainReAttachHostdevDevicesi to virHostdevReAttachPCIDevices Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 41 +++++++++++++++++++++++++++++------------ 1 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index bbc85bc..74923a1 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -1299,22 +1299,19 @@ qemuReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) virPCIDeviceFree(dev); } - -void -qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, - const char *name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) +/* @oldStateDir: + * For upgrade purpose: see virHostdevNetConfigRestore + */ +static void +virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + char *oldStateDir) { virPCIDeviceListPtr pcidevs; size_t i; - virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); - char *oldStateDir = cfg->stateDir; - virHostdevManagerPtr hostdev_mgr; - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) - goto out; virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); @@ -1388,6 +1385,26 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, cleanup: virObjectUnlock(hostdev_mgr->activePciHostdevs); virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + +} + +void +qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + char *oldStateDir = cfg->stateDir; + virHostdevManagerPtr hostdev_mgr; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto out; + + virHostdevReAttachPCIDevices(hostdev_mgr, name, + hostdevs, nhostdevs, oldStateDir); + out: virObjectUnref(cfg); } -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 74923a1..ea776ce 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -1304,6 +1304,7 @@ qemuReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) */ static void virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs, @@ -1342,7 +1343,7 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, const char *usedby_drvname; const char *usedby_domname; virPCIDeviceGetUsedBy(activeDev, &usedby_drvname, &usedby_domname); - if (STRNEQ_NULLABLE(QEMU_DRIVER_NAME, usedby_drvname) || + if (STRNEQ_NULLABLE(drv_name, usedby_drvname) || STRNEQ_NULLABLE(name, usedby_domname)) { virPCIDeviceListDel(pcidevs, dev); continue; @@ -1402,7 +1403,7 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, if (hostdev_mgr == NULL) goto out; - virHostdevReAttachPCIDevices(hostdev_mgr, name, + virHostdevReAttachPCIDevices(hostdev_mgr, QEMU_DRIVER_NAME, name, hostdevs, nhostdevs, oldStateDir); out: -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index ea776ce..8f009e1 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -1270,10 +1270,8 @@ qemuPrepareHostDevices(virQEMUDriverPtr driver, * are locked */ static void -qemuReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) +virHostdevReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) { - int retries = 100; - /* If the device is not managed and was attached to guest * successfully, it must have been inactive. */ @@ -1283,10 +1281,14 @@ qemuReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) return; } - while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device") - && retries) { - usleep(100*1000); - retries--; + /* Wait for device cleanup if it is qemu/kvm */ + if (STREQ(virPCIDeviceGetStubDriver(dev), "pci-stub")) { + int retries = 100; + while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device") + && retries) { + usleep(100*1000); + retries--; + } } if (virPCIDeviceReattach(dev, mgr->activePciHostdevs, -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libvirt_private.syms | 3 +- src/qemu/qemu_hostdev.c | 648 --------------------------------------------- src/qemu/qemu_hostdev.h | 5 - src/qemu/qemu_process.c | 1 + src/util/virhostdev.c | 649 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 25 ++ 6 files changed, 677 insertions(+), 654 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index bc048a1..410133a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1293,7 +1293,8 @@ virHookPresent; #util/virhostdev.h virHostdevManagerGetDefault; - +virHostdevPreparePCIDevices; +virHostdevReAttachPCIDevices; # util/viridentity.h virIdentityGetAttr; diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 8f009e1..b0489e2 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -41,102 +41,6 @@ #define VIR_FROM_THIS VIR_FROM_QEMU -static virPCIDeviceListPtr -virHostdevGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) -{ - virPCIDeviceListPtr list; - size_t i; - - if (!(list = virPCIDeviceListNew())) - return NULL; - - for (i = 0; i < nhostdevs; i++) { - virDomainHostdevDefPtr hostdev = hostdevs[i]; - virPCIDevicePtr dev; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - continue; - if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - continue; - - dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain, - hostdev->source.subsys.u.pci.addr.bus, - hostdev->source.subsys.u.pci.addr.slot, - hostdev->source.subsys.u.pci.addr.function); - if (!dev) { - virObjectUnref(list); - return NULL; - } - - if (virPCIDeviceListAdd(list, dev) < 0) { - virPCIDeviceFree(dev); - virObjectUnref(list); - return NULL; - } - - virPCIDeviceSetManaged(dev, hostdev->managed); - if (hostdev->source.subsys.u.pci.backend - == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { - if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) { - virObjectUnref(list); - return NULL; - } - } else { - if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) { - virObjectUnref(list); - return NULL; - } - } - } - - return list; -} - - -/* - * virHostdevGetActivePciHostDeviceList - make a new list with a *copy* of - * every virPCIDevice object that is found on the activePciHostdevs - * list *and* is in the hostdev list for this domain. - * - * Return the new list, or NULL if there was a failure. - * - * Pre-condition: activePciHostdevs is locked - */ -static virPCIDeviceListPtr -virHostdevGetActivePciHostDeviceList(virHostdevManagerPtr mgr, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) -{ - virPCIDeviceListPtr list; - size_t i; - - if (!(list = virPCIDeviceListNew())) - return NULL; - - for (i = 0; i < nhostdevs; i++) { - virDomainHostdevDefPtr hostdev = hostdevs[i]; - virDevicePCIAddressPtr addr; - virPCIDevicePtr activeDev; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - continue; - if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - continue; - - addr = &hostdev->source.subsys.u.pci.addr; - activeDev = virPCIDeviceListFindByIDs(mgr->activePciHostdevs, - addr->domain, addr->bus, - addr->slot, addr->function); - if (activeDev && virPCIDeviceListAddCopy(list, activeDev) < 0) { - virObjectUnref(list); - return NULL; - } - } - - return list; -} - - int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) @@ -304,232 +208,6 @@ cleanup: } -static int -virHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, - char **sysfs_path) -{ - virPCIDeviceAddress config_address; - - config_address.domain = hostdev->source.subsys.u.pci.addr.domain; - config_address.bus = hostdev->source.subsys.u.pci.addr.bus; - config_address.slot = hostdev->source.subsys.u.pci.addr.slot; - config_address.function = hostdev->source.subsys.u.pci.addr.function; - - return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path); -} - - -static int -virHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev) -{ - char *sysfs_path = NULL; - int ret = -1; - - if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) - return ret; - - ret = virPCIIsVirtualFunction(sysfs_path); - - VIR_FREE(sysfs_path); - - return ret; -} - - -static int -virHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev, - int *vf) -{ - int ret = -1; - char *sysfs_path = NULL; - - if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) - return ret; - - if (virPCIIsVirtualFunction(sysfs_path) == 1) { - if (virPCIGetVirtualFunctionInfo(sysfs_path, linkdev, - vf) < 0) - goto cleanup; - } else { - if (virPCIGetNetName(sysfs_path, linkdev) < 0) - goto cleanup; - *vf = -1; - } - - ret = 0; - -cleanup: - VIR_FREE(sysfs_path); - - return ret; -} - - -static int -virHostdevNetConfigVirtPortProfile(const char *linkdev, int vf, - virNetDevVPortProfilePtr virtPort, - const virMacAddr *macaddr, - const unsigned char *uuid, - bool associate) -{ - int ret = -1; - - if (!virtPort) - return ret; - - switch (virtPort->virtPortType) { - case VIR_NETDEV_VPORT_PROFILE_NONE: - case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: - case VIR_NETDEV_VPORT_PROFILE_8021QBG: - case VIR_NETDEV_VPORT_PROFILE_LAST: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("virtualport type %s is " - "currently not supported on interfaces of type " - "hostdev"), - virNetDevVPortTypeToString(virtPort->virtPortType)); - break; - - case VIR_NETDEV_VPORT_PROFILE_8021QBH: - if (associate) - ret = virNetDevVPortProfileAssociate(NULL, virtPort, macaddr, - linkdev, vf, uuid, - VIR_NETDEV_VPORT_PROFILE_OP_CREATE, false); - else - ret = virNetDevVPortProfileDisassociate(NULL, virtPort, - macaddr, linkdev, vf, - VIR_NETDEV_VPORT_PROFILE_OP_DESTROY); - break; - } - - return ret; -} - - -static int -virHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, - const unsigned char *uuid, - char *stateDir) -{ - char *linkdev = NULL; - virNetDevVlanPtr vlan; - virNetDevVPortProfilePtr virtPort; - int ret = -1; - int vf = -1; - int vlanid = -1; - bool port_profile_associate = true; - int isvf; - - isvf = virHostdevIsVirtualFunction(hostdev); - if (isvf <= 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Interface type hostdev is currently supported on" - " SR-IOV Virtual Functions only")); - return ret; - } - - if (virHostdevNetDevice(hostdev, &linkdev, &vf) < 0) - return ret; - - vlan = virDomainNetGetActualVlan(hostdev->parent.data.net); - virtPort = virDomainNetGetActualVirtPortProfile( - hostdev->parent.data.net); - if (virtPort) { - if (vlan) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("direct setting of the vlan tag is not allowed " - "for hostdev devices using %s mode"), - virNetDevVPortTypeToString(virtPort->virtPortType)); - goto cleanup; - } - ret = virHostdevNetConfigVirtPortProfile(linkdev, vf, - virtPort, &hostdev->parent.data.net->mac, uuid, - port_profile_associate); - } else { - /* Set only mac and vlan */ - if (vlan) { - if (vlan->nTags != 1 || vlan->trunk) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("vlan trunking is not supported " - "by SR-IOV network devices")); - goto cleanup; - } - if (vf == -1) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("vlan can only be set for SR-IOV VFs, but " - "%s is not a VF"), linkdev); - goto cleanup; - } - vlanid = vlan->tag[0]; - } else if (vf >= 0) { - vlanid = 0; /* assure any current vlan tag is reset */ - } - - ret = virNetDevReplaceNetConfig(linkdev, vf, - &hostdev->parent.data.net->mac, - vlanid, stateDir); - } -cleanup: - VIR_FREE(linkdev); - return ret; -} - -/* @oldStateDir: - * For upgrade purpose: - * To an existing VM on QEMU, the hostdev netconfig file is originally stored - * in cfg->stateDir (/var/run/libvirt/qemu). Switch to new version, it uses new - * location (hostdev_mgr->stateDir) but certainly will not find it. In this - * case, try to find in the old state dir. - */ -static int -virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, - char *stateDir, - char *oldStateDir) -{ - char *linkdev = NULL; - virNetDevVPortProfilePtr virtPort; - int ret = -1; - int vf = -1; - bool port_profile_associate = false; - int isvf; - - /* This is only needed for PCI devices that have been defined - * using <interface type='hostdev'>. For all others, it is a NOP. - */ - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || - hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI || - hostdev->parent.type != VIR_DOMAIN_DEVICE_NET || - !hostdev->parent.data.net) - return 0; - - isvf = virHostdevIsVirtualFunction(hostdev); - if (isvf <= 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("Interface type hostdev is currently supported on" - " SR-IOV Virtual Functions only")); - return ret; - } - - if (virHostdevNetDevice(hostdev, &linkdev, &vf) < 0) - return ret; - - virtPort = virDomainNetGetActualVirtPortProfile( - hostdev->parent.data.net); - if (virtPort) - ret = virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, - &hostdev->parent.data.net->mac, NULL, - port_profile_associate); - else { - ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir); - if (ret < 0 && oldStateDir != NULL) - ret = virNetDevRestoreNetConfig(linkdev, vf, oldStateDir); - } - - VIR_FREE(linkdev); - - return ret; -} - - bool qemuHostdevHostSupportsPassthroughVFIO(void) { @@ -662,205 +340,6 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs, return true; } -static int -virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *name, - const unsigned char *uuid, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs, - unsigned int flags) -{ - virPCIDeviceListPtr pcidevs = NULL; - int last_processed_hostdev_vf = -1; - size_t i; - int ret = -1; - - virObjectLock(hostdev_mgr->activePciHostdevs); - virObjectLock(hostdev_mgr->inactivePciHostdevs); - - if (!(pcidevs = virHostdevGetPciHostDeviceList(hostdevs, nhostdevs))) - goto cleanup; - - /* We have to use 9 loops here. *All* devices must - * be detached before we reset any of them, because - * in some cases you have to reset the whole PCI, - * which impacts all devices on it. Also, all devices - * must be reset before being marked as active. - */ - - /* Loop 1: validate that non-managed device isn't in use, eg - * by checking that device is either un-bound, or bound - * to pci-stub.ko - */ - - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - virPCIDevicePtr other; - bool strict_acs_check = !!(flags & VIR_STRICT_ACS_CHECK); - - if (!virPCIDeviceIsAssignable(dev, strict_acs_check)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("PCI device %s is not assignable"), - virPCIDeviceGetName(dev)); - goto cleanup; - } - /* The device is in use by other active domain if - * the dev is in list activePciHostdevs. - */ - if ((other = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev))) { - const char *other_drvname; - const char *other_domname; - - virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname); - if (other_drvname && other_domname) - virReportError(VIR_ERR_OPERATION_INVALID, - _("PCI device %s is in use by " - "driver %s, domain %s"), - virPCIDeviceGetName(dev), - other_drvname, other_domname); - else - virReportError(VIR_ERR_OPERATION_INVALID, - _("PCI device %s is already in use"), - virPCIDeviceGetName(dev)); - goto cleanup; - } - } - - /* Loop 2: detach managed devices (i.e. bind to appropriate stub driver) */ - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - if (virPCIDeviceGetManaged(dev) && - virPCIDeviceDetach(dev, hostdev_mgr->activePciHostdevs, NULL) < 0) - goto reattachdevs; - } - - /* Loop 3: Now that all the PCI hostdevs have been detached, we - * can safely reset them */ - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - - if (virPCIDeviceReset(dev, hostdev_mgr->activePciHostdevs, - hostdev_mgr->inactivePciHostdevs) < 0) - goto reattachdevs; - } - - /* Loop 4: For SRIOV network devices, Now that we have detached the - * the network device, set the netdev config */ - for (i = 0; i < nhostdevs; i++) { - virDomainHostdevDefPtr hostdev = hostdevs[i]; - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - continue; - if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - continue; - if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && - hostdev->parent.data.net) { - if (virHostdevNetConfigReplace(hostdev, uuid, - hostdev_mgr->stateDir) < 0) { - goto resetvfnetconfig; - } - } - last_processed_hostdev_vf = i; - } - - /* Loop 5: Now mark all the devices as active */ - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - if (virPCIDeviceListAdd(hostdev_mgr->activePciHostdevs, dev) < 0) - goto inactivedevs; - } - - /* Loop 6: Now remove the devices from inactive list. */ - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - virPCIDeviceListDel(hostdev_mgr->inactivePciHostdevs, dev); - } - - /* Loop 7: Now set the used_by_domain of the device in - * activePciHostdevs as domain name. - */ - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev, activeDev; - - dev = virPCIDeviceListGet(pcidevs, i); - activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev); - - if (activeDev) - virPCIDeviceSetUsedBy(activeDev, drv_name, name); - } - - /* Loop 8: Now set the original states for hostdev def */ - for (i = 0; i < nhostdevs; i++) { - virPCIDevicePtr dev; - virPCIDevicePtr pcidev; - virDomainHostdevDefPtr hostdev = hostdevs[i]; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - continue; - if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - continue; - - dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain, - hostdev->source.subsys.u.pci.addr.bus, - hostdev->source.subsys.u.pci.addr.slot, - hostdev->source.subsys.u.pci.addr.function); - - /* original states "unbind_from_stub", "remove_slot", - * "reprobe" were already set by pciDettachDevice in - * loop 2. - */ - if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) { - hostdev->origstates.states.pci.unbind_from_stub = - virPCIDeviceGetUnbindFromStub(pcidev); - hostdev->origstates.states.pci.remove_slot = - virPCIDeviceGetRemoveSlot(pcidev); - hostdev->origstates.states.pci.reprobe = - virPCIDeviceGetReprobe(pcidev); - } - - virPCIDeviceFree(dev); - } - - /* Loop 9: Now steal all the devices from pcidevs */ - while (virPCIDeviceListCount(pcidevs) > 0) - virPCIDeviceListStealIndex(pcidevs, 0); - - ret = 0; - goto cleanup; - -inactivedevs: - /* Only steal all the devices from activePciHostdevs. We will - * free them in virObjectUnref(). - */ - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - virPCIDeviceListSteal(hostdev_mgr->activePciHostdevs, dev); - } - -resetvfnetconfig: - for (i = 0; - last_processed_hostdev_vf != -1 && i < last_processed_hostdev_vf; i++) - virHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, NULL); - -reattachdevs: - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - - /* NB: This doesn't actually re-bind to original driver, just - * unbinds from the stub driver - */ - ignore_value(virPCIDeviceReattach(dev, hostdev_mgr->activePciHostdevs, - NULL)); - } - -cleanup: - virObjectUnlock(hostdev_mgr->activePciHostdevs); - virObjectUnlock(hostdev_mgr->inactivePciHostdevs); - virObjectUnref(pcidevs); - return ret; - -} - int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, const char *name, @@ -1264,133 +743,6 @@ qemuPrepareHostDevices(virQEMUDriverPtr driver, return 0; } - -/* - * Pre-condition: inactivePciHostdevs & activePciHostdevs - * are locked - */ -static void -virHostdevReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) -{ - /* If the device is not managed and was attached to guest - * successfully, it must have been inactive. - */ - if (!virPCIDeviceGetManaged(dev)) { - if (virPCIDeviceListAdd(mgr->inactivePciHostdevs, dev) < 0) - virPCIDeviceFree(dev); - return; - } - - /* Wait for device cleanup if it is qemu/kvm */ - if (STREQ(virPCIDeviceGetStubDriver(dev), "pci-stub")) { - int retries = 100; - while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device") - && retries) { - usleep(100*1000); - retries--; - } - } - - if (virPCIDeviceReattach(dev, mgr->activePciHostdevs, - mgr->inactivePciHostdevs) < 0) { - virErrorPtr err = virGetLastError(); - VIR_ERROR(_("Failed to re-attach PCI device: %s"), - err ? err->message : _("unknown error")); - virResetError(err); - } - virPCIDeviceFree(dev); -} - -/* @oldStateDir: - * For upgrade purpose: see virHostdevNetConfigRestore - */ -static void -virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs, - char *oldStateDir) -{ - virPCIDeviceListPtr pcidevs; - size_t i; - - virObjectLock(hostdev_mgr->activePciHostdevs); - virObjectLock(hostdev_mgr->inactivePciHostdevs); - - if (!(pcidevs = virHostdevGetActivePciHostDeviceList(hostdev_mgr, - hostdevs, - nhostdevs))) { - virErrorPtr err = virGetLastError(); - VIR_ERROR(_("Failed to allocate PCI device list: %s"), - err ? err->message : _("unknown error")); - virResetError(err); - goto cleanup; - } - - /* Again 4 loops; mark all devices as inactive before reset - * them and reset all the devices before re-attach. - * Attach mac and port profile parameters to devices - */ - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - virPCIDevicePtr activeDev = NULL; - - /* delete the copy of the dev from pcidevs if it's used by - * other domain. Or delete it from activePciHostDevs if it had - * been used by this domain. - */ - activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev); - if (activeDev) { - const char *usedby_drvname; - const char *usedby_domname; - virPCIDeviceGetUsedBy(activeDev, &usedby_drvname, &usedby_domname); - if (STRNEQ_NULLABLE(drv_name, usedby_drvname) || - STRNEQ_NULLABLE(name, usedby_domname)) { - virPCIDeviceListDel(pcidevs, dev); - continue; - } - } - - virPCIDeviceListDel(hostdev_mgr->activePciHostdevs, dev); - } - - /* At this point, any device that had been used by the guest is in - * pcidevs, but has been removed from activePciHostdevs. - */ - - /* - * For SRIOV net host devices, unset mac and port profile before - * reset and reattach device - */ - for (i = 0; i < nhostdevs; i++) - virHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, - oldStateDir); - - for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { - virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); - - if (virPCIDeviceReset(dev, hostdev_mgr->activePciHostdevs, - hostdev_mgr->inactivePciHostdevs) < 0) { - virErrorPtr err = virGetLastError(); - VIR_ERROR(_("Failed to reset PCI device: %s"), - err ? err->message : _("unknown error")); - virResetError(err); - } - } - - while (virPCIDeviceListCount(pcidevs) > 0) { - virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0); - qemuReattachPciDevice(dev, hostdev_mgr); - } - - virObjectUnref(pcidevs); -cleanup: - virObjectUnlock(hostdev_mgr->activePciHostdevs); - virObjectUnlock(hostdev_mgr->inactivePciHostdevs); - -} - void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, const char *name, diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h index c137302..0957a39 100644 --- a/src/qemu/qemu_hostdev.h +++ b/src/qemu/qemu_hostdev.h @@ -27,11 +27,6 @@ # include "qemu_conf.h" # include "domain_conf.h" -typedef enum { - VIR_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */ - VIR_COLD_BOOT = (1 << 1), /* cold boot */ -} virHostdevFlag; - int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver, virDomainDefPtr def); int qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 3fbe4d1..29c6944 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -66,6 +66,7 @@ #include "viratomic.h" #include "virnuma.h" #include "virstring.h" +#include "virhostdev.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 83124e9..9d48ac9 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -1,5 +1,7 @@ /* virhostdev.c: hostdev management * + * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. * * This library is free software; you can redistribute it and/or @@ -16,6 +18,7 @@ * License along with this library. If not, see * <http://www.gnu.org/licenses/>. * + * Author: Daniel P. Berrange <berrange@redhat.com> * Author: Chunyan Liu <cyliu@suse.com> */ @@ -36,6 +39,7 @@ #include "virerror.h" #include "virlog.h" #include "virutil.h" +#include "virnetdev.h" #include "configmake.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -101,3 +105,648 @@ virHostdevManagerGetDefault(void) return NULL; return hostdevMgr; } + +static virPCIDeviceListPtr +virHostdevGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) +{ + virPCIDeviceListPtr list; + size_t i; + + if (!(list = virPCIDeviceListNew())) + return NULL; + + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virPCIDevicePtr dev; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + + dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + if (!dev) { + virObjectUnref(list); + return NULL; + } + + if (virPCIDeviceListAdd(list, dev) < 0) { + virPCIDeviceFree(dev); + virObjectUnref(list); + return NULL; + } + + virPCIDeviceSetManaged(dev, hostdev->managed); + if (hostdev->source.subsys.u.pci.backend + == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) { + virObjectUnref(list); + return NULL; + } + } else { + if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) { + virObjectUnref(list); + return NULL; + } + } + } + + return list; +} + + +/* + * virHostdevGetActivePciHostDeviceList - make a new list with a *copy* of + * every virPCIDevice object that is found on the activePciHostdevs + * list *and* is in the hostdev list for this domain. + * + * Return the new list, or NULL if there was a failure. + * + * Pre-condition: activePciHostdevs is locked + */ +static virPCIDeviceListPtr +virHostdevGetActivePciHostDeviceList(virHostdevManagerPtr mgr, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + virPCIDeviceListPtr list; + size_t i; + + if (!(list = virPCIDeviceListNew())) + return NULL; + + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virDevicePCIAddressPtr addr; + virPCIDevicePtr activeDev; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + + addr = &hostdev->source.subsys.u.pci.addr; + activeDev = virPCIDeviceListFindByIDs(mgr->activePciHostdevs, + addr->domain, addr->bus, + addr->slot, addr->function); + if (activeDev && virPCIDeviceListAddCopy(list, activeDev) < 0) { + virObjectUnref(list); + return NULL; + } + } + + return list; +} + +static int +virHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, + char **sysfs_path) +{ + virPCIDeviceAddress config_address; + + config_address.domain = hostdev->source.subsys.u.pci.addr.domain; + config_address.bus = hostdev->source.subsys.u.pci.addr.bus; + config_address.slot = hostdev->source.subsys.u.pci.addr.slot; + config_address.function = hostdev->source.subsys.u.pci.addr.function; + + return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path); +} + + +static int +virHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev) +{ + char *sysfs_path = NULL; + int ret = -1; + + if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) + return ret; + + ret = virPCIIsVirtualFunction(sysfs_path); + + VIR_FREE(sysfs_path); + + return ret; +} + + +static int +virHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev, + int *vf) +{ + int ret = -1; + char *sysfs_path = NULL; + + if (virHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) + return ret; + + if (virPCIIsVirtualFunction(sysfs_path) == 1) { + if (virPCIGetVirtualFunctionInfo(sysfs_path, linkdev, + vf) < 0) + goto cleanup; + } else { + if (virPCIGetNetName(sysfs_path, linkdev) < 0) + goto cleanup; + *vf = -1; + } + + ret = 0; + +cleanup: + VIR_FREE(sysfs_path); + + return ret; +} + + +static int +virHostdevNetConfigVirtPortProfile(const char *linkdev, int vf, + virNetDevVPortProfilePtr virtPort, + const virMacAddr *macaddr, + const unsigned char *uuid, + bool associate) +{ + int ret = -1; + + if (!virtPort) + return ret; + + switch (virtPort->virtPortType) { + case VIR_NETDEV_VPORT_PROFILE_NONE: + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: + case VIR_NETDEV_VPORT_PROFILE_8021QBG: + case VIR_NETDEV_VPORT_PROFILE_LAST: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("virtualport type %s is " + "currently not supported on interfaces of type " + "hostdev"), + virNetDevVPortTypeToString(virtPort->virtPortType)); + break; + + case VIR_NETDEV_VPORT_PROFILE_8021QBH: + if (associate) + ret = virNetDevVPortProfileAssociate(NULL, virtPort, macaddr, + linkdev, vf, uuid, + VIR_NETDEV_VPORT_PROFILE_OP_CREATE, false); + else + ret = virNetDevVPortProfileDisassociate(NULL, virtPort, + macaddr, linkdev, vf, + VIR_NETDEV_VPORT_PROFILE_OP_DESTROY); + break; + } + + return ret; +} + + +static int +virHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, + const unsigned char *uuid, + char *stateDir) +{ + char *linkdev = NULL; + virNetDevVlanPtr vlan; + virNetDevVPortProfilePtr virtPort; + int ret = -1; + int vf = -1; + int vlanid = -1; + bool port_profile_associate = true; + int isvf; + + isvf = virHostdevIsVirtualFunction(hostdev); + if (isvf <= 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Interface type hostdev is currently supported on" + " SR-IOV Virtual Functions only")); + return ret; + } + + if (virHostdevNetDevice(hostdev, &linkdev, &vf) < 0) + return ret; + + vlan = virDomainNetGetActualVlan(hostdev->parent.data.net); + virtPort = virDomainNetGetActualVirtPortProfile( + hostdev->parent.data.net); + if (virtPort) { + if (vlan) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("direct setting of the vlan tag is not allowed " + "for hostdev devices using %s mode"), + virNetDevVPortTypeToString(virtPort->virtPortType)); + goto cleanup; + } + ret = virHostdevNetConfigVirtPortProfile(linkdev, vf, + virtPort, &hostdev->parent.data.net->mac, uuid, + port_profile_associate); + } else { + /* Set only mac and vlan */ + if (vlan) { + if (vlan->nTags != 1 || vlan->trunk) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("vlan trunking is not supported " + "by SR-IOV network devices")); + goto cleanup; + } + if (vf == -1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("vlan can only be set for SR-IOV VFs, but " + "%s is not a VF"), linkdev); + goto cleanup; + } + vlanid = vlan->tag[0]; + } else if (vf >= 0) { + vlanid = 0; /* assure any current vlan tag is reset */ + } + + ret = virNetDevReplaceNetConfig(linkdev, vf, + &hostdev->parent.data.net->mac, + vlanid, stateDir); + } +cleanup: + VIR_FREE(linkdev); + return ret; +} + +/* @oldStateDir: + * For upgrade purpose: + * To an existing VM on QEMU, the hostdev netconfig file is originally stored + * in cfg->stateDir (/var/run/libvirt/qemu). Switch to new version, it uses new + * location (hostdev_mgr->stateDir) but certainly will not find it. In this + * case, try to find in the old state dir. + */ +static int +virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, + char *stateDir, + char *oldStateDir) +{ + char *linkdev = NULL; + virNetDevVPortProfilePtr virtPort; + int ret = -1; + int vf = -1; + bool port_profile_associate = false; + int isvf; + + /* This is only needed for PCI devices that have been defined + * using <interface type='hostdev'>. For all others, it is a NOP. + */ + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI || + hostdev->parent.type != VIR_DOMAIN_DEVICE_NET || + !hostdev->parent.data.net) + return 0; + + isvf = virHostdevIsVirtualFunction(hostdev); + if (isvf <= 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Interface type hostdev is currently supported on" + " SR-IOV Virtual Functions only")); + return ret; + } + + if (virHostdevNetDevice(hostdev, &linkdev, &vf) < 0) + return ret; + + virtPort = virDomainNetGetActualVirtPortProfile( + hostdev->parent.data.net); + if (virtPort) + ret = virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, + &hostdev->parent.data.net->mac, NULL, + port_profile_associate); + else { + ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir); + if (ret < 0 && oldStateDir != NULL) + ret = virNetDevRestoreNetConfig(linkdev, vf, oldStateDir); + } + + VIR_FREE(linkdev); + + return ret; +} + +int +virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + const unsigned char *uuid, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + unsigned int flags) +{ + virPCIDeviceListPtr pcidevs = NULL; + int last_processed_hostdev_vf = -1; + size_t i; + int ret = -1; + + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); + + if (!(pcidevs = virHostdevGetPciHostDeviceList(hostdevs, nhostdevs))) + goto cleanup; + + /* We have to use 9 loops here. *All* devices must + * be detached before we reset any of them, because + * in some cases you have to reset the whole PCI, + * which impacts all devices on it. Also, all devices + * must be reset before being marked as active. + */ + + /* Loop 1: validate that non-managed device isn't in use, eg + * by checking that device is either un-bound, or bound + * to pci-stub.ko + */ + + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + virPCIDevicePtr other; + bool strict_acs_check = !!(flags & VIR_STRICT_ACS_CHECK); + + if (!virPCIDeviceIsAssignable(dev, strict_acs_check)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("PCI device %s is not assignable"), + virPCIDeviceGetName(dev)); + goto cleanup; + } + /* The device is in use by other active domain if + * the dev is in list activePciHostdevs. + */ + if ((other = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev))) { + const char *other_drvname; + const char *other_domname; + + virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname); + if (other_drvname && other_domname) + virReportError(VIR_ERR_OPERATION_INVALID, + _("PCI device %s is in use by " + "driver %s, domain %s"), + virPCIDeviceGetName(dev), + other_drvname, other_domname); + else + virReportError(VIR_ERR_OPERATION_INVALID, + _("PCI device %s is already in use"), + virPCIDeviceGetName(dev)); + goto cleanup; + } + } + + /* Loop 2: detach managed devices (i.e. bind to appropriate stub driver) */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + if (virPCIDeviceGetManaged(dev) && + virPCIDeviceDetach(dev, hostdev_mgr->activePciHostdevs, NULL) < 0) + goto reattachdevs; + } + + /* Loop 3: Now that all the PCI hostdevs have been detached, we + * can safely reset them */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + + if (virPCIDeviceReset(dev, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) + goto reattachdevs; + } + + /* Loop 4: For SRIOV network devices, Now that we have detached the + * the network device, set the netdev config */ + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && + hostdev->parent.data.net) { + if (virHostdevNetConfigReplace(hostdev, uuid, + hostdev_mgr->stateDir) < 0) { + goto resetvfnetconfig; + } + } + last_processed_hostdev_vf = i; + } + + /* Loop 5: Now mark all the devices as active */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + if (virPCIDeviceListAdd(hostdev_mgr->activePciHostdevs, dev) < 0) + goto inactivedevs; + } + + /* Loop 6: Now remove the devices from inactive list. */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + virPCIDeviceListDel(hostdev_mgr->inactivePciHostdevs, dev); + } + + /* Loop 7: Now set the used_by_domain of the device in + * activePciHostdevs as domain name. + */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev, activeDev; + + dev = virPCIDeviceListGet(pcidevs, i); + activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev); + + if (activeDev) + virPCIDeviceSetUsedBy(activeDev, drv_name, name); + } + + /* Loop 8: Now set the original states for hostdev def */ + for (i = 0; i < nhostdevs; i++) { + virPCIDevicePtr dev; + virPCIDevicePtr pcidev; + virDomainHostdevDefPtr hostdev = hostdevs[i]; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + + dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + + /* original states "unbind_from_stub", "remove_slot", + * "reprobe" were already set by pciDettachDevice in + * loop 2. + */ + if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) { + hostdev->origstates.states.pci.unbind_from_stub = + virPCIDeviceGetUnbindFromStub(pcidev); + hostdev->origstates.states.pci.remove_slot = + virPCIDeviceGetRemoveSlot(pcidev); + hostdev->origstates.states.pci.reprobe = + virPCIDeviceGetReprobe(pcidev); + } + + virPCIDeviceFree(dev); + } + + /* Loop 9: Now steal all the devices from pcidevs */ + while (virPCIDeviceListCount(pcidevs) > 0) + virPCIDeviceListStealIndex(pcidevs, 0); + + ret = 0; + goto cleanup; + +inactivedevs: + /* Only steal all the devices from activePciHostdevs. We will + * free them in virObjectUnref(). + */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + virPCIDeviceListSteal(hostdev_mgr->activePciHostdevs, dev); + } + +resetvfnetconfig: + for (i = 0; + last_processed_hostdev_vf != -1 && i < last_processed_hostdev_vf; i++) + virHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, NULL); + +reattachdevs: + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + + /* NB: This doesn't actually re-bind to original driver, just + * unbinds from the stub driver + */ + ignore_value(virPCIDeviceReattach(dev, hostdev_mgr->activePciHostdevs, + NULL)); + } + +cleanup: + virObjectUnlock(hostdev_mgr->activePciHostdevs); + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + virObjectUnref(pcidevs); + return ret; + +} + +/* + * Pre-condition: inactivePciHostdevs & activePciHostdevs + * are locked + */ +static void +virHostdevReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) +{ + /* If the device is not managed and was attached to guest + * successfully, it must have been inactive. + */ + if (!virPCIDeviceGetManaged(dev)) { + if (virPCIDeviceListAdd(mgr->inactivePciHostdevs, dev) < 0) + virPCIDeviceFree(dev); + return; + } + + /* Wait for device cleanup if it is qemu/kvm */ + if (STREQ(virPCIDeviceGetStubDriver(dev), "pci-stub")) { + int retries = 100; + while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device") + && retries) { + usleep(100*1000); + retries--; + } + } + + if (virPCIDeviceReattach(dev, mgr->activePciHostdevs, + mgr->inactivePciHostdevs) < 0) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to re-attach PCI device: %s"), + err ? err->message : _("unknown error")); + virResetError(err); + } + virPCIDeviceFree(dev); +} + +/* @oldStateDir: + * For upgrade purpose: see virHostdevNetConfigRestore + */ +void +virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + char *oldStateDir) +{ + virPCIDeviceListPtr pcidevs; + size_t i; + + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); + + if (!(pcidevs = virHostdevGetActivePciHostDeviceList(hostdev_mgr, + hostdevs, + nhostdevs))) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to allocate PCI device list: %s"), + err ? err->message : _("unknown error")); + virResetError(err); + goto cleanup; + } + + /* Again 4 loops; mark all devices as inactive before reset + * them and reset all the devices before re-attach. + * Attach mac and port profile parameters to devices + */ + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + virPCIDevicePtr activeDev = NULL; + + /* delete the copy of the dev from pcidevs if it's used by + * other domain. Or delete it from activePciHostDevs if it had + * been used by this domain. + */ + activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev); + if (activeDev) { + const char *usedby_drvname; + const char *usedby_domname; + virPCIDeviceGetUsedBy(activeDev, &usedby_drvname, &usedby_domname); + if (STRNEQ_NULLABLE(drv_name, usedby_drvname) || + STRNEQ_NULLABLE(name, usedby_domname)) { + virPCIDeviceListDel(pcidevs, dev); + continue; + } + } + + virPCIDeviceListDel(hostdev_mgr->activePciHostdevs, dev); + } + + /* At this point, any device that had been used by the guest is in + * pcidevs, but has been removed from activePciHostdevs. + */ + + /* + * For SRIOV net host devices, unset mac and port profile before + * reset and reattach device + */ + for (i = 0; i < nhostdevs; i++) + virHostdevNetConfigRestore(hostdevs[i], hostdev_mgr->stateDir, + oldStateDir); + + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) { + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i); + + if (virPCIDeviceReset(dev, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) { + virErrorPtr err = virGetLastError(); + VIR_ERROR(_("Failed to reset PCI device: %s"), + err ? err->message : _("unknown error")); + virResetError(err); + } + } + + while (virPCIDeviceListCount(pcidevs) > 0) { + virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0); + virHostdevReattachPciDevice(dev, hostdev_mgr); + } + + virObjectUnref(pcidevs); +cleanup: + virObjectUnlock(hostdev_mgr->activePciHostdevs); + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index dba5e3e..d3ac1d3 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -1,5 +1,7 @@ /* virhostdev.h: hostdev management * + * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc. + * Copyright (C) 2006 Daniel P. Berrange * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. * * This library is free software; you can redistribute it and/or @@ -16,6 +18,7 @@ * License along with this library. If not, see * <http://www.gnu.org/licenses/>. * + * Author: Daniel P. Berrange <berrange@redhat.com> * Author: Chunyan Liu <cyliu@suse.com> */ @@ -27,6 +30,13 @@ # include "virpci.h" # include "virusb.h" # include "virscsi.h" +# include "domain_conf.h" + +typedef enum { + VIR_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */ + VIR_COLD_BOOT = (1 << 1), /* cold boot */ +} virHostdevFlag; + typedef struct _virHostdevManager virHostdevManager; typedef virHostdevManager *virHostdevManagerPtr; @@ -40,5 +50,20 @@ struct _virHostdevManager{ }; virHostdevManagerPtr virHostdevManagerGetDefault(void); +int +virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + const unsigned char *uuid, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + unsigned int flags); +void +virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + char *oldStateDir); #endif /* __VIR_HOSTDEV_H__ */ -- 1.6.0.2

Extract general code from qemuUpdateActivePciHostdevs to virHostdevUpdateActivePciHostdevs. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 28 +++++++++++++++++++--------- 1 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index b0489e2..1730ed8 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -41,21 +41,16 @@ #define VIR_FROM_THIS VIR_FROM_QEMU -int -qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, - virDomainDefPtr def) +static int +virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, + virDomainDefPtr def) + { virDomainHostdevDefPtr hostdev = NULL; virPCIDevicePtr dev = NULL; size_t i; int ret = -1; - virHostdevManagerPtr mgr; - if (!def->nhostdevs) - return 0; - mgr = virHostdevManagerGetDefault(); - if (mgr == NULL) - return -1; virObjectLock(mgr->activePciHostdevs); virObjectLock(mgr->inactivePciHostdevs); @@ -106,6 +101,21 @@ cleanup: } int +qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + virDomainDefPtr def) +{ + virHostdevManagerPtr mgr; + + if (!def->nhostdevs) + return 0; + mgr = virHostdevManagerGetDefault(); + if (mgr == NULL) + return -1; + + return virHostdevUpdateActivePciHostdevs(mgr, def); +} + +int qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) { -- 1.6.0.2

Extract general code from qemuUpdateActiveUsbHostdevs to virHostdevUpdateActiveUsbHostdevs. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 27 ++++++++++++++++++--------- 1 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 1730ed8..1992aa0 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -115,20 +115,14 @@ qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, return virHostdevUpdateActivePciHostdevs(mgr, def); } -int -qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, - virDomainDefPtr def) +static int +virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, + virDomainDefPtr def) { virDomainHostdevDefPtr hostdev = NULL; size_t i; int ret = -1; - virHostdevManagerPtr mgr; - if (!def->nhostdevs) - return 0; - mgr = virHostdevManagerGetDefault(); - if (mgr == NULL) - return -1; virObjectLock(mgr->activeUsbHostdevs); for (i = 0; i < def->nhostdevs; i++) { virUSBDevicePtr usb = NULL; @@ -164,6 +158,21 @@ cleanup: } int +qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + virDomainDefPtr def) +{ + virHostdevManagerPtr mgr; + + if (!def->nhostdevs) + return 0; + mgr = virHostdevManagerGetDefault(); + if (mgr == NULL) + return -1; + + return virHostdevUpdateActiveUsbHostdevs(mgr, def); +} + +int qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) { -- 1.6.0.2

Extract general code from qemuUpdateActiveScsiHostdevs to virHostdevUpdateActiveScsiHostdevs Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 27 ++++++++++++++++++--------- 1 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 1992aa0..972ea09 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -172,22 +172,16 @@ qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, return virHostdevUpdateActiveUsbHostdevs(mgr, def); } -int -qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, - virDomainDefPtr def) +static int +virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, + virDomainDefPtr def) { virDomainHostdevDefPtr hostdev = NULL; size_t i; int ret = -1; virSCSIDevicePtr scsi = NULL; virSCSIDevicePtr tmp = NULL; - virHostdevManagerPtr mgr; - if (!def->nhostdevs) - return 0; - mgr = virHostdevManagerGetDefault(); - if (mgr == NULL) - return -1; virObjectLock(mgr->activeScsiHostdevs); for (i = 0; i < def->nhostdevs; i++) { hostdev = def->hostdevs[i]; @@ -227,6 +221,21 @@ cleanup: } +int +qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + virDomainDefPtr def) +{ + virHostdevManagerPtr mgr; + + if (!def->nhostdevs) + return 0; + mgr = virHostdevManagerGetDefault(); + if (mgr == NULL) + return -1; + + return virHostdevUpdateActiveScsiHostdevs(mgr, def); +} + bool qemuHostdevHostSupportsPassthroughVFIO(void) { -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 18 ++++++++++-------- 1 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 972ea09..c35a5df 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -43,6 +43,7 @@ static int virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, virDomainDefPtr def) { @@ -80,7 +81,7 @@ virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, goto cleanup; } - virPCIDeviceSetUsedBy(dev, QEMU_DRIVER_NAME, def->name); + virPCIDeviceSetUsedBy(dev, drv_name, def->name); /* Setup the original states for the PCI device */ virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub); @@ -112,11 +113,12 @@ qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (mgr == NULL) return -1; - return virHostdevUpdateActivePciHostdevs(mgr, def); + return virHostdevUpdateActivePciHostdevs(mgr, QEMU_DRIVER_NAME, def); } static int virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, virDomainDefPtr def) { virDomainHostdevDefPtr hostdev = NULL; @@ -144,7 +146,7 @@ virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, continue; } - virUSBDeviceSetUsedBy(usb, QEMU_DRIVER_NAME, def->name); + virUSBDeviceSetUsedBy(usb, drv_name, def->name); if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0) { virUSBDeviceFree(usb); @@ -169,11 +171,12 @@ qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (mgr == NULL) return -1; - return virHostdevUpdateActiveUsbHostdevs(mgr, def); + return virHostdevUpdateActiveUsbHostdevs(mgr, QEMU_DRIVER_NAME, def); } static int virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, virDomainDefPtr def) { virDomainHostdevDefPtr hostdev = NULL; @@ -200,13 +203,13 @@ virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, goto cleanup; if ((tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi))) { - if (virSCSIDeviceSetUsedBy(tmp, QEMU_DRIVER_NAME, def->name) < 0) { + if (virSCSIDeviceSetUsedBy(tmp, drv_name, def->name) < 0) { virSCSIDeviceFree(scsi); goto cleanup; } virSCSIDeviceFree(scsi); } else { - if (virSCSIDeviceSetUsedBy(scsi, QEMU_DRIVER_NAME, def->name) < 0 || + if (virSCSIDeviceSetUsedBy(scsi, drv_name, def->name) < 0 || virSCSIDeviceListAdd(mgr->activeScsiHostdevs, scsi) < 0) { virSCSIDeviceFree(scsi); goto cleanup; @@ -220,7 +223,6 @@ cleanup: return ret; } - int qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) @@ -233,7 +235,7 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (mgr == NULL) return -1; - return virHostdevUpdateActiveScsiHostdevs(mgr, def); + return virHostdevUpdateActiveScsiHostdevs(mgr, QEMU_DRIVER_NAME, def); } bool -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libvirt_private.syms | 3 + src/qemu/qemu_hostdev.c | 152 ---------------------------------------------- src/util/virhostdev.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 12 ++++ 4 files changed, 167 insertions(+), 152 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 410133a..4417fdd 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1295,6 +1295,9 @@ virHookPresent; virHostdevManagerGetDefault; virHostdevPreparePCIDevices; virHostdevReAttachPCIDevices; +virHostdevUpdateActivePciHostdevs; +virHostdevUpdateActiveScsiHostdevs; +virHostdevUpdateActiveUsbHostdevs; # util/viridentity.h virIdentityGetAttr; diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index c35a5df..5771f41 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -41,66 +41,6 @@ #define VIR_FROM_THIS VIR_FROM_QEMU -static int -virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, - const char *drv_name, - virDomainDefPtr def) - -{ - virDomainHostdevDefPtr hostdev = NULL; - virPCIDevicePtr dev = NULL; - size_t i; - int ret = -1; - - virObjectLock(mgr->activePciHostdevs); - virObjectLock(mgr->inactivePciHostdevs); - - for (i = 0; i < def->nhostdevs; i++) { - hostdev = def->hostdevs[i]; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - continue; - if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) - continue; - - dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain, - hostdev->source.subsys.u.pci.addr.bus, - hostdev->source.subsys.u.pci.addr.slot, - hostdev->source.subsys.u.pci.addr.function); - - if (!dev) - goto cleanup; - - virPCIDeviceSetManaged(dev, hostdev->managed); - if (hostdev->source.subsys.u.pci.backend - == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { - if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) - goto cleanup; - } else { - if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) - goto cleanup; - - } - virPCIDeviceSetUsedBy(dev, drv_name, def->name); - - /* Setup the original states for the PCI device */ - virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub); - virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot); - virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe); - - if (virPCIDeviceListAdd(mgr->activePciHostdevs, dev) < 0) - goto cleanup; - dev = NULL; - } - - ret = 0; -cleanup: - virPCIDeviceFree(dev); - virObjectUnlock(mgr->activePciHostdevs); - virObjectUnlock(mgr->inactivePciHostdevs); - return ret; -} - int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) @@ -116,49 +56,6 @@ qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, return virHostdevUpdateActivePciHostdevs(mgr, QEMU_DRIVER_NAME, def); } -static int -virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, - const char *drv_name, - virDomainDefPtr def) -{ - virDomainHostdevDefPtr hostdev = NULL; - size_t i; - int ret = -1; - - virObjectLock(mgr->activeUsbHostdevs); - for (i = 0; i < def->nhostdevs; i++) { - virUSBDevicePtr usb = NULL; - hostdev = def->hostdevs[i]; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - continue; - if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) - continue; - - usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - NULL); - if (!usb) { - VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", - hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - def->name); - continue; - } - - virUSBDeviceSetUsedBy(usb, drv_name, def->name); - - if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0) { - virUSBDeviceFree(usb); - goto cleanup; - } - } - ret = 0; -cleanup: - virObjectUnlock(mgr->activeUsbHostdevs); - return ret; -} - int qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) @@ -174,55 +71,6 @@ qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, return virHostdevUpdateActiveUsbHostdevs(mgr, QEMU_DRIVER_NAME, def); } -static int -virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, - const char *drv_name, - virDomainDefPtr def) -{ - virDomainHostdevDefPtr hostdev = NULL; - size_t i; - int ret = -1; - virSCSIDevicePtr scsi = NULL; - virSCSIDevicePtr tmp = NULL; - - virObjectLock(mgr->activeScsiHostdevs); - for (i = 0; i < def->nhostdevs; i++) { - hostdev = def->hostdevs[i]; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || - hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) - continue; - - if (!(scsi = virSCSIDeviceNew(NULL, - hostdev->source.subsys.u.scsi.adapter, - hostdev->source.subsys.u.scsi.bus, - hostdev->source.subsys.u.scsi.target, - hostdev->source.subsys.u.scsi.unit, - hostdev->readonly, - hostdev->shareable))) - goto cleanup; - - if ((tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi))) { - if (virSCSIDeviceSetUsedBy(tmp, drv_name, def->name) < 0) { - virSCSIDeviceFree(scsi); - goto cleanup; - } - virSCSIDeviceFree(scsi); - } else { - if (virSCSIDeviceSetUsedBy(scsi, drv_name, def->name) < 0 || - virSCSIDeviceListAdd(mgr->activeScsiHostdevs, scsi) < 0) { - virSCSIDeviceFree(scsi); - goto cleanup; - } - } - } - ret = 0; - -cleanup: - virObjectUnlock(mgr->activeScsiHostdevs); - return ret; -} - int qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index c381907..5e7318f 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -750,3 +750,155 @@ cleanup: virObjectUnlock(hostdev_mgr->inactivePciHostdevs); } + +int +virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + virDomainDefPtr def) + +{ + virDomainHostdevDefPtr hostdev = NULL; + virPCIDevicePtr dev = NULL; + size_t i; + int ret = -1; + + virObjectLock(mgr->activePciHostdevs); + virObjectLock(mgr->inactivePciHostdevs); + + for (i = 0; i < def->nhostdevs; i++) { + hostdev = def->hostdevs[i]; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + + dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + + if (!dev) + goto cleanup; + + virPCIDeviceSetManaged(dev, hostdev->managed); + if (hostdev->source.subsys.u.pci.backend + == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { + if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) + goto cleanup; + } else { + if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) + goto cleanup; + + } + virPCIDeviceSetUsedBy(dev, drv_name, def->name); + + /* Setup the original states for the PCI device */ + virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub); + virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot); + virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe); + + if (virPCIDeviceListAdd(mgr->activePciHostdevs, dev) < 0) + goto cleanup; + dev = NULL; + } + + ret = 0; +cleanup: + virPCIDeviceFree(dev); + virObjectUnlock(mgr->activePciHostdevs); + virObjectUnlock(mgr->inactivePciHostdevs); + return ret; +} + +int +virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + virDomainDefPtr def) +{ + virDomainHostdevDefPtr hostdev = NULL; + size_t i; + int ret = -1; + + virObjectLock(mgr->activeUsbHostdevs); + for (i = 0; i < def->nhostdevs; i++) { + virUSBDevicePtr usb = NULL; + hostdev = def->hostdevs[i]; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) + continue; + + usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + NULL); + if (!usb) { + VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + def->name); + continue; + } + + virUSBDeviceSetUsedBy(usb, drv_name, def->name); + + if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0) { + virUSBDeviceFree(usb); + goto cleanup; + } + } + ret = 0; +cleanup: + virObjectUnlock(mgr->activeUsbHostdevs); + return ret; +} + +int +virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + virDomainDefPtr def) +{ + virDomainHostdevDefPtr hostdev = NULL; + size_t i; + int ret = -1; + virSCSIDevicePtr scsi = NULL; + virSCSIDevicePtr tmp = NULL; + + virObjectLock(mgr->activeScsiHostdevs); + for (i = 0; i < def->nhostdevs; i++) { + hostdev = def->hostdevs[i]; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) + continue; + + if (!(scsi = virSCSIDeviceNew(NULL, + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + hostdev->readonly, + hostdev->shareable))) + goto cleanup; + + if ((tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi))) { + if (virSCSIDeviceSetUsedBy(tmp, drv_name, def->name) < 0) { + virSCSIDeviceFree(scsi); + goto cleanup; + } + virSCSIDeviceFree(scsi); + } else { + if (virSCSIDeviceSetUsedBy(scsi, drv_name, def->name) < 0 || + virSCSIDeviceListAdd(mgr->activeScsiHostdevs, scsi) < 0) { + virSCSIDeviceFree(scsi); + goto cleanup; + } + } + } + ret = 0; + +cleanup: + virObjectUnlock(mgr->activeScsiHostdevs); + return ret; +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index d3ac1d3..9773c6e 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -65,5 +65,17 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, virDomainHostdevDefPtr *hostdevs, int nhostdevs, char *oldStateDir); +int +virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + virDomainDefPtr def); +int +virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + virDomainDefPtr def); +int +virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, + virDomainDefPtr def); #endif /* __VIR_HOSTDEV_H__ */ -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 5771f41..e39bc47 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -402,9 +402,14 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virUSBDevicePtr tmp; virDomainHostdevDefPtr *hostdevs = def->hostdevs; int nhostdevs = def->nhostdevs; + const char *dom_name = def->name; virHostdevManagerPtr hostdev_mgr; bool coldBoot = !!(flags & VIR_COLD_BOOT); + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return -1; + /* 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 @@ -443,10 +448,7 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, * and add them do driver list. However, if something goes * wrong, perform rollback. */ - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) - goto cleanup; - if (qemuPrepareHostdevUSBDevices(hostdev_mgr, def->name, list) < 0) + if (qemuPrepareHostdevUSBDevices(hostdev_mgr, dom_name, list) < 0) goto cleanup; /* Loop 2: Temporary list was successfully merged with -- 1.6.0.2

Extract general code from qemuPrepareHostUSBDevices to virHostdevPrepareHostUSBDevices. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 37 ++++++++++++++++++++++++------------- 1 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index e39bc47..1a589f4 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -390,26 +390,19 @@ out: return 0; } - -int -qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, - virDomainDefPtr def, - unsigned int flags) +static int +virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + unsigned int flags) { size_t i; int ret = -1; virUSBDeviceListPtr list; virUSBDevicePtr tmp; - virDomainHostdevDefPtr *hostdevs = def->hostdevs; - int nhostdevs = def->nhostdevs; - const char *dom_name = def->name; - virHostdevManagerPtr hostdev_mgr; bool coldBoot = !!(flags & VIR_COLD_BOOT); - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) - return -1; - /* 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 @@ -467,6 +460,24 @@ cleanup: return ret; } +int +qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + virDomainDefPtr def, + unsigned int flags) +{ + virDomainHostdevDefPtr *hostdevs = def->hostdevs; + int nhostdevs = def->nhostdevs; + const char *dom_name = def->name; + virHostdevManagerPtr hostdev_mgr; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return -1; + + return virHostdevPrepareUSBDevices(hostdev_mgr, dom_name, + hostdevs, nhostdevs, flags); +} + int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 16 ++++++++-------- 1 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 1a589f4..15ed47c 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -247,9 +247,9 @@ out: static int -qemuPrepareHostdevUSBDevices(virHostdevManagerPtr mgr, - const char *name, - virUSBDeviceListPtr list) +virHostdevMarkUsbHostdevs(virHostdevManagerPtr mgr, + const char *name, + virUSBDeviceListPtr list) { size_t i, j; unsigned int count; @@ -304,9 +304,9 @@ error: static int -qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev, - bool mandatory, - virUSBDevicePtr *usb) +virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev, + bool mandatory, + virUSBDevicePtr *usb) { unsigned vendor = hostdev->source.subsys.u.usb.vendor; unsigned product = hostdev->source.subsys.u.usb.product; @@ -428,7 +428,7 @@ virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, !coldBoot)) required = false; - if (qemuFindHostdevUSBDevice(hostdev, required, &usb) < 0) + if (virHostdevFindUSBDevice(hostdev, required, &usb) < 0) goto cleanup; if (usb && virUSBDeviceListAdd(list, usb) < 0) { @@ -441,7 +441,7 @@ virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, * and add them do driver list. However, if something goes * wrong, perform rollback. */ - if (qemuPrepareHostdevUSBDevices(hostdev_mgr, dom_name, list) < 0) + if (virHostdevMarkUsbHostdevs(hostdev_mgr, dom_name, list) < 0) goto cleanup; /* Loop 2: Temporary list was successfully merged with -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 15ed47c..a7e6c91 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -248,6 +248,7 @@ out: static int virHostdevMarkUsbHostdevs(virHostdevManagerPtr mgr, + const char *drv_name, const char *name, virUSBDeviceListPtr list) { @@ -278,7 +279,7 @@ virHostdevMarkUsbHostdevs(virHostdevManagerPtr mgr, goto error; } - virUSBDeviceSetUsedBy(usb, QEMU_DRIVER_NAME, name); + virUSBDeviceSetUsedBy(usb, drv_name, name); VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs", virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name); /* @@ -392,6 +393,7 @@ out: static int virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs, @@ -441,7 +443,7 @@ virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, * and add them do driver list. However, if something goes * wrong, perform rollback. */ - if (virHostdevMarkUsbHostdevs(hostdev_mgr, dom_name, list) < 0) + if (virHostdevMarkUsbHostdevs(hostdev_mgr, drv_name, dom_name, list) < 0) goto cleanup; /* Loop 2: Temporary list was successfully merged with @@ -474,7 +476,7 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (hostdev_mgr == NULL) return -1; - return virHostdevPrepareUSBDevices(hostdev_mgr, dom_name, + return virHostdevPrepareUSBDevices(hostdev_mgr, QEMU_DRIVER_NAME, dom_name, hostdevs, nhostdevs, flags); } -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@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

Extract general code from qemuPrepareHostSCSIDevices to virHostdevPrepareHostSCSIDevices. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 70 +++++++++++++++++++++++++++------------------- 1 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 2934e65..5eb12d1 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -263,34 +263,16 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, hostdevs, nhostdevs, flags); } - -int -qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, - const char *name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) +static int +virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) { size_t i, j; int count; virSCSIDeviceListPtr list; virSCSIDevicePtr tmp; - virHostdevManagerPtr hostdev_mgr; - - /* Loop 1: Add the shared scsi host device to shared device - * table. - */ - for (i = 0; i < nhostdevs; i++) { - virDomainDeviceDef dev; - - dev.type = VIR_DOMAIN_DEVICE_HOSTDEV; - dev.data.hostdev = hostdevs[i]; - - if (qemuAddSharedDevice(driver, &dev, name) < 0) - return -1; - - if (qemuSetUnprivSGIO(&dev) < 0) - return -1; - } /* To prevent situation where SCSI device is assigned to two domains * we need to keep a list of currently assigned SCSI devices. @@ -300,7 +282,7 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, if (!(list = virSCSIDeviceListNew())) goto cleanup; - /* Loop 2: build temporary list */ + /* Loop 1: build temporary list */ for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; virSCSIDevicePtr scsi; @@ -330,13 +312,10 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, } } - /* Loop 3: Mark devices in temporary list as used by @name + /* Loop 2: Mark devices in temporary list as used by @name * and add them to driver list. However, if something goes * wrong, perform rollback. */ - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) - goto cleanup; virObjectLock(hostdev_mgr->activeScsiHostdevs); count = virSCSIDeviceListCount(list); @@ -371,7 +350,7 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, virObjectUnlock(hostdev_mgr->activeScsiHostdevs); - /* Loop 4: Temporary list was successfully merged with + /* Loop 3: Temporary list was successfully merged with * driver list, so steal all items to avoid freeing them * when freeing temporary list. */ @@ -392,6 +371,39 @@ error: cleanup: virObjectUnref(list); return -1; + +} + +int +qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i; + virHostdevManagerPtr hostdev_mgr; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return -1; + + /* Loop 1: Add the shared scsi host device to shared device + * table. + */ + for (i = 0; i < nhostdevs; i++) { + virDomainDeviceDef dev; + + dev.type = VIR_DOMAIN_DEVICE_HOSTDEV; + dev.data.hostdev = hostdevs[i]; + + if (qemuAddSharedDevice(driver, &dev, name) < 0) + return -1; + + if (qemuSetUnprivSGIO(&dev) < 0) + return -1; + } + + return virHostdevPrepareSCSIDevices(hostdev_mgr, name, hostdevs, nhostdevs); } -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 8 +++++--- 1 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 5eb12d1..a7b4e74 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -265,6 +265,7 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, static int virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) @@ -335,10 +336,10 @@ virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, goto error; } - if (virSCSIDeviceSetUsedBy(tmp, QEMU_DRIVER_NAME, name) < 0) + if (virSCSIDeviceSetUsedBy(tmp, drv_name, name) < 0) goto error; } else { - if (virSCSIDeviceSetUsedBy(scsi, QEMU_DRIVER_NAME, name) < 0) + if (virSCSIDeviceSetUsedBy(scsi, drv_name, name) < 0) goto error; VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); @@ -403,7 +404,8 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, return -1; } - return virHostdevPrepareSCSIDevices(hostdev_mgr, name, hostdevs, nhostdevs); + return virHostdevPrepareSCSIDevices(hostdev_mgr, QEMU_DRIVER_NAME, + name, hostdevs, nhostdevs); } -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libvirt_private.syms | 1 + src/qemu/qemu_hostdev.c | 112 ---------------------------------------------- src/util/virhostdev.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 6 +++ 4 files changed, 119 insertions(+), 112 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 01f6c81..fd92467 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1294,6 +1294,7 @@ virHookPresent; #util/virhostdev.h virHostdevManagerGetDefault; virHostdevPreparePCIDevices; +virHostdevPrepareSCSIDevices; virHostdevPrepareUSBDevices; virHostdevReAttachPCIDevices; virHostdevUpdateActivePciHostdevs; diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index a7b4e74..add887f 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -263,118 +263,6 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, hostdevs, nhostdevs, flags); } -static int -virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) -{ - size_t i, j; - int count; - virSCSIDeviceListPtr list; - virSCSIDevicePtr tmp; - - /* To prevent situation where SCSI device is assigned to two domains - * we need to keep a list of currently assigned SCSI devices. - * This is done in several loops which cannot be joined into one big - * loop. See qemuPrepareHostdevPCIDevices() - */ - if (!(list = virSCSIDeviceListNew())) - goto cleanup; - - /* Loop 1: build temporary list */ - for (i = 0; i < nhostdevs; i++) { - virDomainHostdevDefPtr hostdev = hostdevs[i]; - virSCSIDevicePtr scsi; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || - hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) - continue; - - if (hostdev->managed) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("SCSI host device doesn't support managed mode")); - goto cleanup; - } - - if (!(scsi = virSCSIDeviceNew(NULL, - hostdev->source.subsys.u.scsi.adapter, - hostdev->source.subsys.u.scsi.bus, - hostdev->source.subsys.u.scsi.target, - hostdev->source.subsys.u.scsi.unit, - hostdev->readonly, - hostdev->shareable))) - goto cleanup; - - if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) { - virSCSIDeviceFree(scsi); - goto cleanup; - } - } - - /* Loop 2: Mark devices in temporary list as used by @name - * and add them to driver list. However, if something goes - * wrong, perform rollback. - */ - virObjectLock(hostdev_mgr->activeScsiHostdevs); - count = virSCSIDeviceListCount(list); - - for (i = 0; i < count; i++) { - virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i); - if ((tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, - scsi))) { - bool scsi_shareable = virSCSIDeviceGetShareable(scsi); - bool tmp_shareable = virSCSIDeviceGetShareable(tmp); - - if (!(scsi_shareable && tmp_shareable)) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("SCSI device %s is already in use by " - "other domain(s) as '%s'"), - virSCSIDeviceGetName(tmp), - tmp_shareable ? "shareable" : "non-shareable"); - goto error; - } - - if (virSCSIDeviceSetUsedBy(tmp, drv_name, name) < 0) - goto error; - } else { - if (virSCSIDeviceSetUsedBy(scsi, drv_name, name) < 0) - goto error; - - VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); - - if (virSCSIDeviceListAdd(hostdev_mgr->activeScsiHostdevs, scsi) < 0) - goto error; - } - } - - virObjectUnlock(hostdev_mgr->activeScsiHostdevs); - - /* Loop 3: Temporary list was successfully merged with - * driver list, so steal all items to avoid freeing them - * when freeing temporary list. - */ - while (virSCSIDeviceListCount(list) > 0) { - tmp = virSCSIDeviceListGet(list, 0); - virSCSIDeviceListSteal(list, tmp); - } - - virObjectUnref(list); - return 0; - -error: - for (j = 0; j < i; j++) { - tmp = virSCSIDeviceListGet(list, i); - virSCSIDeviceListSteal(hostdev_mgr->activeScsiHostdevs, tmp); - } - virObjectUnlock(hostdev_mgr->activeScsiHostdevs); -cleanup: - virObjectUnref(list); - return -1; - -} - int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, const char *name, diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 896d451..5d1bb64 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -1118,3 +1118,115 @@ cleanup: virObjectUnref(list); return ret; } + +int +virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i, j; + int count; + virSCSIDeviceListPtr list; + virSCSIDevicePtr tmp; + + /* To prevent situation where SCSI device is assigned to two domains + * we need to keep a list of currently assigned SCSI devices. + * This is done in several loops which cannot be joined into one big + * loop. See qemuPrepareHostdevPCIDevices() + */ + if (!(list = virSCSIDeviceListNew())) + goto cleanup; + + /* Loop 1: build temporary list */ + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virSCSIDevicePtr scsi; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) + continue; + + if (hostdev->managed) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("SCSI host device doesn't support managed mode")); + goto cleanup; + } + + if (!(scsi = virSCSIDeviceNew(NULL, + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + hostdev->readonly, + hostdev->shareable))) + goto cleanup; + + if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) { + virSCSIDeviceFree(scsi); + goto cleanup; + } + } + + /* Loop 2: Mark devices in temporary list as used by @name + * and add them to driver list. However, if something goes + * wrong, perform rollback. + */ + virObjectLock(hostdev_mgr->activeScsiHostdevs); + count = virSCSIDeviceListCount(list); + + for (i = 0; i < count; i++) { + virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i); + if ((tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, + scsi))) { + bool scsi_shareable = virSCSIDeviceGetShareable(scsi); + bool tmp_shareable = virSCSIDeviceGetShareable(tmp); + + if (!(scsi_shareable && tmp_shareable)) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("SCSI device %s is already in use by " + "other domain(s) as '%s'"), + virSCSIDeviceGetName(tmp), + tmp_shareable ? "shareable" : "non-shareable"); + goto error; + } + + if (virSCSIDeviceSetUsedBy(tmp, drv_name, name) < 0) + goto error; + } else { + if (virSCSIDeviceSetUsedBy(scsi, drv_name, name) < 0) + goto error; + + VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); + + if (virSCSIDeviceListAdd(hostdev_mgr->activeScsiHostdevs, scsi) < 0) + goto error; + } + } + + virObjectUnlock(hostdev_mgr->activeScsiHostdevs); + + /* Loop 3: Temporary list was successfully merged with + * driver list, so steal all items to avoid freeing them + * when freeing temporary list. + */ + while (virSCSIDeviceListCount(list) > 0) { + tmp = virSCSIDeviceListGet(list, 0); + virSCSIDeviceListSteal(list, tmp); + } + + virObjectUnref(list); + return 0; + +error: + for (j = 0; j < i; j++) { + tmp = virSCSIDeviceListGet(list, i); + virSCSIDeviceListSteal(hostdev_mgr->activeScsiHostdevs, tmp); + } + virObjectUnlock(hostdev_mgr->activeScsiHostdevs); +cleanup: + virObjectUnref(list); + return -1; + +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index 77e31fc..fc36ead 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -65,6 +65,12 @@ virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, virDomainHostdevDefPtr *hostdevs, int nhostdevs, unsigned int flags); +int +virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); void virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, const char *drv_name, -- 1.6.0.2

Extract general code from qemuDomainReAttachHostUsbDevices to virHostdevDomainReAttachHostUsbDevices. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 32 ++++++++++++++++++++------------ 1 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index add887f..64372a3 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -342,20 +342,13 @@ out: virObjectUnref(cfg); } - -void -qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, - const char *name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) +static void +virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) { size_t i; - virHostdevManagerPtr hostdev_mgr; - - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) - return; - virObjectLock(hostdev_mgr->activeUsbHostdevs); for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; @@ -413,6 +406,21 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, virObjectUnlock(hostdev_mgr->activeUsbHostdevs); } +void +qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + virHostdevManagerPtr hostdev_mgr; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return; + + virHostdevReAttachUsbHostdevs(hostdev_mgr, name, hostdevs, nhostdevs); +} + void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 64372a3..2c92c2b 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -344,6 +344,7 @@ out: static void virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) @@ -393,7 +394,7 @@ virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, } virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname); - if (STREQ_NULLABLE(QEMU_DRIVER_NAME, usedby_drvname) && + if (STREQ_NULLABLE(drv_name, usedby_drvname) && STREQ_NULLABLE(name, usedby_domname)) { VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs", hostdev->source.subsys.u.usb.bus, @@ -418,7 +419,8 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (hostdev_mgr == NULL) return; - virHostdevReAttachUsbHostdevs(hostdev_mgr, name, hostdevs, nhostdevs); + virHostdevReAttachUsbHostdevs(hostdev_mgr, QEMU_DRIVER_NAME, + name, hostdevs, nhostdevs); } -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libvirt_private.syms | 1 + src/qemu/qemu_hostdev.c | 65 ---------------------------------------------- src/util/virhostdev.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 6 ++++ 4 files changed, 72 insertions(+), 65 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index fd92467..7da32a0 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1297,6 +1297,7 @@ virHostdevPreparePCIDevices; virHostdevPrepareSCSIDevices; virHostdevPrepareUSBDevices; virHostdevReAttachPCIDevices; +virHostdevReAttachUsbHostdevs; virHostdevUpdateActivePciHostdevs; virHostdevUpdateActiveScsiHostdevs; virHostdevUpdateActiveUsbHostdevs; diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 2c92c2b..6e65a02 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -342,71 +342,6 @@ out: virObjectUnref(cfg); } -static void -virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) -{ - size_t i; - virObjectLock(hostdev_mgr->activeUsbHostdevs); - for (i = 0; i < nhostdevs; i++) { - virDomainHostdevDefPtr hostdev = hostdevs[i]; - virUSBDevicePtr usb, tmp; - const char *usedby_drvname; - const char *usedby_domname; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - continue; - if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) - continue; - if (hostdev->missing) - continue; - - usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - NULL); - - if (!usb) { - VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", - hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - name); - continue; - } - - /* Delete only those USB devices which belongs - * to domain @name because qemuProcessStart() might - * have failed because USB device is already taken. - * Therefore we want to steal only those devices from - * the list which were taken by @name */ - - tmp = virUSBDeviceListFind(hostdev_mgr->activeUsbHostdevs, usb); - virUSBDeviceFree(usb); - - if (!tmp) { - VIR_WARN("Unable to find device %03d.%03d " - "in list of active USB devices", - hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device); - continue; - } - - virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname); - if (STREQ_NULLABLE(drv_name, usedby_drvname) && - STREQ_NULLABLE(name, usedby_domname)) { - VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs", - hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - name); - - virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, tmp); - } - } - virObjectUnlock(hostdev_mgr->activeUsbHostdevs); -} - void qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, const char *name, diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 5d1bb64..03962d3 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -1230,3 +1230,68 @@ cleanup: return -1; } + +void +virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i; + virObjectLock(hostdev_mgr->activeUsbHostdevs); + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virUSBDevicePtr usb, tmp; + const char *usedby_drvname; + const char *usedby_domname; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) + continue; + if (hostdev->missing) + continue; + + usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + NULL); + + if (!usb) { + VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + name); + continue; + } + + /* Delete only those USB devices which belongs + * to domain @name because qemuProcessStart() might + * have failed because USB device is already taken. + * Therefore we want to steal only those devices from + * the list which were taken by @name */ + + tmp = virUSBDeviceListFind(hostdev_mgr->activeUsbHostdevs, usb); + virUSBDeviceFree(usb); + + if (!tmp) { + VIR_WARN("Unable to find device %03d.%03d " + "in list of active USB devices", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device); + continue; + } + + virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname); + if (STREQ_NULLABLE(drv_name, usedby_drvname) && + STREQ_NULLABLE(name, usedby_domname)) { + VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs", + hostdev->source.subsys.u.usb.bus, + hostdev->source.subsys.u.usb.device, + name); + + virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, tmp); + } + } + virObjectUnlock(hostdev_mgr->activeUsbHostdevs); +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index fc36ead..a07ba27 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -78,6 +78,12 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, virDomainHostdevDefPtr *hostdevs, int nhostdevs, char *oldStateDir); +void +virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); int virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, const char *drv_name, -- 1.6.0.2

Extract general code from qemuDomainReAttachHostScsiDevices to virHostdevDomainReAttachHostScsiDevices. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 48 ++++++++++++++++++++++++++++++---------------- 1 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 6e65a02..66fb26a 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -358,31 +358,19 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, name, hostdevs, nhostdevs); } - -void -qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, - const char *name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) +static void +virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) { size_t i; - virHostdevManagerPtr hostdev_mgr; - - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) - return; virObjectLock(hostdev_mgr->activeScsiHostdevs); for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; virSCSIDevicePtr scsi; virSCSIDevicePtr tmp; - virDomainDeviceDef dev; - - dev.type = VIR_DOMAIN_DEVICE_HOSTDEV; - dev.data.hostdev = hostdev; - - ignore_value(qemuRemoveSharedDevice(driver, &dev, name)); if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) @@ -432,6 +420,32 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, } void +qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i; + virHostdevManagerPtr hostdev_mgr; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return; + + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virDomainDeviceDef dev; + + dev.type = VIR_DOMAIN_DEVICE_HOSTDEV; + dev.data.hostdev = hostdev; + + ignore_value(qemuRemoveSharedDevice(driver, &dev, name)); + } + + virHostdevReAttachScsiHostdevs(hostdev_mgr, name, hostdevs, nhostdevs); +} + +void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver, virDomainDefPtr def) { -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 66fb26a..7ef9b1b 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -360,6 +360,7 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, static void virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) @@ -413,7 +414,7 @@ virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, hostdev->source.subsys.u.scsi.unit, name); - virSCSIDeviceListDel(hostdev_mgr->activeScsiHostdevs, tmp, QEMU_DRIVER_NAME, name); + virSCSIDeviceListDel(hostdev_mgr->activeScsiHostdevs, tmp, drv_name, name); virSCSIDeviceFree(scsi); } virObjectUnlock(hostdev_mgr->activeScsiHostdevs); @@ -442,7 +443,8 @@ qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, ignore_value(qemuRemoveSharedDevice(driver, &dev, name)); } - virHostdevReAttachScsiHostdevs(hostdev_mgr, name, hostdevs, nhostdevs); + virHostdevReAttachScsiHostdevs(hostdev_mgr, QEMU_DRIVER_NAME, + name, hostdevs, nhostdevs); } void -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libvirt_private.syms | 1 + src/qemu/qemu_hostdev.c | 62 ---------------------------------------------- src/util/virhostdev.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 6 ++++ 4 files changed, 69 insertions(+), 62 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7da32a0..d657982 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1297,6 +1297,7 @@ virHostdevPreparePCIDevices; virHostdevPrepareSCSIDevices; virHostdevPrepareUSBDevices; virHostdevReAttachPCIDevices; +virHostdevReAttachScsiHostdevs; virHostdevReAttachUsbHostdevs; virHostdevUpdateActivePciHostdevs; virHostdevUpdateActiveScsiHostdevs; diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 7ef9b1b..b8d914a 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -358,68 +358,6 @@ qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, name, hostdevs, nhostdevs); } -static void -virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) -{ - size_t i; - - virObjectLock(hostdev_mgr->activeScsiHostdevs); - for (i = 0; i < nhostdevs; i++) { - virDomainHostdevDefPtr hostdev = hostdevs[i]; - virSCSIDevicePtr scsi; - virSCSIDevicePtr tmp; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || - hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) - continue; - - if (!(scsi = virSCSIDeviceNew(NULL, - hostdev->source.subsys.u.scsi.adapter, - hostdev->source.subsys.u.scsi.bus, - hostdev->source.subsys.u.scsi.target, - hostdev->source.subsys.u.scsi.unit, - hostdev->readonly, - hostdev->shareable))) { - VIR_WARN("Unable to reattach SCSI device %s:%d:%d:%d on domain %s", - hostdev->source.subsys.u.scsi.adapter, - hostdev->source.subsys.u.scsi.bus, - hostdev->source.subsys.u.scsi.target, - hostdev->source.subsys.u.scsi.unit, - name); - continue; - } - - /* Only delete the devices which are marked as being used by @name, - * because qemuProcessStart could fail on the half way. */ - - if (!(tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, scsi))) { - VIR_WARN("Unable to find device %s:%d:%d:%d " - "in list of active SCSI devices", - hostdev->source.subsys.u.scsi.adapter, - hostdev->source.subsys.u.scsi.bus, - hostdev->source.subsys.u.scsi.target, - hostdev->source.subsys.u.scsi.unit); - virSCSIDeviceFree(scsi); - continue; - } - - VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from activeScsiHostdevs", - hostdev->source.subsys.u.scsi.adapter, - hostdev->source.subsys.u.scsi.bus, - hostdev->source.subsys.u.scsi.target, - hostdev->source.subsys.u.scsi.unit, - name); - - virSCSIDeviceListDel(hostdev_mgr->activeScsiHostdevs, tmp, drv_name, name); - virSCSIDeviceFree(scsi); - } - virObjectUnlock(hostdev_mgr->activeScsiHostdevs); -} - void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver, const char *name, diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 03962d3..83d9916 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -1295,3 +1295,65 @@ virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, } virObjectUnlock(hostdev_mgr->activeUsbHostdevs); } + +void +virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) +{ + size_t i; + + virObjectLock(hostdev_mgr->activeScsiHostdevs); + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevDefPtr hostdev = hostdevs[i]; + virSCSIDevicePtr scsi; + virSCSIDevicePtr tmp; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) + continue; + + if (!(scsi = virSCSIDeviceNew(NULL, + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + hostdev->readonly, + hostdev->shareable))) { + VIR_WARN("Unable to reattach SCSI device %s:%d:%d:%d on domain %s", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + name); + continue; + } + + /* Only delete the devices which are marked as being used by @name, + * because qemuProcessStart could fail on the half way. */ + + if (!(tmp = virSCSIDeviceListFind(hostdev_mgr->activeScsiHostdevs, scsi))) { + VIR_WARN("Unable to find device %s:%d:%d:%d " + "in list of active SCSI devices", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit); + virSCSIDeviceFree(scsi); + continue; + } + + VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from activeScsiHostdevs", + hostdev->source.subsys.u.scsi.adapter, + hostdev->source.subsys.u.scsi.bus, + hostdev->source.subsys.u.scsi.target, + hostdev->source.subsys.u.scsi.unit, + name); + + virSCSIDeviceListDel(hostdev_mgr->activeScsiHostdevs, tmp, drv_name, name); + virSCSIDeviceFree(scsi); + } + virObjectUnlock(hostdev_mgr->activeScsiHostdevs); +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index a07ba27..0a60ec3 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -84,6 +84,12 @@ virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs); +void +virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); int virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, const char *drv_name, -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_driver.c | 33 ++++++++++++++++++++++----------- 1 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7d924b2..46d975e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11207,6 +11207,27 @@ out: } static int +virHostdevPciNodeDeviceDetach(virHostdevManagerPtr hostdev_mgr, + virPCIDevicePtr pci) +{ + int ret = -1; + + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); + + if (virPCIDeviceDetach(pci, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) { + goto out; + } + + ret = 0; +out: + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); + return ret; +} + +static int qemuNodeDeviceDetachFlags(virNodeDevicePtr dev, const char *driverName, unsigned int flags) @@ -11280,18 +11301,8 @@ qemuNodeDeviceDetachFlags(virNodeDevicePtr dev, hostdev_mgr = virHostdevManagerGetDefault(); if (hostdev_mgr == NULL) goto cleanup; - virObjectLock(hostdev_mgr->activePciHostdevs); - virObjectLock(hostdev_mgr->inactivePciHostdevs); - if (virPCIDeviceDetach(pci, hostdev_mgr->activePciHostdevs, - hostdev_mgr->inactivePciHostdevs) < 0) { - goto out; - } - - ret = 0; -out: - virObjectUnlock(hostdev_mgr->inactivePciHostdevs); - virObjectUnlock(hostdev_mgr->activePciHostdevs); + ret = virHostdevPciNodeDeviceDetach(hostdev_mgr, pci); cleanup: virPCIDeviceFree(pci); virNodeDeviceDefFree(def); -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_driver.c | 67 ++++++++++++++++++++++++++++-------------------- 1 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 46d975e..1b81689 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11317,37 +11317,11 @@ qemuNodeDeviceDettach(virNodeDevicePtr dev) } static int -qemuNodeDeviceReAttach(virNodeDevicePtr dev) +virHostdevPciNodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr, + virPCIDevicePtr pci) { - virPCIDevicePtr pci = NULL; virPCIDevicePtr other; - unsigned domain = 0, bus = 0, slot = 0, function = 0; int ret = -1; - virNodeDeviceDefPtr def = NULL; - char *xml = NULL; - virHostdevManagerPtr hostdev_mgr; - - xml = virNodeDeviceGetXMLDesc(dev, 0); - if (!xml) - goto cleanup; - - def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); - if (!def) - goto cleanup; - - if (virNodeDeviceReAttachEnsureACL(dev->conn, def) < 0) - goto cleanup; - - if (qemuNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0) - goto cleanup; - - pci = virPCIDeviceNew(domain, bus, slot, function); - if (!pci) - goto cleanup; - - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) - goto cleanup_pci; virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); @@ -11380,6 +11354,43 @@ qemuNodeDeviceReAttach(virNodeDevicePtr dev) out: virObjectUnlock(hostdev_mgr->inactivePciHostdevs); virObjectUnlock(hostdev_mgr->activePciHostdevs); + return ret; +} + +static int +qemuNodeDeviceReAttach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci = NULL; + unsigned domain = 0, bus = 0, slot = 0, function = 0; + int ret = -1; + virNodeDeviceDefPtr def = NULL; + char *xml = NULL; + virHostdevManagerPtr hostdev_mgr; + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto cleanup; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto cleanup; + + if (virNodeDeviceReAttachEnsureACL(dev->conn, def) < 0) + goto cleanup; + + if (qemuNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0) + goto cleanup; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + goto cleanup; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + goto cleanup_pci; + + ret = virHostdevPciNodeDeviceReAttach(hostdev_mgr, pci); + cleanup_pci: virPCIDeviceFree(pci); cleanup: -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_driver.c | 29 ++++++++++++++++++++--------- 1 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 1b81689..44ac556 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11400,6 +11400,25 @@ cleanup: } static int +virHostdevPciNodeDeviceReset(virHostdevManagerPtr hostdev_mgr, + virPCIDevicePtr pci) +{ + int ret = -1; + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); + if (virPCIDeviceReset(pci, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) + goto out; + + ret = 0; +out: + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); + return ret; +} + + +static int qemuNodeDeviceReset(virNodeDevicePtr dev) { virPCIDevicePtr pci; @@ -11430,16 +11449,8 @@ qemuNodeDeviceReset(virNodeDevicePtr dev) hostdev_mgr = virHostdevManagerGetDefault(); if (hostdev_mgr == NULL) goto cleanup_pci; - virObjectLock(hostdev_mgr->activePciHostdevs); - virObjectLock(hostdev_mgr->inactivePciHostdevs); - if (virPCIDeviceReset(pci, hostdev_mgr->activePciHostdevs, - hostdev_mgr->inactivePciHostdevs) < 0) - goto out; + ret = virHostdevPciNodeDeviceReset(hostdev_mgr, pci); - ret = 0; -out: - virObjectUnlock(hostdev_mgr->inactivePciHostdevs); - virObjectUnlock(hostdev_mgr->activePciHostdevs); cleanup_pci: virPCIDeviceFree(pci); cleanup: -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libvirt_private.syms | 3 ++ src/qemu/qemu_driver.c | 81 ---------------------------------------------- src/util/virhostdev.c | 80 +++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 8 ++++ 4 files changed, 91 insertions(+), 81 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d657982..c924854 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1293,6 +1293,9 @@ virHookPresent; #util/virhostdev.h virHostdevManagerGetDefault; +virHostdevPciNodeDeviceDetach; +virHostdevPciNodeDeviceReAttach; +virHostdevPciNodeDeviceReset; virHostdevPreparePCIDevices; virHostdevPrepareSCSIDevices; virHostdevPrepareUSBDevices; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 44ac556..76e91d9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -11207,27 +11207,6 @@ out: } static int -virHostdevPciNodeDeviceDetach(virHostdevManagerPtr hostdev_mgr, - virPCIDevicePtr pci) -{ - int ret = -1; - - virObjectLock(hostdev_mgr->activePciHostdevs); - virObjectLock(hostdev_mgr->inactivePciHostdevs); - - if (virPCIDeviceDetach(pci, hostdev_mgr->activePciHostdevs, - hostdev_mgr->inactivePciHostdevs) < 0) { - goto out; - } - - ret = 0; -out: - virObjectUnlock(hostdev_mgr->inactivePciHostdevs); - virObjectUnlock(hostdev_mgr->activePciHostdevs); - return ret; -} - -static int qemuNodeDeviceDetachFlags(virNodeDevicePtr dev, const char *driverName, unsigned int flags) @@ -11317,47 +11296,6 @@ qemuNodeDeviceDettach(virNodeDevicePtr dev) } static int -virHostdevPciNodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr, - virPCIDevicePtr pci) -{ - virPCIDevicePtr other; - int ret = -1; - - virObjectLock(hostdev_mgr->activePciHostdevs); - virObjectLock(hostdev_mgr->inactivePciHostdevs); - other = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, pci); - if (other) { - const char *other_drvname = NULL; - const char *other_domname = NULL; - virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname); - - if (other_drvname && other_domname) - virReportError(VIR_ERR_OPERATION_INVALID, - _("PCI device %s is still in use by " - "driver %s, domain %s"), - virPCIDeviceGetName(pci), - other_drvname, other_domname); - else - virReportError(VIR_ERR_OPERATION_INVALID, - _("PCI device %s is still in use"), - virPCIDeviceGetName(pci)); - goto out; - } - - virPCIDeviceReattachInit(pci); - - if (virPCIDeviceReattach(pci, hostdev_mgr->activePciHostdevs, - hostdev_mgr->inactivePciHostdevs) < 0) - goto out; - - ret = 0; -out: - virObjectUnlock(hostdev_mgr->inactivePciHostdevs); - virObjectUnlock(hostdev_mgr->activePciHostdevs); - return ret; -} - -static int qemuNodeDeviceReAttach(virNodeDevicePtr dev) { virPCIDevicePtr pci = NULL; @@ -11400,25 +11338,6 @@ cleanup: } static int -virHostdevPciNodeDeviceReset(virHostdevManagerPtr hostdev_mgr, - virPCIDevicePtr pci) -{ - int ret = -1; - virObjectLock(hostdev_mgr->activePciHostdevs); - virObjectLock(hostdev_mgr->inactivePciHostdevs); - if (virPCIDeviceReset(pci, hostdev_mgr->activePciHostdevs, - hostdev_mgr->inactivePciHostdevs) < 0) - goto out; - - ret = 0; -out: - virObjectUnlock(hostdev_mgr->inactivePciHostdevs); - virObjectUnlock(hostdev_mgr->activePciHostdevs); - return ret; -} - - -static int qemuNodeDeviceReset(virNodeDevicePtr dev) { virPCIDevicePtr pci; diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 83d9916..e3b818e 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -1357,3 +1357,83 @@ virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, } virObjectUnlock(hostdev_mgr->activeScsiHostdevs); } + +int +virHostdevPciNodeDeviceDetach(virHostdevManagerPtr hostdev_mgr, + virPCIDevicePtr pci) +{ + int ret = -1; + + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); + + if (virPCIDeviceDetach(pci, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) { + goto out; + } + + ret = 0; +out: + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); + return ret; +} + +int +virHostdevPciNodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr, + virPCIDevicePtr pci) +{ + virPCIDevicePtr other; + int ret = -1; + + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); + other = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, pci); + if (other) { + const char *other_drvname = NULL; + const char *other_domname = NULL; + virPCIDeviceGetUsedBy(other, &other_drvname, &other_domname); + + if (other_drvname && other_domname) + virReportError(VIR_ERR_OPERATION_INVALID, + _("PCI device %s is still in use by " + "driver %s, domain %s"), + virPCIDeviceGetName(pci), + other_drvname, other_domname); + else + virReportError(VIR_ERR_OPERATION_INVALID, + _("PCI device %s is still in use"), + virPCIDeviceGetName(pci)); + goto out; + } + + virPCIDeviceReattachInit(pci); + + if (virPCIDeviceReattach(pci, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) + goto out; + + ret = 0; +out: + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); + return ret; +} + +int +virHostdevPciNodeDeviceReset(virHostdevManagerPtr hostdev_mgr, + virPCIDevicePtr pci) +{ + int ret = -1; + virObjectLock(hostdev_mgr->activePciHostdevs); + virObjectLock(hostdev_mgr->inactivePciHostdevs); + if (virPCIDeviceReset(pci, hostdev_mgr->activePciHostdevs, + hostdev_mgr->inactivePciHostdevs) < 0) + goto out; + + ret = 0; +out: + virObjectUnlock(hostdev_mgr->inactivePciHostdevs); + virObjectUnlock(hostdev_mgr->activePciHostdevs); + return ret; +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index 0a60ec3..bb097b0 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -103,4 +103,12 @@ virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, const char *drv_name, virDomainDefPtr def); +/* functions used by NodeDevDetach/Reattach/Reset */ +int virHostdevPciNodeDeviceDetach(virHostdevManagerPtr mgr, + virPCIDevicePtr pci); +int virHostdevPciNodeDeviceReAttach(virHostdevManagerPtr mgr, + virPCIDevicePtr pci); +int virHostdevPciNodeDeviceReset(virHostdevManagerPtr mgr, + virPCIDevicePtr pci); + #endif /* __VIR_HOSTDEV_H__ */ -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/util/virhostdev.c | 38 ++++++++++++++++++++------------------ src/util/virhostdev.h | 10 +++++----- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index e3b818e..9cd11d4 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -429,7 +429,7 @@ virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, int virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, const unsigned char *uuid, virDomainHostdevDefPtr *hostdevs, int nhostdevs, @@ -550,7 +550,7 @@ virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, activeDev = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, dev); if (activeDev) - virPCIDeviceSetUsedBy(activeDev, drv_name, name); + virPCIDeviceSetUsedBy(activeDev, drv_name, dom_name); } /* Loop 8: Now set the original states for hostdev def */ @@ -667,7 +667,7 @@ qemuReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) void virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs, char *oldStateDir) @@ -706,7 +706,7 @@ virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, const char *usedby_domname; virPCIDeviceGetUsedBy(activeDev, &usedby_drvname, &usedby_domname); if (STRNEQ_NULLABLE(drv_name, usedby_drvname) || - STRNEQ_NULLABLE(name, usedby_domname)) { + STRNEQ_NULLABLE(dom_name, usedby_domname)) { virPCIDeviceListDel(pcidevs, dev); continue; } @@ -906,7 +906,7 @@ cleanup: static int virHostdevMarkUsbHostdevs(virHostdevManagerPtr mgr, const char *drv_name, - const char *name, + const char *dom_name, virUSBDeviceListPtr list) { size_t i, j; @@ -936,9 +936,10 @@ virHostdevMarkUsbHostdevs(virHostdevManagerPtr mgr, goto error; } - virUSBDeviceSetUsedBy(usb, drv_name, name); + virUSBDeviceSetUsedBy(usb, drv_name, dom_name); VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs", - virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name); + virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), + dom_name); /* * The caller is responsible to steal these usb devices * from the virUSBDeviceList that passed in on success, @@ -1122,7 +1123,7 @@ cleanup: int virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { @@ -1192,10 +1193,10 @@ virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, goto error; } - if (virSCSIDeviceSetUsedBy(tmp, drv_name, name) < 0) + if (virSCSIDeviceSetUsedBy(tmp, drv_name, dom_name) < 0) goto error; } else { - if (virSCSIDeviceSetUsedBy(scsi, drv_name, name) < 0) + if (virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name) < 0) goto error; VIR_DEBUG("Adding %s to activeScsiHostdevs", virSCSIDeviceGetName(scsi)); @@ -1234,7 +1235,7 @@ cleanup: void virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { @@ -1261,7 +1262,7 @@ virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device, - name); + dom_name); continue; } @@ -1284,11 +1285,11 @@ virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname); if (STREQ_NULLABLE(drv_name, usedby_drvname) && - STREQ_NULLABLE(name, usedby_domname)) { + STREQ_NULLABLE(dom_name, usedby_domname)) { VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs", hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device, - name); + dom_name); virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, tmp); } @@ -1299,7 +1300,7 @@ virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, void virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { @@ -1327,7 +1328,7 @@ virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, hostdev->source.subsys.u.scsi.bus, hostdev->source.subsys.u.scsi.target, hostdev->source.subsys.u.scsi.unit, - name); + dom_name); continue; } @@ -1350,9 +1351,10 @@ virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, hostdev->source.subsys.u.scsi.bus, hostdev->source.subsys.u.scsi.target, hostdev->source.subsys.u.scsi.unit, - name); + dom_name); - virSCSIDeviceListDel(hostdev_mgr->activeScsiHostdevs, tmp, drv_name, name); + virSCSIDeviceListDel(hostdev_mgr->activeScsiHostdevs, tmp, + drv_name, dom_name); virSCSIDeviceFree(scsi); } virObjectUnlock(hostdev_mgr->activeScsiHostdevs); diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index bb097b0..3e8ca6d 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -53,7 +53,7 @@ virHostdevManagerPtr virHostdevManagerGetDefault(void); int virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, const unsigned char *uuid, virDomainHostdevDefPtr *hostdevs, int nhostdevs, @@ -68,26 +68,26 @@ virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, int virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs); void virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs, char *oldStateDir); void virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs); void virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, const char *drv_name, - const char *name, + const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs); int -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libvirt_private.syms | 8 +++--- src/qemu/qemu_hostdev.c | 16 +++++++------- src/util/virhostdev.c | 52 +++++++++++++++++++++++----------------------- src/util/virhostdev.h | 40 +++++++++++++++++----------------- 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c924854..a604c54 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1296,10 +1296,10 @@ virHostdevManagerGetDefault; virHostdevPciNodeDeviceDetach; virHostdevPciNodeDeviceReAttach; virHostdevPciNodeDeviceReset; -virHostdevPreparePCIDevices; -virHostdevPrepareSCSIDevices; -virHostdevPrepareUSBDevices; -virHostdevReAttachPCIDevices; +virHostdevPreparePciHostdevs; +virHostdevPrepareScsiHostdevs; +virHostdevPrepareUsbHostdevs; +virHostdevReAttachPciHostdevs; virHostdevReAttachScsiHostdevs; virHostdevReAttachUsbHostdevs; virHostdevUpdateActivePciHostdevs; diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index b8d914a..8b67b88 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -237,8 +237,8 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (hostdev_mgr == NULL) goto out; - ret = virHostdevPreparePCIDevices(hostdev_mgr, QEMU_DRIVER_NAME, - name, uuid, hostdevs, + ret = virHostdevPreparePciHostdevs(hostdev_mgr, QEMU_DRIVER_NAME, + name, uuid, hostdevs, nhostdevs, flags); out: @@ -259,8 +259,8 @@ qemuPrepareHostUSBDevices(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (hostdev_mgr == NULL) return -1; - return virHostdevPrepareUSBDevices(hostdev_mgr, QEMU_DRIVER_NAME, dom_name, - hostdevs, nhostdevs, flags); + return virHostdevPrepareUsbHostdevs(hostdev_mgr, QEMU_DRIVER_NAME, dom_name, + hostdevs, nhostdevs, flags); } int @@ -292,8 +292,8 @@ qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver, return -1; } - return virHostdevPrepareSCSIDevices(hostdev_mgr, QEMU_DRIVER_NAME, - name, hostdevs, nhostdevs); + return virHostdevPrepareScsiHostdevs(hostdev_mgr, QEMU_DRIVER_NAME, + name, hostdevs, nhostdevs); } @@ -335,8 +335,8 @@ qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver, if (hostdev_mgr == NULL) goto out; - virHostdevReAttachPCIDevices(hostdev_mgr, QEMU_DRIVER_NAME, name, - hostdevs, nhostdevs, oldStateDir); + virHostdevReAttachPciHostdevs(hostdev_mgr, QEMU_DRIVER_NAME, name, + hostdevs, nhostdevs, oldStateDir); out: virObjectUnref(cfg); diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 9cd11d4..1ee44cf 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -427,13 +427,13 @@ virHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, } int -virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *dom_name, - const unsigned char *uuid, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs, - unsigned int flags) +virHostdevPreparePciHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *dom_name, + const unsigned char *uuid, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + unsigned int flags) { virPCIDeviceListPtr pcidevs = NULL; int last_processed_hostdev_vf = -1; @@ -665,12 +665,12 @@ qemuReattachPciDevice(virPCIDevicePtr dev, virHostdevManagerPtr mgr) * For upgrade purpose: see virHostdevNetConfigRestore */ void -virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *dom_name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs, - char *oldStateDir) +virHostdevReAttachPciHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + char *oldStateDir) { virPCIDeviceListPtr pcidevs; size_t i; @@ -1050,12 +1050,12 @@ out: } int -virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *dom_name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs, - unsigned int flags) +virHostdevPrepareUsbHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + unsigned int flags) { size_t i; int ret = -1; @@ -1066,7 +1066,7 @@ virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr, /* 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() + * loop. See virHostdevPrepareHostdevPciHostdevs() */ if (!(list = virUSBDeviceListNew())) goto cleanup; @@ -1121,11 +1121,11 @@ cleanup: } int -virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *dom_name, - virDomainHostdevDefPtr *hostdevs, - int nhostdevs) +virHostdevPrepareScsiHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs) { size_t i, j; int count; @@ -1135,7 +1135,7 @@ virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, /* To prevent situation where SCSI device is assigned to two domains * we need to keep a list of currently assigned SCSI devices. * This is done in several loops which cannot be joined into one big - * loop. See qemuPrepareHostdevPCIDevices() + * loop. See virHostdevPrepareHostdevPciHostdevs() */ if (!(list = virSCSIDeviceListNew())) goto cleanup; diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index 3e8ca6d..bdfc908 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -51,33 +51,33 @@ struct _virHostdevManager{ virHostdevManagerPtr virHostdevManagerGetDefault(void); int -virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr, - const char *drv_name, - const char *dom_name, - const unsigned char *uuid, - 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); -int -virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr, +virHostdevPreparePciHostdevs(virHostdevManagerPtr hostdev_mgr, const char *drv_name, const char *dom_name, + const unsigned char *uuid, virDomainHostdevDefPtr *hostdevs, - int nhostdevs); -void -virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr, + int nhostdevs, + unsigned int flags); +int +virHostdevPrepareUsbHostdevs(virHostdevManagerPtr hostdev_mgr, const char *drv_name, const char *dom_name, virDomainHostdevDefPtr *hostdevs, int nhostdevs, - char *oldStateDir); + unsigned int flags); +int +virHostdevPrepareScsiHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs); +void +virHostdevReAttachPciHostdevs(virHostdevManagerPtr hostdev_mgr, + const char *drv_name, + const char *dom_name, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, + char *oldStateDir); void virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, const char *drv_name, -- 1.6.0.2

Changes parameter from vm def to specific hostdevs info and name info, so that it could be used more widely, e.g, could be used without full vm def info. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/qemu/qemu_hostdev.c | 9 ++++++--- src/util/virhostdev.c | 35 ++++++++++++++++++++--------------- src/util/virhostdev.h | 12 +++++++++--- 3 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 8b67b88..56afe0a 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -53,7 +53,8 @@ qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (mgr == NULL) return -1; - return virHostdevUpdateActivePciHostdevs(mgr, QEMU_DRIVER_NAME, def); + return virHostdevUpdateActivePciHostdevs(mgr, def->hostdevs, def->nhostdevs, + QEMU_DRIVER_NAME, def->name); } int @@ -68,7 +69,8 @@ qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (mgr == NULL) return -1; - return virHostdevUpdateActiveUsbHostdevs(mgr, QEMU_DRIVER_NAME, def); + return virHostdevUpdateActiveUsbHostdevs(mgr, def->hostdevs, def->nhostdevs, + QEMU_DRIVER_NAME, def->name); } int @@ -83,7 +85,8 @@ qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver ATTRIBUTE_UNUSED, if (mgr == NULL) return -1; - return virHostdevUpdateActiveScsiHostdevs(mgr, QEMU_DRIVER_NAME, def); + return virHostdevUpdateActiveScsiHostdevs(mgr, def->hostdevs, def->nhostdevs, + QEMU_DRIVER_NAME, def->name); } bool diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 1ee44cf..3160bb6 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -753,9 +753,10 @@ cleanup: int virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, const char *drv_name, - virDomainDefPtr def) - + const char *dom_name) { virDomainHostdevDefPtr hostdev = NULL; virPCIDevicePtr dev = NULL; @@ -765,8 +766,8 @@ virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, virObjectLock(mgr->activePciHostdevs); virObjectLock(mgr->inactivePciHostdevs); - for (i = 0; i < def->nhostdevs; i++) { - hostdev = def->hostdevs[i]; + for (i = 0; i < nhostdevs; i++) { + hostdev = hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; @@ -791,7 +792,7 @@ virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, goto cleanup; } - virPCIDeviceSetUsedBy(dev, drv_name, def->name); + virPCIDeviceSetUsedBy(dev, drv_name, dom_name); /* Setup the original states for the PCI device */ virPCIDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub); @@ -813,17 +814,19 @@ cleanup: int virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, const char *drv_name, - virDomainDefPtr def) + const char *dom_name) { virDomainHostdevDefPtr hostdev = NULL; size_t i; int ret = -1; virObjectLock(mgr->activeUsbHostdevs); - for (i = 0; i < def->nhostdevs; i++) { + for (i = 0; i < nhostdevs; i++) { virUSBDevicePtr usb = NULL; - hostdev = def->hostdevs[i]; + hostdev = hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; @@ -837,11 +840,11 @@ virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", hostdev->source.subsys.u.usb.bus, hostdev->source.subsys.u.usb.device, - def->name); + dom_name); continue; } - virUSBDeviceSetUsedBy(usb, drv_name, def->name); + virUSBDeviceSetUsedBy(usb, drv_name, dom_name); if (virUSBDeviceListAdd(mgr->activeUsbHostdevs, usb) < 0) { virUSBDeviceFree(usb); @@ -856,8 +859,10 @@ cleanup: int virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, const char *drv_name, - virDomainDefPtr def) + const char *dom_name) { virDomainHostdevDefPtr hostdev = NULL; size_t i; @@ -866,8 +871,8 @@ virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, virSCSIDevicePtr tmp = NULL; virObjectLock(mgr->activeScsiHostdevs); - for (i = 0; i < def->nhostdevs; i++) { - hostdev = def->hostdevs[i]; + for (i = 0; i < nhostdevs; i++) { + hostdev = hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI) @@ -883,13 +888,13 @@ virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, goto cleanup; if ((tmp = virSCSIDeviceListFind(mgr->activeScsiHostdevs, scsi))) { - if (virSCSIDeviceSetUsedBy(tmp, drv_name, def->name) < 0) { + if (virSCSIDeviceSetUsedBy(tmp, drv_name, dom_name) < 0) { virSCSIDeviceFree(scsi); goto cleanup; } virSCSIDeviceFree(scsi); } else { - if (virSCSIDeviceSetUsedBy(scsi, drv_name, def->name) < 0 || + if (virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name) < 0 || virSCSIDeviceListAdd(mgr->activeScsiHostdevs, scsi) < 0) { virSCSIDeviceFree(scsi); goto cleanup; diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index bdfc908..387c160 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -92,16 +92,22 @@ virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, int nhostdevs); int virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, const char *drv_name, - virDomainDefPtr def); + const char *dom_name); int virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, const char *drv_name, - virDomainDefPtr def); + const char *dom_name); int virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, + virDomainHostdevDefPtr *hostdevs, + int nhostdevs, const char *drv_name, - virDomainDefPtr def); + const char *dom_name); /* functions used by NodeDevDetach/Reattach/Reset */ int virHostdevPciNodeDeviceDetach(virHostdevManagerPtr mgr, -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libvirt_private.syms | 4 ++ src/util/virhostdev.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 24 ++++++++++- 3 files changed, 130 insertions(+), 2 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a604c54..1b73518 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1296,15 +1296,19 @@ virHostdevManagerGetDefault; virHostdevPciNodeDeviceDetach; virHostdevPciNodeDeviceReAttach; virHostdevPciNodeDeviceReset; +virHostdevPrepareDomainHostdevs; virHostdevPreparePciHostdevs; virHostdevPrepareScsiHostdevs; virHostdevPrepareUsbHostdevs; +virHostdevReAttachDomainHostdevs; virHostdevReAttachPciHostdevs; virHostdevReAttachScsiHostdevs; virHostdevReAttachUsbHostdevs; virHostdevUpdateActivePciHostdevs; virHostdevUpdateActiveScsiHostdevs; virHostdevUpdateActiveUsbHostdevs; +virHostdevUpdateDomainActiveHostdevs; + # util/viridentity.h virIdentityGetAttr; diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 3160bb6..9c189a7 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -1444,3 +1444,107 @@ out: virObjectUnlock(hostdev_mgr->activePciHostdevs); return ret; } + +int +virHostdevPrepareDomainHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags) +{ + if (!def->nhostdevs) + return 0; + + if (mgr == NULL) + return -1; + + if (flags & VIR_SP_PCI_HOSTDEV) { + if (virHostdevPreparePciHostdevs(mgr, driver, + def->name, def->uuid, + def->hostdevs, + def->nhostdevs, + flags) < 0) + return -1; + } + + if (flags & VIR_SP_USB_HOSTDEV) { + bool coldBoot = !!(flags & VIR_COLD_BOOT); + if (virHostdevPrepareUsbHostdevs(mgr, driver, def->name, + def->hostdevs, def->nhostdevs, + coldBoot) < 0) + return -1; + } + + if (flags & VIR_SP_SCSI_HOSTDEV) { + if (virHostdevPrepareScsiHostdevs(mgr, driver, def->name, + def->hostdevs, def->nhostdevs) < 0) + return -1; + } + + return 0; +} + +/* @oldStateDir + * For upgrade purpose: see virHostdevReAttachPciHostdevs + */ +void +virHostdevReAttachDomainHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags, + char *oldStateDir) +{ + if (!def->nhostdevs || !mgr) + return; + + if (flags & VIR_SP_PCI_HOSTDEV) { + virHostdevReAttachPciHostdevs(mgr, driver, def->name, + def->hostdevs, def->nhostdevs, + oldStateDir); + } + + if (flags & VIR_SP_USB_HOSTDEV) { + virHostdevReAttachUsbHostdevs(mgr, driver, def->name, + def->hostdevs, def->nhostdevs); + } + + if (flags & VIR_SP_SCSI_HOSTDEV) { + virHostdevReAttachScsiHostdevs(mgr, driver, def->name, + def->hostdevs, def->nhostdevs); + } +} + +int +virHostdevUpdateDomainActiveHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags) +{ + if (!def->nhostdevs) + return 0; + + if (flags & VIR_SP_PCI_HOSTDEV) { + if (virHostdevUpdateActivePciHostdevs(mgr, + def->hostdevs, + def->nhostdevs, + driver, def->name) < 0) + return -1; + } + + if (flags & VIR_SP_USB_HOSTDEV) { + if (virHostdevUpdateActiveUsbHostdevs(mgr, + def->hostdevs, + def->nhostdevs, + driver, def->name) < 0) + return -1; + } + + if (flags & VIR_SP_SCSI_HOSTDEV) { + if (virHostdevUpdateActiveScsiHostdevs(mgr, + def->hostdevs, + def->nhostdevs, + driver, def->name) < 0) + return -1; + } + + return 0; +} diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h index 387c160..74f1221 100644 --- a/src/util/virhostdev.h +++ b/src/util/virhostdev.h @@ -33,8 +33,12 @@ # include "domain_conf.h" typedef enum { - VIR_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */ - VIR_COLD_BOOT = (1 << 1), /* cold boot */ + VIR_STRICT_ACS_CHECK = (1 << 0), /* strict acs check */ + VIR_COLD_BOOT = (1 << 1), /* cold boot */ + + VIR_SP_PCI_HOSTDEV = (1 << 8), /* support pci passthrough */ + VIR_SP_USB_HOSTDEV = (1 << 9), /* support usb passthrough */ + VIR_SP_SCSI_HOSTDEV = (1 << 10), /* support scsi passthrough */ } virHostdevFlag; @@ -108,6 +112,22 @@ virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, int nhostdevs, const char *drv_name, const char *dom_name); +int +virHostdevUpdateDomainActiveHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags); +int +virHostdevPrepareDomainHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags); +void +virHostdevReAttachDomainHostdevs(virHostdevManagerPtr mgr, + const char *driver, + virDomainDefPtr def, + unsigned int flags, + char *oldStateDir); /* functions used by NodeDevDetach/Reattach/Reset */ int virHostdevPciNodeDeviceDetach(virHostdevManagerPtr mgr, -- 1.6.0.2

Check NULL parameter inputs Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/util/virhostdev.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 59 insertions(+), 0 deletions(-) diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 9c189a7..73844a6 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -440,6 +440,11 @@ virHostdevPreparePciHostdevs(virHostdevManagerPtr hostdev_mgr, size_t i; int ret = -1; + if (!nhostdevs) + return 0; + if (hostdev_mgr == NULL) + return -1; + virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); @@ -675,6 +680,11 @@ virHostdevReAttachPciHostdevs(virHostdevManagerPtr hostdev_mgr, virPCIDeviceListPtr pcidevs; size_t i; + if (!nhostdevs) + return; + if (hostdev_mgr == NULL) + return; + virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); @@ -763,6 +773,11 @@ virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, size_t i; int ret = -1; + if (!nhostdevs) + return 0; + if (mgr == NULL) + return -1; + virObjectLock(mgr->activePciHostdevs); virObjectLock(mgr->inactivePciHostdevs); @@ -823,6 +838,11 @@ virHostdevUpdateActiveUsbHostdevs(virHostdevManagerPtr mgr, size_t i; int ret = -1; + if (!nhostdevs) + return 0; + if (mgr == NULL) + return -1; + virObjectLock(mgr->activeUsbHostdevs); for (i = 0; i < nhostdevs; i++) { virUSBDevicePtr usb = NULL; @@ -870,6 +890,11 @@ virHostdevUpdateActiveScsiHostdevs(virHostdevManagerPtr mgr, virSCSIDevicePtr scsi = NULL; virSCSIDevicePtr tmp = NULL; + if (!nhostdevs) + return 0; + if (mgr == NULL) + return -1; + virObjectLock(mgr->activeScsiHostdevs); for (i = 0; i < nhostdevs; i++) { hostdev = hostdevs[i]; @@ -1068,6 +1093,11 @@ virHostdevPrepareUsbHostdevs(virHostdevManagerPtr hostdev_mgr, virUSBDevicePtr tmp; bool coldBoot = !!(flags & VIR_COLD_BOOT); + if (!nhostdevs) + return 0; + if (hostdev_mgr == NULL) + return -1; + /* 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 @@ -1137,6 +1167,11 @@ virHostdevPrepareScsiHostdevs(virHostdevManagerPtr hostdev_mgr, virSCSIDeviceListPtr list; virSCSIDevicePtr tmp; + if (!nhostdevs) + return 0; + if (hostdev_mgr == NULL) + return -1; + /* To prevent situation where SCSI device is assigned to two domains * we need to keep a list of currently assigned SCSI devices. * This is done in several loops which cannot be joined into one big @@ -1245,6 +1280,12 @@ virHostdevReAttachUsbHostdevs(virHostdevManagerPtr hostdev_mgr, int nhostdevs) { size_t i; + + if (!nhostdevs) + return; + if (hostdev_mgr == NULL) + return; + virObjectLock(hostdev_mgr->activeUsbHostdevs); for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; @@ -1311,6 +1352,11 @@ virHostdevReAttachScsiHostdevs(virHostdevManagerPtr hostdev_mgr, { size_t i; + if (!nhostdevs) + return; + if (hostdev_mgr == NULL) + return; + virObjectLock(hostdev_mgr->activeScsiHostdevs); for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; @@ -1371,6 +1417,9 @@ virHostdevPciNodeDeviceDetach(virHostdevManagerPtr hostdev_mgr, { int ret = -1; + if (hostdev_mgr == NULL || pci == NULL) + return -1; + virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); @@ -1393,6 +1442,9 @@ virHostdevPciNodeDeviceReAttach(virHostdevManagerPtr hostdev_mgr, virPCIDevicePtr other; int ret = -1; + if (hostdev_mgr == NULL || pci == NULL) + return -1; + virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); other = virPCIDeviceListFind(hostdev_mgr->activePciHostdevs, pci); @@ -1432,6 +1484,10 @@ virHostdevPciNodeDeviceReset(virHostdevManagerPtr hostdev_mgr, virPCIDevicePtr pci) { int ret = -1; + + if (hostdev_mgr == NULL || pci == NULL) + return -1; + virObjectLock(hostdev_mgr->activePciHostdevs); virObjectLock(hostdev_mgr->inactivePciHostdevs); if (virPCIDeviceReset(pci, hostdev_mgr->activePciHostdevs, @@ -1522,6 +1578,9 @@ virHostdevUpdateDomainActiveHostdevs(virHostdevManagerPtr mgr, if (!def->nhostdevs) return 0; + if (mgr == NULL) + return -1; + if (flags & VIR_SP_PCI_HOSTDEV) { if (virHostdevUpdateActivePciHostdevs(mgr, def->hostdevs, -- 1.6.0.2

Add unit test for hostdev common library. Current tests are based on virpcimock. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- .gitignore | 1 + tests/Makefile.am | 5 + tests/virhostdevtest.c | 507 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 513 insertions(+), 0 deletions(-) create mode 100644 tests/virhostdevtest.c diff --git a/.gitignore b/.gitignore index 1b063e1..11513eb 100644 --- a/.gitignore +++ b/.gitignore @@ -203,6 +203,7 @@ /tests/virendiantest /tests/virfiletest /tests/virhashtest +/tests/virhostdevtest /tests/viridentitytest /tests/virkeycodetest /tests/virkeyfiletest diff --git a/tests/Makefile.am b/tests/Makefile.am index c374f14..503ab60 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -149,6 +149,7 @@ test_programs = virshtest sockettest \ virkmodtest \ vircapstest \ domainconftest \ + virhostdevtest \ $(NULL) if WITH_REMOTE @@ -803,6 +804,10 @@ vircgroupmock_la_CFLAGS = $(AM_CFLAGS) vircgroupmock_la_LDFLAGS = -module -avoid-version \ -rpath /evil/libtool/hack/to/force/shared/lib/creation +virhostdevtest_SOURCES = \ + virhostdevtest.c testutils.h testutils.c +virhostdevtest_LDADD = $(LDADDS) + virpcitest_SOURCES = \ virpcitest.c testutils.h testutils.c virpcitest_LDADD = $(LDADDS) diff --git a/tests/virhostdevtest.c b/tests/virhostdevtest.c new file mode 100644 index 0000000..f4d1853 --- /dev/null +++ b/tests/virhostdevtest.c @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + * Author: Chunyan Liu <cyliu@suse.com> + */ + +#include <config.h> + +#include "testutils.h" + +#ifdef __linux__ + +# include <stdlib.h> +# include <stdio.h> +# include <sys/types.h> +# include <sys/stat.h> +# include <sys/ioctl.h> +# include <fcntl.h> +# include "virlog.h" +# include "virhostdev.h" + +# define VIR_FROM_THIS VIR_FROM_NONE + +# define CHECK_LIST_COUNT(list, cnt) \ + if ((count = virPCIDeviceListCount(list)) != cnt) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "Unexpected count of items in " #list ": %d, " \ + "expecting %zu", count, (size_t) cnt); \ + goto cleanup; \ + } + +# define TEST_STATE_DIR abs_builddir "/hostdevmgr" +static const char *drv_name = "test_driver"; +static const char *dom_name = "test_domain"; +static const unsigned char *uuid = + (unsigned char *)("f92360b0-2541-8791-fb32-d1f838811541"); +static int nhostdevs = 3; +static virDomainHostdevDefPtr hostdevs[] = {NULL, NULL, NULL}; +static virPCIDevicePtr dev[] = {NULL, NULL, NULL}; +static virHostdevManagerPtr mgr = NULL; + +static void +myCleanup(void) +{ + size_t i; + for (i = 0; i < nhostdevs; i++) { + virPCIDeviceFree(dev[i]); + virDomainHostdevDefFree(hostdevs[i]); + } + + if (mgr) { + virObjectUnref(mgr->activePciHostdevs); + virObjectUnref(mgr->inactivePciHostdevs); + virObjectUnref(mgr->activeUsbHostdevs); + VIR_FREE(mgr->stateDir); + VIR_FREE(mgr); + } +} + +static int +myInit(void) +{ + size_t i; + + for (i = 0; i < nhostdevs; i++) { + virDomainHostdevSubsys subsys; + hostdevs[i] = virDomainHostdevDefAlloc(); + if (!hostdevs[i]) + goto cleanup; + hostdevs[i]->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI; + subsys.u.pci.addr.domain = 0; + subsys.u.pci.addr.bus = 0; + subsys.u.pci.addr.slot = i + 1; + subsys.u.pci.addr.function = 0; + subsys.u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM; + hostdevs[i]->source.subsys = subsys; + } + + for (i = 0; i < nhostdevs; i++) { + if (!(dev[i] = virPCIDeviceNew(0, 0, i + 1, 0)) || + virPCIDeviceSetStubDriver(dev[i], "pci-stub") < 0) + goto cleanup; + } + + if (VIR_ALLOC(mgr) < 0) + goto cleanup; + if ((mgr->activePciHostdevs = virPCIDeviceListNew()) == NULL) + goto cleanup; + if ((mgr->activeUsbHostdevs = virUSBDeviceListNew()) == NULL) + goto cleanup; + if ((mgr->inactivePciHostdevs = virPCIDeviceListNew()) == NULL) + goto cleanup; + if ((mgr->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL) + goto cleanup; + if (VIR_STRDUP(mgr->stateDir, TEST_STATE_DIR) < 0) + goto cleanup; + if (virFileMakePath(mgr->stateDir) < 0) + goto cleanup; + + return 0; + +cleanup: + myCleanup(); + return -1; +} + +#if HAVE_LINUX_KVM_H +# include <linux/kvm.h> +static bool +virHostdevHostSupportsPassthroughKVM(void) +{ + int kvmfd = -1; + bool ret = false; + + if ((kvmfd = open("/dev/kvm", O_RDONLY)) < 0) + goto cleanup; + +# ifdef KVM_CAP_IOMMU + if ((ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_IOMMU)) <= 0) + goto cleanup; + + ret = true; +# endif + +cleanup: + VIR_FORCE_CLOSE(kvmfd); + + return ret; +} +#else +static bool +virHostdevHostSupportsPassthroughKVM(void) +{ + return false; +} +#endif + +static int +testVirHostdevPreparePciHostdevs_unmanaged(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1, count2; + + for (i = 0; i < nhostdevs; i++) + hostdevs[i]->managed = false; + + /* Test invalid args */ + VIR_DEBUG("Test hostdev mgr=NULL\n"); + if (!virHostdevPreparePciHostdevs(NULL, drv_name, dom_name, uuid, + hostdevs, nhostdevs, 0)) + goto cleanup; + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + count2 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + + /* Test normal functionality */ + VIR_DEBUG("Test 0 hostdevs\n"); + if (virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + NULL, 0, 0) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + /* Test unmanaged hostdevs */ + VIR_DEBUG("Test >=1 unmanaged hostdevs\n"); + if (virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + hostdevs, nhostdevs, 0) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 + 3); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2 - 3); + + /* Test conflict */ + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + count2 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + VIR_DEBUG("Test: prepare same hostdevs for same driver/domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + &hostdevs[0], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2); + + VIR_DEBUG("Test: prepare same hostdevs for same driver, diff domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, drv_name, "test_domain1", uuid, + &hostdevs[1], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2); + + VIR_DEBUG("Test: prepare same hostdevs for diff driver/domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, "test_driver1", dom_name, uuid, + &hostdevs[2], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2); + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevReAttachPciHostdevs_unmanaged(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1, count2; + + for (i = 0; i < nhostdevs; i++) { + if (hostdevs[i]->managed != false) { + VIR_DEBUG("invalid test\n"); + return -1; + } + } + + VIR_DEBUG("Test hostdev mgr=NULL\n"); + virHostdevReAttachPciHostdevs(NULL, drv_name, dom_name, + hostdevs, nhostdevs, NULL); + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + count2 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + + VIR_DEBUG("Test 0 hostdevs\n"); + virHostdevReAttachPciHostdevs(mgr, drv_name, dom_name, NULL, 0, NULL); + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test >=1 unmanaged hostdevs\n"); + virHostdevReAttachPciHostdevs(mgr, drv_name, dom_name, + hostdevs, nhostdevs, NULL); + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 - 3); + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count2 + 3); + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevPreparePciHostdevs_managed(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1; + + for (i = 0; i < nhostdevs; i++) + hostdevs[i]->managed = true; + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + + /* Test normal functionality */ + VIR_DEBUG("Test >=1 hostdevs\n"); + if (virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + hostdevs, nhostdevs, 0) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 + 3); + + /* Test conflict */ + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + VIR_DEBUG("Test: prepare same hostdevs for same driver/domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, drv_name, dom_name, uuid, + &hostdevs[0], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test: prepare same hostdevs for same driver, diff domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, drv_name, "test_domain1", uuid, + &hostdevs[1], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test: prepare same hostdevs for diff driver/domain again\n"); + if (!virHostdevPreparePciHostdevs(mgr, "test_driver1", dom_name, uuid, + &hostdevs[2], 1, 0)) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevReAttachPciHostdevs_managed(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1; + + for (i = 0; i < nhostdevs; i++) { + if (hostdevs[i]->managed != true) { + VIR_DEBUG("invalid test\n"); + return -1; + } + } + + VIR_DEBUG("Test hostdev mgr=NULL\n"); + virHostdevReAttachPciHostdevs(NULL, drv_name, dom_name, + hostdevs, nhostdevs, NULL); + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + + VIR_DEBUG("Test 0 hostdevs\n"); + virHostdevReAttachPciHostdevs(mgr, drv_name, dom_name, NULL, 0, NULL); + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test >=1 hostdevs\n"); + virHostdevReAttachPciHostdevs(mgr, drv_name, dom_name, + hostdevs, nhostdevs, NULL); + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 - 3); + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevDetachPciNodeDevice(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1; + + if (!virHostdevPciNodeDeviceDetach(NULL, dev[0])) + goto cleanup; + + if (!virHostdevPciNodeDeviceDetach(mgr, NULL)) + goto cleanup; + + for (i = 0; i < nhostdevs; i++) { + count1 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + if (virHostdevPciNodeDeviceDetach(mgr, dev[i]) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count1 + 1); + } + + ret = 0; + +cleanup: + return ret; +} +static int +testVirHostdevResetPciNodeDevice(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + + if (!virHostdevPciNodeDeviceReset(NULL, dev[0])) + goto cleanup; + + if (!virHostdevPciNodeDeviceReAttach(mgr, NULL)) + goto cleanup; + + for (i = 0; i < nhostdevs; i++) { + if (virHostdevPciNodeDeviceReset(mgr, dev[i]) < 0) + goto cleanup; + } + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevReAttachPciNodeDevice(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + size_t i; + int count, count1; + + if (!virHostdevPciNodeDeviceReAttach(NULL, dev[0])) + goto cleanup; + + if (!virHostdevPciNodeDeviceReAttach(mgr, NULL)) + goto cleanup; + + for (i = 0; i < nhostdevs; i++) { + count1 = virPCIDeviceListCount(mgr->inactivePciHostdevs); + if (virHostdevPciNodeDeviceReAttach(mgr, dev[i]) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->inactivePciHostdevs, count1 - 1); + } + + ret = 0; + +cleanup: + return ret; + +} + +static int +testVirHostdevUpdateActivePciHostdevs(const void *oaque ATTRIBUTE_UNUSED) +{ + int ret = -1; + int count, count1; + + VIR_DEBUG("Test hostdev mgr=NULL\n"); + if (!virHostdevUpdateActivePciHostdevs(NULL, hostdevs, nhostdevs, + drv_name, dom_name)) + goto cleanup; + + count1 = virPCIDeviceListCount(mgr->activePciHostdevs); + + VIR_DEBUG("Test 0 hostdevs\n"); + if (virHostdevUpdateActivePciHostdevs(mgr, NULL, 0, + drv_name, dom_name) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1); + + VIR_DEBUG("Test >=1 hostdevs\n"); + if (virHostdevUpdateActivePciHostdevs(mgr, hostdevs, nhostdevs, + drv_name, dom_name) < 0) + goto cleanup; + CHECK_LIST_COUNT(mgr->activePciHostdevs, count1 + 3); + + ret = 0; + +cleanup: + return ret; +} + +# define FAKESYSFSDIRTEMPLATE abs_builddir "/fakesysfsdir-XXXXXX" + +static int +mymain(void) +{ + int ret = 0; + char *fakesysfsdir; + + if (VIR_STRDUP_QUIET(fakesysfsdir, FAKESYSFSDIRTEMPLATE) < 0) { + fprintf(stderr, "Out of memory\n"); + abort(); + } + + if (!mkdtemp(fakesysfsdir)) { + fprintf(stderr, "Cannot create fakesysfsdir"); + abort(); + } + + setenv("LIBVIRT_FAKE_SYSFS_DIR", fakesysfsdir, 1); + +# define DO_TEST(fnc) \ + do { \ + VIR_DEBUG("\nTesting: %s", #fnc); \ + if (virtTestRun(#fnc, fnc, NULL) < 0) \ + ret = -1; \ + } while (0) + + if (myInit() < 0) + fprintf(stderr, "Init data structures failed."); + + DO_TEST(testVirHostdevDetachPciNodeDevice); + if (virHostdevHostSupportsPassthroughKVM()) { + /* following tests would check KVM support */ + DO_TEST(testVirHostdevPreparePciHostdevs_unmanaged); + DO_TEST(testVirHostdevReAttachPciHostdevs_unmanaged); + } + DO_TEST(testVirHostdevResetPciNodeDevice); + DO_TEST(testVirHostdevReAttachPciNodeDevice); + if (virHostdevHostSupportsPassthroughKVM()) { + /* following tests would check KVM support */ + DO_TEST(testVirHostdevPreparePciHostdevs_managed); + DO_TEST(testVirHostdevReAttachPciHostdevs_managed); + } + DO_TEST(testVirHostdevUpdateActivePciHostdevs); + + myCleanup(); + + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakesysfsdir); + + VIR_FREE(fakesysfsdir); + + return ret==0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/virpcimock.so") +#else +int +main(void) +{ + return EXIT_AM_SKIP; +} +#endif -- 1.6.0.2

Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/lxc/lxc_hostdev.c | 320 +++---------------------------------------------- 1 files changed, 16 insertions(+), 304 deletions(-) diff --git a/src/lxc/lxc_hostdev.c b/src/lxc/lxc_hostdev.c index 8398646..3d9cc04 100644 --- a/src/lxc/lxc_hostdev.c +++ b/src/lxc/lxc_hostdev.c @@ -35,269 +35,36 @@ int virLXCUpdateActiveUsbHostdevs(virLXCDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) { - virDomainHostdevDefPtr hostdev = NULL; - size_t i; - virHostdevManagerPtr hostdev_mgr; + virHostdevManagerPtr mgr; if (!def->nhostdevs) return 0; - - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) + mgr = virHostdevManagerGetDefault(); + if (mgr == NULL) return -1; - for (i = 0; i < def->nhostdevs; i++) { - virUSBDevicePtr usb = NULL; - hostdev = def->hostdevs[i]; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - continue; - if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) - continue; - - usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - NULL); - if (!usb) { - VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", - hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - def->name); - continue; - } - - virUSBDeviceSetUsedBy(usb, LXC_DRIVER_NAME, def->name); - - virObjectLock(hostdev_mgr->activeUsbHostdevs); - if (virUSBDeviceListAdd(hostdev_mgr->activeUsbHostdevs, usb) < 0) { - virObjectUnlock(hostdev_mgr->activeUsbHostdevs); - virUSBDeviceFree(usb); - return -1; - } - virObjectUnlock(hostdev_mgr->activeUsbHostdevs); - } - - return 0; -} - - -int -virLXCPrepareHostdevUSBDevices(virLXCDriverPtr driver ATTRIBUTE_UNUSED, - const char *name, - virUSBDeviceList *list) -{ - size_t i, j; - unsigned int count; - virUSBDevicePtr tmp; - virHostdevManagerPtr hostdev_mgr; - - count = virUSBDeviceListCount(list); - - hostdev_mgr = virHostdevManagerGetDefault(); - if (hostdev_mgr == NULL) - return -1; - virObjectLock(hostdev_mgr->activeUsbHostdevs); - for (i = 0; i < count; i++) { - virUSBDevicePtr usb = virUSBDeviceListGet(list, i); - if ((tmp = virUSBDeviceListFind(hostdev_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, LXC_DRIVER_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(hostdev_mgr->activeUsbHostdevs, usb) < 0) - goto error; - } - virObjectUnlock(hostdev_mgr->activeUsbHostdevs); - return 0; - -error: - for (j = 0; j < i; j++) { - tmp = virUSBDeviceListGet(list, i); - virUSBDeviceListSteal(hostdev_mgr->activeUsbHostdevs, tmp); - } - virObjectUnlock(hostdev_mgr->activeUsbHostdevs); - return -1; -} - -int -virLXCFindHostdevUSBDevice(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) { - virUSBDeviceList *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; + return virHostdevUpdateActiveUsbHostdevs(mgr, def->hostdevs, def->nhostdevs, + LXC_DRIVER_NAME, def->name); } static int -virLXCPrepareHostUSBDevices(virLXCDriverPtr driver, +virLXCPrepareHostUSBDevices(virLXCDriverPtr driver ATTRIBUTE_UNUSED, virDomainDefPtr def) { - size_t i; - int ret = -1; - virUSBDeviceList *list; - virUSBDevicePtr tmp; virDomainHostdevDefPtr *hostdevs = def->hostdevs; int nhostdevs = def->nhostdevs; + const char *dom_name = def->name; + unsigned int flags = 0; + virHostdevManagerPtr hostdev_mgr; - /* 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 virLXCPrepareHostdevPCIDevices() - */ - 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) - required = false; - - if (virLXCFindHostdevUSBDevice(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 (virLXCPrepareHostdevUSBDevices(driver, def->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; + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL) + return -1; -cleanup: - virObjectUnref(list); - return ret; + return virHostdevPrepareUsbHostdevs(hostdev_mgr, LXC_DRIVER_NAME, dom_name, + hostdevs, nhostdevs, flags); } - int virLXCPrepareHostDevices(virLXCDriverPtr driver, virDomainDefPtr def) { @@ -352,75 +119,20 @@ int virLXCPrepareHostDevices(virLXCDriverPtr driver, return 0; } - static void virLXCDomainReAttachHostUsbDevices(virLXCDriverPtr driver ATTRIBUTE_UNUSED, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { - size_t i; virHostdevManagerPtr hostdev_mgr; hostdev_mgr = virHostdevManagerGetDefault(); if (hostdev_mgr == NULL) return; - virObjectLock(hostdev_mgr->activeUsbHostdevs); - for (i = 0; i < nhostdevs; i++) { - virDomainHostdevDefPtr hostdev = hostdevs[i]; - virUSBDevicePtr usb, tmp; - const char *usedby_domname = NULL; - const char *usedby_drvname = NULL; - - if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) - continue; - if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) - continue; - if (hostdev->missing) - continue; - - usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - NULL); - - if (!usb) { - VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s", - hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - name); - continue; - } - - /* Delete only those USB devices which belongs - * to domain @name because virLXCProcessStart() might - * have failed because USB device is already taken. - * Therefore we want to steal only those devices from - * the list which were taken by @name */ - - tmp = virUSBDeviceListFind(hostdev_mgr->activeUsbHostdevs, usb); - virUSBDeviceFree(usb); - - if (!tmp) { - VIR_WARN("Unable to find device %03d.%03d " - "in list of active USB devices", - hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device); - continue; - } - - virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname); - if (STREQ_NULLABLE(LXC_DRIVER_NAME, usedby_drvname) && - STREQ_NULLABLE(name, usedby_domname)) { - VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs", - hostdev->source.subsys.u.usb.bus, - hostdev->source.subsys.u.usb.device, - name); - - virUSBDeviceListDel(hostdev_mgr->activeUsbHostdevs, tmp); - } - } - virObjectUnlock(hostdev_mgr->activeUsbHostdevs); + virHostdevReAttachUsbHostdevs(hostdev_mgr, LXC_DRIVER_NAME, + name, hostdevs, nhostdevs); } void virLXCDomainReAttachHostDevices(virLXCDriverPtr driver, -- 1.6.0.2

Add VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN. For legacy xen, it will use "pciback" as stub driver. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- docs/schemas/domaincommon.rng | 1 + src/conf/domain_conf.c | 3 ++- src/conf/domain_conf.h | 1 + src/libxl/libxl_domain.c | 9 +++++++++ src/qemu/qemu_command.c | 3 +-- src/qemu/qemu_hostdev.c | 1 + src/qemu/qemu_hotplug.c | 4 +--- src/util/virhostdev.c | 10 ++++++++++ 8 files changed, 26 insertions(+), 6 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 601e7ac..bcd8142 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3421,6 +3421,7 @@ <choice> <value>kvm</value> <value>vfio</value> + <value>xen</value> </choice> </attribute> <empty/> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 1d5cc14..6d778a5 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -627,7 +627,8 @@ VIR_ENUM_IMPL(virDomainHostdevSubsysPciBackend, VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST, "default", "kvm", - "vfio") + "vfio", + "xen") VIR_ENUM_IMPL(virDomainHostdevCaps, VIR_DOMAIN_HOSTDEV_CAPS_TYPE_LAST, "storage", diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 2467f65..2840539 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -415,6 +415,7 @@ typedef enum { VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, /* detect automaticaly, prefer VFIO */ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM, /* force legacy kvm style */ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO, /* force vfio */ + VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN, /* force legacy xen style, use pciback */ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST } virDomainHostdevSubsysPciBackendType; diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index fdc4661..274fb6c 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -478,6 +478,15 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, STRNEQ(def->os.type, "hvm")) dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN; + if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) { + virDomainHostdevDefPtr hostdev = dev->data.hostdev; + + if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS && + hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI && + hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) + hostdev->source.subsys.u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN; + } + return 0; } diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 9ee84a0..8ed62bd 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5548,8 +5548,7 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def, virBufferAddLit(&buf, "vfio-pci"); break; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT: - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST: + default: virReportError(VIR_ERR_INTERNAL_ERROR, _("invalid PCI passthrough type '%s'"), virDomainHostdevSubsysPciBackendTypeToString(backend)); diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c index 56afe0a..b60017a 100644 --- a/src/qemu/qemu_hostdev.c +++ b/src/qemu/qemu_hostdev.c @@ -213,6 +213,7 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs, break; + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN: case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST: break; } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index a213929..0348968 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1193,9 +1193,7 @@ qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver, virProcessSetMaxMemLock(vm->pid, memKB * 1024); break; - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT: - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM: - case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST: + default: break; } diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c index 73844a6..56d5b98 100644 --- a/src/util/virhostdev.c +++ b/src/util/virhostdev.c @@ -146,6 +146,12 @@ virHostdevGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) virObjectUnref(list); return NULL; } + } else if (hostdev->source.subsys.u.pci.backend + == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN) { + if (virPCIDeviceSetStubDriver(dev, "pciback") < 0) { + virObjectUnref(list); + return NULL; + } } else { if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) { virObjectUnref(list); @@ -802,6 +808,10 @@ virHostdevUpdateActivePciHostdevs(virHostdevManagerPtr mgr, == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) { if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) goto cleanup; + } else if (hostdev->source.subsys.u.pci.backend + == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN) { + if (virPCIDeviceSetStubDriver(dev, "pciback") < 0) + goto cleanup; } else { if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) goto cleanup; -- 1.6.0.2

Add pci passthrough to libxl driver, support attach-device, detach-device and start a vm with pci hostdev specified. Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libxl/libxl_conf.c | 63 +++++++ src/libxl/libxl_conf.h | 4 + src/libxl/libxl_driver.c | 447 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 513 insertions(+), 1 deletions(-) diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index ade0a08..8ba3ce3 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -1147,6 +1147,66 @@ libxlDriverConfigGet(libxlDriverPrivatePtr driver) return cfg; } +int +libxlMakePci(virDomainHostdevDefPtr hostdev, libxl_device_pci *pcidev) +{ + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + return -1; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + return -1; + + pcidev->domain = hostdev->source.subsys.u.pci.addr.domain; + pcidev->bus = hostdev->source.subsys.u.pci.addr.bus; + pcidev->dev = hostdev->source.subsys.u.pci.addr.slot; + pcidev->func = hostdev->source.subsys.u.pci.addr.function; + + return 0; +} + +static int +libxlMakePciList(virDomainDefPtr def, libxl_domain_config *d_config) +{ + virDomainHostdevDefPtr *l_hostdevs = def->hostdevs; + size_t nhostdevs = def->nhostdevs; + size_t npcidevs = 0; + libxl_device_pci *x_pcidevs; + size_t i, j; + + if (nhostdevs == 0) + return 0; + + if (VIR_ALLOC_N(x_pcidevs, nhostdevs) < 0) + return -1; + + for (i = 0, j = 0; i < nhostdevs; i++) { + if (l_hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (l_hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + + libxl_device_pci_init(&x_pcidevs[j]); + + if (libxlMakePci(l_hostdevs[i], &x_pcidevs[j]) < 0) + goto error; + + npcidevs++; + j++; + } + + VIR_SHRINK_N(x_pcidevs, nhostdevs, nhostdevs - npcidevs); + d_config->pcidevs = x_pcidevs; + d_config->num_pcidevs = npcidevs; + + return 0; + +error: + for (i = 0; i < npcidevs; i++) + libxl_device_pci_dispose(&x_pcidevs[i]); + + VIR_FREE(x_pcidevs); + return -1; +} + virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx) { @@ -1195,6 +1255,9 @@ libxlBuildDomainConfig(libxlDriverPrivatePtr driver, if (libxlMakeVfbList(driver, def, d_config) < 0) return -1; + if (libxlMakePciList(def, d_config) < 0) + return -1; + d_config->on_reboot = def->onReboot; d_config->on_poweroff = def->onPoweroff; d_config->on_crash = def->onCrash; diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index f089a92..faf0d00 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -39,6 +39,7 @@ # include "virchrdev.h" +# define LIBXL_DRIVER_NAME "xenlight" # define LIBXL_VNC_PORT_MIN 5900 # define LIBXL_VNC_PORT_MAX 65535 @@ -150,6 +151,9 @@ libxlMakeVfb(libxlDriverPrivatePtr driver, virDomainGraphicsDefPtr l_vfb, libxl_device_vfb *x_vfb); int +libxlMakePci(virDomainHostdevDefPtr hostdev, libxl_device_pci *pcidev); + +int libxlBuildDomainConfig(libxlDriverPrivatePtr driver, virDomainObjPtr vm, libxl_domain_config *d_config); diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index a79efcb..9035262 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -52,6 +52,7 @@ #include "virsysinfo.h" #include "viraccessapicheck.h" #include "viratomic.h" +#include "virhostdev.h" #define VIR_FROM_THIS VIR_FROM_LIBXL @@ -309,6 +310,12 @@ libxlVmCleanup(libxlDriverPrivatePtr driver, int vnc_port; char *file; size_t i; + virHostdevManagerPtr hostdev_mgr; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr != NULL) + virHostdevReAttachDomainHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def, VIR_SP_PCI_HOSTDEV, NULL); vm->def->id = -1; @@ -699,6 +706,7 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, #ifdef LIBXL_HAVE_DOMAIN_CREATE_RESTORE_PARAMS libxl_domain_restore_params params; #endif + virHostdevManagerPtr hostdev_mgr; if (libxlDomainObjPrivateInitCtx(vm) < 0) return ret; @@ -761,6 +769,12 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, goto endjob; } + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPrepareDomainHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def, VIR_SP_PCI_HOSTDEV) < 0) + goto endjob; + /* Unlock virDomainObj while creating the domain */ virObjectUnlock(vm); if (restore_fd < 0) { @@ -867,6 +881,7 @@ libxlReconnectDomain(virDomainObjPtr vm, libxl_dominfo d_info; int len; uint8_t *data = NULL; + virHostdevManagerPtr hostdev_mgr; virObjectLock(vm); @@ -890,6 +905,14 @@ libxlReconnectDomain(virDomainObjPtr vm, /* Update domid in case it changed (e.g. reboot) while we were gone? */ vm->def->id = d_info.domid; + + /* Update hostdev state */ + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevUpdateDomainActiveHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def, VIR_SP_PCI_HOSTDEV) < 0) + goto out; + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN); if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) @@ -3274,6 +3297,95 @@ cleanup: } static int +libxlDomainAttachHostPciDevice(libxlDomainObjPrivatePtr priv, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + libxl_device_pci pcidev; + virDomainHostdevDefPtr found; + virHostdevManagerPtr hostdev_mgr; + + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + return -1; + + if (virDomainHostdevFind(vm->def, hostdev, &found) >= 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("target pci device %.4x:%.2x:%.2x.%.1x already exists"), + hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + return -1; + } + + if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0) + return -1; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPreparePciHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def->name, vm->def->uuid, + &hostdev, 1, 0) < 0) + goto cleanup; + + if (libxlMakePci(hostdev, &pcidev) < 0) + goto reattach_hostdev; + + if (libxl_device_pci_add(priv->ctx, vm->def->id, &pcidev, 0) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("libxenlight failed to attach pci device %.4x:%.2x:%.2x.%.1x"), + hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + goto reattach_hostdev; + } + + vm->def->hostdevs[vm->def->nhostdevs++] = hostdev; + return 0; + +reattach_hostdev: + virHostdevReAttachPciHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def->name, &hostdev, 1, NULL); + +cleanup: + return -1; +} + +static int +libxlDomainAttachHostDevice(libxlDomainObjPrivatePtr priv, + virDomainObjPtr vm, + virDomainDeviceDefPtr dev) +{ + virDomainHostdevDefPtr hostdev = dev->data.hostdev; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hostdev mode '%s' not supported"), + virDomainHostdevModeTypeToString(hostdev->mode)); + return -1; + } + + switch (hostdev->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + if (libxlDomainAttachHostPciDevice(priv, vm, hostdev) < 0) + goto error; + break; + + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hostdev subsys type '%s' not supported"), + virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type)); + goto error; + } + + return 0; + +error: + return -1; +} + +static int libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { @@ -3340,6 +3452,12 @@ libxlDomainAttachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, dev->data.disk = NULL; break; + case VIR_DOMAIN_DEVICE_HOSTDEV: + ret = libxlDomainAttachHostDevice(priv, vm, dev); + if (!ret) + dev->data.hostdev = NULL; + break; + default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%s' cannot be attached"), @@ -3354,6 +3472,8 @@ static int libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) { virDomainDiskDefPtr disk; + virDomainHostdevDefPtr hostdev; + virDomainHostdevDefPtr found; switch (dev->type) { case VIR_DOMAIN_DEVICE_DISK: @@ -3368,6 +3488,25 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) /* vmdef has the pointer. Generic codes for vmdef will do all jobs */ dev->data.disk = NULL; break; + case VIR_DOMAIN_DEVICE_HOSTDEV: + hostdev = dev->data.hostdev; + + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + return -1; + + if (virDomainHostdevFind(vmdef, hostdev, &found) >= 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("target pci device %.4x:%.2x:%.2x.%.1x\ + already exists"), + hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + return -1; + } + + virDomainHostdevInsert(vmdef, hostdev); + break; default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", @@ -3378,6 +3517,125 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) } static int +libxlComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr device ATTRIBUTE_UNUSED, + virDomainDeviceInfoPtr info1, + void *opaque) +{ + virDomainDeviceInfoPtr info2 = opaque; + + if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI || + info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) + return 0; + + if (info1->addr.pci.domain == info2->addr.pci.domain && + info1->addr.pci.bus == info2->addr.pci.bus && + info1->addr.pci.slot == info2->addr.pci.slot && + info1->addr.pci.function != info2->addr.pci.function) + return -1; + return 0; +} + +static bool +libxlIsMultiFunctionDevice(virDomainDefPtr def, + virDomainDeviceInfoPtr dev) +{ + if (virDomainDeviceInfoIterate(def, libxlComparePCIDevice, dev) < 0) + return true; + return false; +} + +static int +libxlDomainDetachHostPciDevice(libxlDomainObjPrivatePtr priv, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; + libxl_device_pci pcidev; + virDomainHostdevDefPtr detach; + int idx; + virHostdevManagerPtr hostdev_mgr; + + if (subsys->type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + return -1; + + idx = virDomainHostdevFind(vm->def, hostdev, &detach); + if (idx < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("host pci device %.4x:%.2x:%.2x.%.1x not found"), + subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, + subsys->u.pci.addr.slot, subsys->u.pci.addr.function); + return -1; + } + + if (libxlIsMultiFunctionDevice(vm->def, detach->info)) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"), + subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, + subsys->u.pci.addr.slot, subsys->u.pci.addr.function); + goto cleanup; + } + + + libxl_device_pci_init(&pcidev); + + if (libxlMakePci(detach, &pcidev) < 0) + goto cleanup; + + if (libxl_device_pci_remove(priv->ctx, vm->def->id, &pcidev, 0) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("libxenlight failed to detach pci device\ + %.4x:%.2x:%.2x.%.1x"), + subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, + subsys->u.pci.addr.slot, subsys->u.pci.addr.function); + goto cleanup; + } + + libxl_device_pci_dispose(&pcidev); + + virDomainHostdevRemove(vm->def, idx); + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr != NULL) + virHostdevReAttachPciHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def->name, &hostdev, 1, NULL); + + return 0; + +cleanup: + virDomainHostdevDefFree(detach); + return -1; +} + +static int +libxlDomainDetachHostDevice(libxlDomainObjPrivatePtr priv, + virDomainObjPtr vm, + virDomainDeviceDefPtr dev) +{ + virDomainHostdevDefPtr hostdev = dev->data.hostdev; + virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hostdev mode '%s' not supported"), + virDomainHostdevModeTypeToString(hostdev->mode)); + return -1; + } + + switch (subsys->type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + return libxlDomainDetachHostPciDevice(priv, vm, hostdev); + + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected hostdev type %d"), subsys->type); + break; + } + + return -1; +} + +static int libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { @@ -3388,6 +3646,10 @@ libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, ret = libxlDomainDetachDeviceDiskLive(priv, vm, dev); break; + case VIR_DOMAIN_DEVICE_HOSTDEV: + ret = libxlDomainDetachHostDevice(priv, vm, dev); + break; + default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%s' cannot be detached"), @@ -3398,6 +3660,7 @@ libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, return ret; } + static int libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) { @@ -4590,10 +4853,188 @@ libxlConnectSupportsFeature(virConnectPtr conn, int feature) } } +static int +libxlNodeDeviceGetPciInfo(virNodeDeviceDefPtr def, + unsigned *domain, + unsigned *bus, + unsigned *slot, + unsigned *function) +{ + virNodeDevCapsDefPtr cap; + int ret = -1; + + cap = def->caps; + while (cap) { + if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) { + *domain = cap->data.pci_dev.domain; + *bus = cap->data.pci_dev.bus; + *slot = cap->data.pci_dev.slot; + *function = cap->data.pci_dev.function; + break; + } + + cap = cap->next; + } + + if (!cap) { + virReportError(VIR_ERR_INVALID_ARG, + _("device %s is not a PCI device"), def->name); + goto out; + } + + ret = 0; +out: + return ret; +} + +static int +libxlNodeDeviceDetachFlags(virNodeDevicePtr dev, + const char *driverName, + unsigned int flags) +{ + virPCIDevicePtr pci = NULL; + unsigned domain = 0, bus = 0, slot = 0, function = 0; + int ret = -1; + virNodeDeviceDefPtr def = NULL; + char *xml = NULL; + virHostdevManagerPtr hostdev_mgr; + + virCheckFlags(0, -1); + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto cleanup; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto cleanup; + + if (virNodeDeviceDetachFlagsEnsureACL(dev->conn, def) < 0) + goto cleanup; + + if (libxlNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0) + goto cleanup; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + goto cleanup; + + if (!driverName || STREQ(driverName, "xen")) { + if (virPCIDeviceSetStubDriver(pci, "pciback") < 0) + goto cleanup; + } else { + virReportError(VIR_ERR_INVALID_ARG, + _("unsupported driver name '%s'"), driverName); + goto cleanup; + } + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPciNodeDeviceDetach(hostdev_mgr, pci) < 0) + goto cleanup; + + ret = 0; +cleanup: + virPCIDeviceFree(pci); + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} + +static int +libxlNodeDeviceDettach(virNodeDevicePtr dev) +{ + return libxlNodeDeviceDetachFlags(dev, NULL, 0); +} + +static int +libxlNodeDeviceReAttach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci = NULL; + unsigned domain = 0, bus = 0, slot = 0, function = 0; + int ret = -1; + virNodeDeviceDefPtr def = NULL; + char *xml = NULL; + virHostdevManagerPtr hostdev_mgr; + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto cleanup; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto cleanup; + + if (virNodeDeviceReAttachEnsureACL(dev->conn, def) < 0) + goto cleanup; + + if (libxlNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0) + goto cleanup; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + goto cleanup; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPciNodeDeviceReAttach(hostdev_mgr, pci) < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); +cleanup: + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} + +static int +libxlNodeDeviceReset(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain = 0, bus = 0, slot = 0, function = 0; + int ret = -1; + virNodeDeviceDefPtr def = NULL; + char *xml = NULL; + virHostdevManagerPtr hostdev_mgr; + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto cleanup; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto cleanup; + + if (virNodeDeviceResetEnsureACL(dev->conn, def) < 0) + goto cleanup; + + if (libxlNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0) + goto cleanup; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + goto cleanup; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPciNodeDeviceReset(hostdev_mgr, pci) < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci); +cleanup: + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} + static virDriver libxlDriver = { .no = VIR_DRV_LIBXL, - .name = "xenlight", + .name = LIBXL_DRIVER_NAME, .connectOpen = libxlConnectOpen, /* 0.9.0 */ .connectClose = libxlConnectClose, /* 0.9.0 */ .connectGetType = libxlConnectGetType, /* 0.9.0 */ @@ -4676,6 +5117,10 @@ static virDriver libxlDriver = { .connectDomainEventDeregisterAny = libxlConnectDomainEventDeregisterAny, /* 0.9.0 */ .connectIsAlive = libxlConnectIsAlive, /* 0.9.8 */ .connectSupportsFeature = libxlConnectSupportsFeature, /* 1.1.1 */ + .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.2.2 */ + .nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.2.2 */ + .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.2.2 */ + .nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.2 */ }; static virStateDriver libxlStateDriver = { -- 1.6.0.2

Chunyan Liu wrote:
Add pci passthrough to libxl driver, support attach-device, detach-device and start a vm with pci hostdev specified.
Signed-off-by: Chunyan Liu <cyliu@suse.com> --- src/libxl/libxl_conf.c | 63 +++++++ src/libxl/libxl_conf.h | 4 + src/libxl/libxl_driver.c | 447 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 513 insertions(+), 1 deletions(-)
diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index ade0a08..8ba3ce3 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -1147,6 +1147,66 @@ libxlDriverConfigGet(libxlDriverPrivatePtr driver) return cfg; }
+int +libxlMakePci(virDomainHostdevDefPtr hostdev, libxl_device_pci *pcidev) +{ + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + return -1; + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + return -1; + + pcidev->domain = hostdev->source.subsys.u.pci.addr.domain; + pcidev->bus = hostdev->source.subsys.u.pci.addr.bus; + pcidev->dev = hostdev->source.subsys.u.pci.addr.slot; + pcidev->func = hostdev->source.subsys.u.pci.addr.function; + + return 0; +} + +static int +libxlMakePciList(virDomainDefPtr def, libxl_domain_config *d_config) +{ + virDomainHostdevDefPtr *l_hostdevs = def->hostdevs; + size_t nhostdevs = def->nhostdevs; + size_t npcidevs = 0; + libxl_device_pci *x_pcidevs; + size_t i, j; + + if (nhostdevs == 0) + return 0; + + if (VIR_ALLOC_N(x_pcidevs, nhostdevs) < 0) + return -1; + + for (i = 0, j = 0; i < nhostdevs; i++) { + if (l_hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) + continue; + if (l_hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + continue; + + libxl_device_pci_init(&x_pcidevs[j]); + + if (libxlMakePci(l_hostdevs[i], &x_pcidevs[j]) < 0) + goto error; + + npcidevs++; + j++; + } + + VIR_SHRINK_N(x_pcidevs, nhostdevs, nhostdevs - npcidevs); + d_config->pcidevs = x_pcidevs; + d_config->num_pcidevs = npcidevs; + + return 0; + +error: + for (i = 0; i < npcidevs; i++) + libxl_device_pci_dispose(&x_pcidevs[i]); + + VIR_FREE(x_pcidevs); + return -1; +} + virCapsPtr libxlMakeCapabilities(libxl_ctx *ctx) { @@ -1195,6 +1255,9 @@ libxlBuildDomainConfig(libxlDriverPrivatePtr driver, if (libxlMakeVfbList(driver, def, d_config) < 0) return -1;
+ if (libxlMakePciList(def, d_config) < 0) + return -1; + d_config->on_reboot = def->onReboot; d_config->on_poweroff = def->onPoweroff; d_config->on_crash = def->onCrash; diff --git a/src/libxl/libxl_conf.h b/src/libxl/libxl_conf.h index f089a92..faf0d00 100644 --- a/src/libxl/libxl_conf.h +++ b/src/libxl/libxl_conf.h @@ -39,6 +39,7 @@ # include "virchrdev.h"
+# define LIBXL_DRIVER_NAME "xenlight" # define LIBXL_VNC_PORT_MIN 5900 # define LIBXL_VNC_PORT_MAX 65535
@@ -150,6 +151,9 @@ libxlMakeVfb(libxlDriverPrivatePtr driver, virDomainGraphicsDefPtr l_vfb, libxl_device_vfb *x_vfb);
int +libxlMakePci(virDomainHostdevDefPtr hostdev, libxl_device_pci *pcidev); + +int libxlBuildDomainConfig(libxlDriverPrivatePtr driver, virDomainObjPtr vm, libxl_domain_config *d_config);
diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c index a79efcb..9035262 100644 --- a/src/libxl/libxl_driver.c +++ b/src/libxl/libxl_driver.c @@ -52,6 +52,7 @@ #include "virsysinfo.h" #include "viraccessapicheck.h" #include "viratomic.h" +#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_LIBXL
@@ -309,6 +310,12 @@ libxlVmCleanup(libxlDriverPrivatePtr driver, int vnc_port; char *file; size_t i; + virHostdevManagerPtr hostdev_mgr; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr != NULL) + virHostdevReAttachDomainHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def, VIR_SP_PCI_HOSTDEV, NULL);
vm->def->id = -1;
@@ -699,6 +706,7 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, #ifdef LIBXL_HAVE_DOMAIN_CREATE_RESTORE_PARAMS libxl_domain_restore_params params; #endif + virHostdevManagerPtr hostdev_mgr;
if (libxlDomainObjPrivateInitCtx(vm) < 0) return ret; @@ -761,6 +769,12 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm, goto endjob; }
+ hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPrepareDomainHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def, VIR_SP_PCI_HOSTDEV) < 0) + goto endjob; + /* Unlock virDomainObj while creating the domain */ virObjectUnlock(vm); if (restore_fd < 0) { @@ -867,6 +881,7 @@ libxlReconnectDomain(virDomainObjPtr vm, libxl_dominfo d_info; int len; uint8_t *data = NULL; + virHostdevManagerPtr hostdev_mgr;
virObjectLock(vm);
@@ -890,6 +905,14 @@ libxlReconnectDomain(virDomainObjPtr vm,
/* Update domid in case it changed (e.g. reboot) while we were gone? */ vm->def->id = d_info.domid; + + /* Update hostdev state */ + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevUpdateDomainActiveHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def, VIR_SP_PCI_HOSTDEV) < 0) + goto out; + virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN);
if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback) @@ -3274,6 +3297,95 @@ cleanup: }
static int +libxlDomainAttachHostPciDevice(libxlDomainObjPrivatePtr priv, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + libxl_device_pci pcidev; + virDomainHostdevDefPtr found; + virHostdevManagerPtr hostdev_mgr; + + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + return -1; + + if (virDomainHostdevFind(vm->def, hostdev, &found) >= 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("target pci device %.4x:%.2x:%.2x.%.1x already exists"), + hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + return -1; + } + + if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0) + return -1; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPreparePciHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def->name, vm->def->uuid, + &hostdev, 1, 0) < 0) + goto cleanup;
The cleanup label simply returns -1, so might as well do that here.
+ + if (libxlMakePci(hostdev, &pcidev) < 0) + goto reattach_hostdev; + + if (libxl_device_pci_add(priv->ctx, vm->def->id, &pcidev, 0) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("libxenlight failed to attach pci device %.4x:%.2x:%.2x.%.1x"), + hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + goto reattach_hostdev; + } + + vm->def->hostdevs[vm->def->nhostdevs++] = hostdev; + return 0; + +reattach_hostdev:
I think this label should be 'error'.
+ virHostdevReAttachPciHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def->name, &hostdev, 1, NULL); + +cleanup:
No need for cleanup, just return -1.
+ return -1; +} + +static int +libxlDomainAttachHostDevice(libxlDomainObjPrivatePtr priv, + virDomainObjPtr vm, + virDomainDeviceDefPtr dev) +{ + virDomainHostdevDefPtr hostdev = dev->data.hostdev; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hostdev mode '%s' not supported"), + virDomainHostdevModeTypeToString(hostdev->mode)); + return -1; + } + + switch (hostdev->source.subsys.type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + if (libxlDomainAttachHostPciDevice(priv, vm, hostdev) < 0) + goto error; + break; + + default: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hostdev subsys type '%s' not supported"), + virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type)); + goto error; + } + + return 0; + +error: + return -1;
Nothing done here, so just 'return -1' on error and drop it.
+} + +static int libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { @@ -3340,6 +3452,12 @@ libxlDomainAttachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, dev->data.disk = NULL; break;
+ case VIR_DOMAIN_DEVICE_HOSTDEV: + ret = libxlDomainAttachHostDevice(priv, vm, dev); + if (!ret) + dev->data.hostdev = NULL; + break; + default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%s' cannot be attached"), @@ -3354,6 +3472,8 @@ static int libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) { virDomainDiskDefPtr disk; + virDomainHostdevDefPtr hostdev; + virDomainHostdevDefPtr found;
switch (dev->type) { case VIR_DOMAIN_DEVICE_DISK: @@ -3368,6 +3488,25 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) /* vmdef has the pointer. Generic codes for vmdef will do all jobs */ dev->data.disk = NULL; break; + case VIR_DOMAIN_DEVICE_HOSTDEV: + hostdev = dev->data.hostdev; + + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + return -1; + + if (virDomainHostdevFind(vmdef, hostdev, &found) >= 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("target pci device %.4x:%.2x:%.2x.%.1x\ + already exists"), + hostdev->source.subsys.u.pci.addr.domain, + hostdev->source.subsys.u.pci.addr.bus, + hostdev->source.subsys.u.pci.addr.slot, + hostdev->source.subsys.u.pci.addr.function); + return -1; + } + + virDomainHostdevInsert(vmdef, hostdev); + break;
default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", @@ -3378,6 +3517,125 @@ libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) }
static int +libxlComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED, + virDomainDeviceDefPtr device ATTRIBUTE_UNUSED, + virDomainDeviceInfoPtr info1, + void *opaque) +{ + virDomainDeviceInfoPtr info2 = opaque; + + if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI || + info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) + return 0; + + if (info1->addr.pci.domain == info2->addr.pci.domain && + info1->addr.pci.bus == info2->addr.pci.bus && + info1->addr.pci.slot == info2->addr.pci.slot && + info1->addr.pci.function != info2->addr.pci.function) + return -1; + return 0; +} + +static bool +libxlIsMultiFunctionDevice(virDomainDefPtr def, + virDomainDeviceInfoPtr dev) +{ + if (virDomainDeviceInfoIterate(def, libxlComparePCIDevice, dev) < 0) + return true; + return false; +} + +static int +libxlDomainDetachHostPciDevice(libxlDomainObjPrivatePtr priv, + virDomainObjPtr vm, + virDomainHostdevDefPtr hostdev) +{ + virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; + libxl_device_pci pcidev; + virDomainHostdevDefPtr detach; + int idx; + virHostdevManagerPtr hostdev_mgr; + + if (subsys->type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) + return -1; + + idx = virDomainHostdevFind(vm->def, hostdev, &detach); + if (idx < 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("host pci device %.4x:%.2x:%.2x.%.1x not found"), + subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, + subsys->u.pci.addr.slot, subsys->u.pci.addr.function); + return -1; + } + + if (libxlIsMultiFunctionDevice(vm->def, detach->info)) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"), + subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, + subsys->u.pci.addr.slot, subsys->u.pci.addr.function); + goto cleanup; + } + + + libxl_device_pci_init(&pcidev); + + if (libxlMakePci(detach, &pcidev) < 0) + goto cleanup; + + if (libxl_device_pci_remove(priv->ctx, vm->def->id, &pcidev, 0) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("libxenlight failed to detach pci device\ + %.4x:%.2x:%.2x.%.1x"), + subsys->u.pci.addr.domain, subsys->u.pci.addr.bus, + subsys->u.pci.addr.slot, subsys->u.pci.addr.function); + goto cleanup; + } + + libxl_device_pci_dispose(&pcidev); + + virDomainHostdevRemove(vm->def, idx); + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr != NULL) + virHostdevReAttachPciHostdevs(hostdev_mgr, LIBXL_DRIVER_NAME, + vm->def->name, &hostdev, 1, NULL); + + return 0; + +cleanup:
'error' seems like a better name for this label.
+ virDomainHostdevDefFree(detach); + return -1; +} + +static int +libxlDomainDetachHostDevice(libxlDomainObjPrivatePtr priv, + virDomainObjPtr vm, + virDomainDeviceDefPtr dev) +{ + virDomainHostdevDefPtr hostdev = dev->data.hostdev; + virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys; + + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hostdev mode '%s' not supported"), + virDomainHostdevModeTypeToString(hostdev->mode)); + return -1; + } + + switch (subsys->type) { + case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: + return libxlDomainDetachHostPciDevice(priv, vm, hostdev); + + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected hostdev type %d"), subsys->type); + break; + } + + return -1; +} + +static int libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, virDomainDeviceDefPtr dev) { @@ -3388,6 +3646,10 @@ libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, ret = libxlDomainDetachDeviceDiskLive(priv, vm, dev); break;
+ case VIR_DOMAIN_DEVICE_HOSTDEV: + ret = libxlDomainDetachHostDevice(priv, vm, dev); + break; + default: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("device type '%s' cannot be detached"), @@ -3398,6 +3660,7 @@ libxlDomainDetachDeviceLive(libxlDomainObjPrivatePtr priv, virDomainObjPtr vm, return ret; }
+ static int libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev) { @@ -4590,10 +4853,188 @@ libxlConnectSupportsFeature(virConnectPtr conn, int feature) } }
+static int +libxlNodeDeviceGetPciInfo(virNodeDeviceDefPtr def, + unsigned *domain, + unsigned *bus, + unsigned *slot, + unsigned *function) +{ + virNodeDevCapsDefPtr cap; + int ret = -1; + + cap = def->caps; + while (cap) { + if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) { + *domain = cap->data.pci_dev.domain; + *bus = cap->data.pci_dev.bus; + *slot = cap->data.pci_dev.slot; + *function = cap->data.pci_dev.function; + break; + } + + cap = cap->next; + } + + if (!cap) { + virReportError(VIR_ERR_INVALID_ARG, + _("device %s is not a PCI device"), def->name); + goto out;
You can return -1 here
+ } + + ret = 0;
and 0 here
+out: + return ret;
and drop ret.
+} + +static int +libxlNodeDeviceDetachFlags(virNodeDevicePtr dev, + const char *driverName, + unsigned int flags) +{ + virPCIDevicePtr pci = NULL; + unsigned domain = 0, bus = 0, slot = 0, function = 0; + int ret = -1; + virNodeDeviceDefPtr def = NULL; + char *xml = NULL; + virHostdevManagerPtr hostdev_mgr; + + virCheckFlags(0, -1); + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto cleanup; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto cleanup; + + if (virNodeDeviceDetachFlagsEnsureACL(dev->conn, def) < 0) + goto cleanup; + + if (libxlNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0) + goto cleanup; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + goto cleanup; + + if (!driverName || STREQ(driverName, "xen")) { + if (virPCIDeviceSetStubDriver(pci, "pciback") < 0) + goto cleanup; + } else { + virReportError(VIR_ERR_INVALID_ARG, + _("unsupported driver name '%s'"), driverName); + goto cleanup; + } + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPciNodeDeviceDetach(hostdev_mgr, pci) < 0) + goto cleanup; + + ret = 0; +cleanup: + virPCIDeviceFree(pci); + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} + +static int +libxlNodeDeviceDettach(virNodeDevicePtr dev) +{ + return libxlNodeDeviceDetachFlags(dev, NULL, 0); +} + +static int +libxlNodeDeviceReAttach(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci = NULL; + unsigned domain = 0, bus = 0, slot = 0, function = 0; + int ret = -1; + virNodeDeviceDefPtr def = NULL; + char *xml = NULL; + virHostdevManagerPtr hostdev_mgr; + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto cleanup; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto cleanup; + + if (virNodeDeviceReAttachEnsureACL(dev->conn, def) < 0) + goto cleanup; + + if (libxlNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0) + goto cleanup; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + goto cleanup; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPciNodeDeviceReAttach(hostdev_mgr, pci) < 0) + goto out;
I think you can just goto cleanup here
+ + ret = 0; +out: + virPCIDeviceFree(pci);
moving this to cleanup and removing out. It is safe to call virPCIDeviceFree with NULL.
+cleanup: + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} + +static int +libxlNodeDeviceReset(virNodeDevicePtr dev) +{ + virPCIDevicePtr pci; + unsigned domain = 0, bus = 0, slot = 0, function = 0; + int ret = -1; + virNodeDeviceDefPtr def = NULL; + char *xml = NULL; + virHostdevManagerPtr hostdev_mgr; + + xml = virNodeDeviceGetXMLDesc(dev, 0); + if (!xml) + goto cleanup; + + def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL); + if (!def) + goto cleanup; + + if (virNodeDeviceResetEnsureACL(dev->conn, def) < 0) + goto cleanup; + + if (libxlNodeDeviceGetPciInfo(def, &domain, &bus, &slot, &function) < 0) + goto cleanup; + + pci = virPCIDeviceNew(domain, bus, slot, function); + if (!pci) + goto cleanup; + + hostdev_mgr = virHostdevManagerGetDefault(); + if (hostdev_mgr == NULL || + virHostdevPciNodeDeviceReset(hostdev_mgr, pci) < 0) + goto out; + + ret = 0; +out: + virPCIDeviceFree(pci);
Same comment here, except you will need to initialize pci to NULL.
+cleanup: + virNodeDeviceDefFree(def); + VIR_FREE(xml); + return ret; +} +
static virDriver libxlDriver = { .no = VIR_DRV_LIBXL, - .name = "xenlight", + .name = LIBXL_DRIVER_NAME, .connectOpen = libxlConnectOpen, /* 0.9.0 */ .connectClose = libxlConnectClose, /* 0.9.0 */ .connectGetType = libxlConnectGetType, /* 0.9.0 */ @@ -4676,6 +5117,10 @@ static virDriver libxlDriver = { .connectDomainEventDeregisterAny = libxlConnectDomainEventDeregisterAny, /* 0.9.0 */ .connectIsAlive = libxlConnectIsAlive, /* 0.9.8 */ .connectSupportsFeature = libxlConnectSupportsFeature, /* 1.1.1 */ + .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.2.2 */ + .nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.2.2 */ + .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.2.2 */ + .nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.2 */
1.2.3 :) I'm hopeful this series will make the next release. I haven't looked at all the patches in detail as Cedric has, but agree that the split made an initial skim much easier. Nice work Chunyan! Regards, Jim

Hello ChunYan, I saw a few minor problems in some patches that made me rebase quite a lot of other patches in your serie, but otherwise it really looks good to me. Here is a summary of the changes I made or questions I have: * Patch 2: Fixed a few remaining changes that broke the build. Just remember that having the tree building after each commit helps a lot when one later needs to bisect. * Patch 4: when is the manager freed? * Patch 5 & 6: remove the added ATTRIBUTE_UNUSED * Patch 9: added { } around if block to match else style. * Patch 10: remove added ATTRIBUTE_UNUSED * Patch 11: fixed indent function rename * Patch 42: Fix comment about qemuPrepareHostdevPCIDevices in earlier patch * Patch 47: remove added ATTRIBUTE_UNUSED * Patch 49: Fixed the version in libxl_driver.c as 1.2.2 is out The whole updated patch series is sitting here for those wanting to see the changes applied: https://github.com/cbosdo/libvirt/commits/hostdev-passthrough Of course, I'ld love another pair of sharper eyes to look at the patch series. I'm not an expert on the hostdev topic ;) Kind regards -- Cedric On Sat, 2014-03-01 at 14:28 +0800, Chunyan Liu wrote:
These patches implements a separate module for hostdev passthrough so that it could be shared by different drivers and can maintain a global state of a host device.
Patches 1~6 are to switch existing qemu and lxc driver to use common library lists, so that to maintain a global state of every host device.
Patches 7~45 are to extract general code from qemu_hostdev.c piece by piece, make them reusable common APIs.
Patches 46: unit test for the virhostdev common library Patches 47: add a hostdev backend type for xen Patches 48: add pci passthrough to libxl driver based on the common library Patches 49: change lxc to use common library APIs
--- changes to v12: * split "add hostdev passthrough common library" patch into small patches for easier review. * fix v12 comments * rebase to libxl changes
Chunyan Liu (49): add 'driver' info to used_by qemu: reuse hostdev interfaces to avoid duplicate qemu: remove functions now used internally only from qemu_hostdev.h add virhostdev files to maintain global state of host devices qemu: use general virhostdev lists instead of its own lxc: use general virhostdev lists instead of its own qemu_hostdev: move cfg->relaxedACS as a flag qemu_hostdev: move ColdBoot as a flag qemu_hostdev: move netconfig file location to virhostdev stateDir extract general code from qemuPrepareHostdevPCIDevices rename qemu*NetConfigRestore/Replace to virHostdevNetConfigRestore/Replace rename qemuGet*PciHostDeviceList to virHostdevGet*PciHostDeviceList pass driver name as a parameter to virHostdevPrepareHostdevPCIDevices extract general code from qemuDomainReAttachHostdevDevices pass driver name as a parameter to virHostdevReAttachPCIDevices rename qemuReAttachPciDevice to virHostdevReAttachPciDevice move virHostdevPrepare(ReAttach)PCIDevices to virhostdev.c extract general code from qemuUpdateActivePciHostdevs extract general code from qemuUpdateActiveUsbHostdevs extract general code from qemuUpdateActiveScsiHostdevs pass driver_name as parameter of virHostdevUpdate*Hostdevs functions move virHostdevUpdate* functions to virhostdev.c qemuPrepareUSBDevices: code adjustment for extracting general code extract general code from qemuPrepareHostUSBDevices rename qemu*USBDevices to virHostdev*USBDevices pass driver name to virHostdevPrepareUSBDevices move virHostdevPrepareHostUSBDevices to virhostdev.c extract general code from qemuPrepareHostSCSIDevices pass driver name as parameter to virHostdevPrepareSCSIDevices move virHostdevPrepareHostSCSIDevices to virhostdev.c extract general code from qemuDomainReAttachHostUsbDevices pass driver name as paramter to virHostdevReAttachUsbHostdevs move virHostdevDomainReAttachHostUsbDevices to virhostdev.c extract general code from qemuDomainReAttachHostScsiDevices pass driver name as parameter to virHostdevReAttachScciHostdevs move virHostdevReAttachHostScsiDevices to virhostdev.c extract general code of NodeDeviceDetach extract general code of NodeDeviceReAttach extract general code of NodeDeviceReset move virHostdevNodeDevice* to virhostdev.c improve parameter name to let it more meaningful rename some function names to keep consistency improve virHostdevUpdate* parameters to make it more widely used add 3 wrapper functions for prepare/reattach/update domain hostdevs add parameter checks to common interfaces add unit test for new virhostdev common library change lxc_hostdev.c to use virhostdev common library APIs add hostdev pci backend type for xen add pci passthrough to libxl driver
.gitignore | 1 + docs/schemas/domaincommon.rng | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/conf/domain_conf.c | 3 +- src/conf/domain_conf.h | 1 + src/libvirt_private.syms | 19 + src/libxl/libxl_conf.c | 63 ++ src/libxl/libxl_conf.h | 4 + src/libxl/libxl_domain.c | 9 + src/libxl/libxl_driver.c | 447 +++++++++++- src/lxc/lxc_conf.h | 4 - src/lxc/lxc_driver.c | 17 +- src/lxc/lxc_hostdev.c | 315 +-------- src/qemu/qemu_command.c | 3 +- src/qemu/qemu_conf.h | 10 +- src/qemu/qemu_driver.c | 88 +-- src/qemu/qemu_hostdev.c | 1220 ++----------------------------- src/qemu/qemu_hostdev.h | 27 +- src/qemu/qemu_hotplug.c | 77 +-- src/qemu/qemu_process.c | 8 +- src/util/virhostdev.c | 1621 +++++++++++++++++++++++++++++++++++++++++ src/util/virhostdev.h | 140 ++++ src/util/virpci.c | 31 +- src/util/virpci.h | 9 +- src/util/virscsi.c | 32 +- src/util/virscsi.h | 7 +- src/util/virusb.c | 31 +- src/util/virusb.h | 8 +- tests/Makefile.am | 5 + tests/virhostdevtest.c | 507 +++++++++++++ tests/virscsitest.c | 6 +- 32 files changed, 3081 insertions(+), 1635 deletions(-) create mode 100644 src/util/virhostdev.c create mode 100644 src/util/virhostdev.h create mode 100644 tests/virhostdevtest.c
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On Mon, Mar 03, 2014 at 05:57:31PM +0100, Cedric Bosdonnat wrote:
Hello ChunYan,
I saw a few minor problems in some patches that made me rebase quite a lot of other patches in your serie, but otherwise it really looks good to me.
Here is a summary of the changes I made or questions I have: * Patch 2: Fixed a few remaining changes that broke the build. Just remember that having the tree building after each commit helps a lot when one later needs to bisect. * Patch 4: when is the manager freed? * Patch 5 & 6: remove the added ATTRIBUTE_UNUSED * Patch 9: added { } around if block to match else style. * Patch 10: remove added ATTRIBUTE_UNUSED * Patch 11: fixed indent function rename * Patch 42: Fix comment about qemuPrepareHostdevPCIDevices in earlier patch * Patch 47: remove added ATTRIBUTE_UNUSED * Patch 49: Fixed the version in libxl_driver.c as 1.2.2 is out
The whole updated patch series is sitting here for those wanting to see the changes applied: https://github.com/cbosdo/libvirt/commits/hostdev-passthrough
Of course, I'ld love another pair of sharper eyes to look at the patch series. I'm not an expert on the hostdev topic ;)
Thanks for posting that. I'm going to start reviewing this series and aim to push as many patches as practical todo so. This is a good time in the release cycle to get such a big change into the tree. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Tue, Mar 04, 2014 at 12:04:39PM +0000, Daniel P. Berrange wrote:
On Mon, Mar 03, 2014 at 05:57:31PM +0100, Cedric Bosdonnat wrote:
Hello ChunYan,
I saw a few minor problems in some patches that made me rebase quite a lot of other patches in your serie, but otherwise it really looks good to me.
Here is a summary of the changes I made or questions I have: * Patch 2: Fixed a few remaining changes that broke the build. Just remember that having the tree building after each commit helps a lot when one later needs to bisect. * Patch 4: when is the manager freed? * Patch 5 & 6: remove the added ATTRIBUTE_UNUSED * Patch 9: added { } around if block to match else style. * Patch 10: remove added ATTRIBUTE_UNUSED * Patch 11: fixed indent function rename * Patch 42: Fix comment about qemuPrepareHostdevPCIDevices in earlier patch * Patch 47: remove added ATTRIBUTE_UNUSED * Patch 49: Fixed the version in libxl_driver.c as 1.2.2 is out
The whole updated patch series is sitting here for those wanting to see the changes applied: https://github.com/cbosdo/libvirt/commits/hostdev-passthrough
Of course, I'ld love another pair of sharper eyes to look at the patch series. I'm not an expert on the hostdev topic ;)
Thanks for posting that. I'm going to start reviewing this series and aim to push as many patches as practical todo so. This is a good time in the release cycle to get such a big change into the tree.
Unfortunately I was only able to push two patches until I hit problems that are larger than I want to resolve myself. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

2014-03-04 0:57 GMT+08:00 Cedric Bosdonnat <cbosdonnat@suse.com>:
Hello ChunYan,
I saw a few minor problems in some patches that made me rebase quite a lot of other patches in your serie, but otherwise it really looks good to me.
Here is a summary of the changes I made or questions I have: * Patch 2: Fixed a few remaining changes that broke the build. Just remember that having the tree building after each commit helps a lot when one later needs to bisect. * Patch 4: when is the manager freed?
It's hard to find a specified code point to free the manager, since we don't know is there anyone else still using it.
* Patch 5 & 6: remove the added ATTRIBUTE_UNUSED * Patch 9: added { } around if block to match else style. * Patch 10: remove added ATTRIBUTE_UNUSED * Patch 11: fixed indent function rename * Patch 42: Fix comment about qemuPrepareHostdevPCIDevices in earlier patch * Patch 47: remove added ATTRIBUTE_UNUSED * Patch 49: Fixed the version in libxl_driver.c as 1.2.2 is out
The whole updated patch series is sitting here for those wanting to see the changes applied: https://github.com/cbosdo/libvirt/commits/hostdev-passthrough
Of course, I'ld love another pair of sharper eyes to look at the patch series. I'm not an expert on the hostdev topic ;)
Kind regards -- Cedric
These patches implements a separate module for hostdev passthrough so
could be shared by different drivers and can maintain a global state of a host device.
Patches 1~6 are to switch existing qemu and lxc driver to use common
lists, so that to maintain a global state of every host device.
Patches 7~45 are to extract general code from qemu_hostdev.c piece by
make them reusable common APIs.
Patches 46: unit test for the virhostdev common library Patches 47: add a hostdev backend type for xen Patches 48: add pci passthrough to libxl driver based on the common
Patches 49: change lxc to use common library APIs
--- changes to v12: * split "add hostdev passthrough common library" patch into small
On Sat, 2014-03-01 at 14:28 +0800, Chunyan Liu wrote: that it library piece, library patches
for easier review. * fix v12 comments * rebase to libxl changes
Chunyan Liu (49): add 'driver' info to used_by qemu: reuse hostdev interfaces to avoid duplicate qemu: remove functions now used internally only from qemu_hostdev.h add virhostdev files to maintain global state of host devices qemu: use general virhostdev lists instead of its own lxc: use general virhostdev lists instead of its own qemu_hostdev: move cfg->relaxedACS as a flag qemu_hostdev: move ColdBoot as a flag qemu_hostdev: move netconfig file location to virhostdev stateDir extract general code from qemuPrepareHostdevPCIDevices rename qemu*NetConfigRestore/Replace to virHostdevNetConfigRestore/Replace rename qemuGet*PciHostDeviceList to virHostdevGet*PciHostDeviceList pass driver name as a parameter to virHostdevPrepareHostdevPCIDevices extract general code from qemuDomainReAttachHostdevDevices pass driver name as a parameter to virHostdevReAttachPCIDevices rename qemuReAttachPciDevice to virHostdevReAttachPciDevice move virHostdevPrepare(ReAttach)PCIDevices to virhostdev.c extract general code from qemuUpdateActivePciHostdevs extract general code from qemuUpdateActiveUsbHostdevs extract general code from qemuUpdateActiveScsiHostdevs pass driver_name as parameter of virHostdevUpdate*Hostdevs functions move virHostdevUpdate* functions to virhostdev.c qemuPrepareUSBDevices: code adjustment for extracting general code extract general code from qemuPrepareHostUSBDevices rename qemu*USBDevices to virHostdev*USBDevices pass driver name to virHostdevPrepareUSBDevices move virHostdevPrepareHostUSBDevices to virhostdev.c extract general code from qemuPrepareHostSCSIDevices pass driver name as parameter to virHostdevPrepareSCSIDevices move virHostdevPrepareHostSCSIDevices to virhostdev.c extract general code from qemuDomainReAttachHostUsbDevices pass driver name as paramter to virHostdevReAttachUsbHostdevs move virHostdevDomainReAttachHostUsbDevices to virhostdev.c extract general code from qemuDomainReAttachHostScsiDevices pass driver name as parameter to virHostdevReAttachScciHostdevs move virHostdevReAttachHostScsiDevices to virhostdev.c extract general code of NodeDeviceDetach extract general code of NodeDeviceReAttach extract general code of NodeDeviceReset move virHostdevNodeDevice* to virhostdev.c improve parameter name to let it more meaningful rename some function names to keep consistency improve virHostdevUpdate* parameters to make it more widely used add 3 wrapper functions for prepare/reattach/update domain hostdevs add parameter checks to common interfaces add unit test for new virhostdev common library change lxc_hostdev.c to use virhostdev common library APIs add hostdev pci backend type for xen add pci passthrough to libxl driver
.gitignore | 1 + docs/schemas/domaincommon.rng | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/conf/domain_conf.c | 3 +- src/conf/domain_conf.h | 1 + src/libvirt_private.syms | 19 + src/libxl/libxl_conf.c | 63 ++ src/libxl/libxl_conf.h | 4 + src/libxl/libxl_domain.c | 9 + src/libxl/libxl_driver.c | 447 +++++++++++- src/lxc/lxc_conf.h | 4 - src/lxc/lxc_driver.c | 17 +- src/lxc/lxc_hostdev.c | 315 +-------- src/qemu/qemu_command.c | 3 +- src/qemu/qemu_conf.h | 10 +- src/qemu/qemu_driver.c | 88 +-- src/qemu/qemu_hostdev.c | 1220 ++----------------------------- src/qemu/qemu_hostdev.h | 27 +- src/qemu/qemu_hotplug.c | 77 +-- src/qemu/qemu_process.c | 8 +- src/util/virhostdev.c | 1621
+++++++++++++++++++++++++++++++++++++++++
src/util/virhostdev.h | 140 ++++ src/util/virpci.c | 31 +- src/util/virpci.h | 9 +- src/util/virscsi.c | 32 +- src/util/virscsi.h | 7 +- src/util/virusb.c | 31 +- src/util/virusb.h | 8 +- tests/Makefile.am | 5 + tests/virhostdevtest.c | 507 +++++++++++++ tests/virscsitest.c | 6 +- 32 files changed, 3081 insertions(+), 1635 deletions(-) create mode 100644 src/util/virhostdev.c create mode 100644 src/util/virhostdev.h create mode 100644 tests/virhostdevtest.c
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On Wed, Mar 05, 2014 at 02:15:51PM +0800, Chunyan Liu wrote:
2014-03-04 0:57 GMT+08:00 Cedric Bosdonnat <cbosdonnat@suse.com>:
Hello ChunYan,
I saw a few minor problems in some patches that made me rebase quite a lot of other patches in your serie, but otherwise it really looks good to me.
Here is a summary of the changes I made or questions I have: * Patch 2: Fixed a few remaining changes that broke the build. Just remember that having the tree building after each commit helps a lot when one later needs to bisect. * Patch 4: when is the manager freed?
It's hard to find a specified code point to free the manager, since we don't know is there anyone else still using it.
If we now keep a reference to the manager in the virQEMUDriver struct and the same for the LXC/libxl drivers, then you could turn the virHostdevManagerPtr struct into a virObject. Then you can use ref counting to make it get free'd when the drivers shutdown. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|
participants (5)
-
Cedric Bosdonnat
-
Chunyan Liu
-
Daniel P. Berrange
-
Jim Fehlig
-
John Ferlan