2013/5/27 Marek Marczykowski <marmarek@xxxxxxxxxxxxxxxxxxxxxx>
On 16.05.2013 08:07, Chunyan Liu wrote:Some comments inline. Besides that seems to be working (with your next patch
> Write separate module for hostdev passthrough so that it could be used by all
> hypervisor drivers and maintain a global hostdev state.
>
> Signed-off-by: Chunyan Liu <cyliu@xxxxxxxx>
for libxl) :)
Thanks for your comments! Will update.
(Didn't change qemu and lxc drivers yet, I think it's better to change existing drivers after there is a consensus on the common library.)
(Didn't change qemu and lxc drivers yet, I think it's better to change existing drivers after there is a consensus on the common library.)
"make check" reports wrong symbol order here.> ---
> po/POTFILES.in | 1 +
> src/Makefile.am | 1 +
> src/libvirt.c | 5 +
> src/libvirt_private.syms | 15 +
> src/util/virhostdevmanager.c | 1218 ++++++++++++++++++++++++++++++++++++++++++
> src/util/virhostdevmanager.h | 91 ++++
> src/util/virpci.c | 17 +-
> src/util/virpci.h | 7 +-
> src/util/virusb.c | 19 +-
> src/util/virusb.h | 4 +-
> 10 files changed, 1362 insertions(+), 16 deletions(-)
> create mode 100644 src/util/virhostdevmanager.c
> create mode 100644 src/util/virhostdevmanager.h
>
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index f3ea4da..a7c21bf 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -188,6 +188,7 @@ src/util/viruri.c
> src/util/virusb.c
> src/util/virutil.c
> src/util/virxml.c
> +src/util/virhostdevmanager.c
> src/vbox/vbox_MSCOMGlue.c
> src/vbox/vbox_XPCOMCGlue.c
> src/vbox/vbox_driver.c
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 4312c3c..a197c2b 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -130,6 +130,7 @@ UTIL_SOURCES = \
> util/virutil.c util/virutil.h \
> util/viruuid.c util/viruuid.h \
> util/virxml.c util/virxml.h \
> + util/virhostdevmanager.c util/virhostdevmanager.h \
> $(NULL)
>
>
> diff --git a/src/libvirt.c b/src/libvirt.c
> index 2b3515e..d9af5a6 100644
> --- a/src/libvirt.c
> +++ b/src/libvirt.c
> @@ -65,6 +65,7 @@
> #include "virthread.h"
> #include "virstring.h"
> #include "virutil.h"
> +#include "virhostdevmanager.h"
>
> #ifdef WITH_TEST
> # include "test/test_driver.h"
> @@ -827,6 +828,7 @@ int virStateInitialize(bool privileged,
> if (virInitialize() < 0)
> return -1;
>
> + virHostdevManagerInit();
> for (i = 0 ; i < virStateDriverTabCount ; i++) {
> if (virStateDriverTab[i]->stateInitialize) {
> VIR_DEBUG("Running global init for %s state driver",
> @@ -858,6 +860,9 @@ int virStateCleanup(void) {
> virStateDriverTab[i]->stateCleanup() < 0)
> ret = -1;
> }
> +
> + virHostdevManagerCleanup();
> +
> return ret;
> }
>
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index cdd0b41..824de4e 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1991,6 +1991,21 @@ virXPathULong;
> virXPathULongHex;
> virXPathULongLong;
>
> +#util/virhostdevmanager.h
> +virHostdevManagerGetDefault;
> +virHostdevManagerInit;
> +virHostdevManagerCleanup;
> +virHostdevManagerPrepareHostdevs;
> +virHostdevManagerReAttachHostdevs;
> +virHostdevManagerPreparePciHostdevs;
> +virHostdevManagerPrepareUsbHostdevs;
> +virHostdevManagerReAttachPciHostdevs;
> +virHostdevManagerReAttachUsbHostdevs;
> +virGetActivePciHostdevs;
> +virGetActiveUsbHostdevs;
> +virGetDomainActivePciHostdevs;
> +virGetDomainActiveUsbHostdevs;
> +virFreeHostdevNameList;
goto out_of_memory ?
>
> # Let emacs know we want case-insensitive sorting
> # Local Variables:
> diff --git a/src/util/virhostdevmanager.c b/src/util/virhostdevmanager.c
> new file mode 100644
> index 0000000..9034212
> --- /dev/null
> +++ b/src/util/virhostdevmanager.c
> @@ -0,0 +1,1218 @@
> +/*
> + * Copyright (C) 2013 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@xxxxxxxx>
> + */
> +#include <config.h>
> +
> +#include "virhostdevmanager.h"
> +
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +#include "viralloc.h"
> +#include "virstring.h"
> +#include "virfile.h"
> +#include "virerror.h"
> +#include "virlog.h"
> +#include "virpci.h"
> +#include "virusb.h"
> +#include "virnetdev.h"
> +
> +/* For virReportOOMError() and virReportSystemError() */
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +struct _virHostdevManager{
> + char *stateDir;
> +
> + virPCIDeviceListPtr activePciHostdevs;
> + virPCIDeviceListPtr inactivePciHostdevs;
> + virUSBDeviceListPtr activeUsbHostdevs;
> +};
> +
> +static virHostdevManagerPtr hostdevMgr;
> +
> +int virHostdevManagerInit(void)
> +{
> + char ebuf[1024];
> + if (VIR_ALLOC(hostdevMgr) < 0)
> + return -1;
> +
> + if ((hostdevMgr->activePciHostdevs = virPCIDeviceListNew()) == NULL)
> + return -1;
goto out_of_memory ?
> +
> + if ((hostdevMgr->activeUsbHostdevs = virUSBDeviceListNew()) == NULL)
> + return -1;
goto out_of_memory ?
> +
> + if ((hostdevMgr->inactivePciHostdevs = virPCIDeviceListNew()) == NULL)
> + return -1;
Really need hardcode driver name here? BTW "xen" driver missing here.
> +
> + if (virAsprintf(&hostdevMgr->stateDir,
> + "%s",HOSTDEV_STATE_DIR) == -1)
> + goto out_of_memory;
> +
> + if (virFileMakePath(hostdevMgr->stateDir) < 0) {
> + VIR_ERROR(_("Failed to create state dir '%s': %s"),
> + hostdevMgr->stateDir, virStrerror(errno, ebuf, sizeof(ebuf)));
> + goto error;
> + }
> +
> + return 0;
> +
> +out_of_memory:
> + virReportOOMError();
> +error:
> + return -1;
> +}
> +
> +void virHostdevManagerCleanup(void)
> +{
> + if(!hostdevMgr)
> + return;
> +
> + virObjectUnref(hostdevMgr->activePciHostdevs);
> + virObjectUnref(hostdevMgr->inactivePciHostdevs);
> + virObjectUnref(hostdevMgr->activeUsbHostdevs);
> +
> + VIR_FREE(hostdevMgr->stateDir);
> +}
> +
> +virHostdevManagerPtr virHostdevManagerGetDefault(void)
> +{
> + return hostdevMgr;
> +}
> +
> +static int
> +virDomainHostdevPciSysfsPath(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
> +virDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
> +{
> + char *sysfs_path = NULL;
> + int ret = -1;
> +
> + if (virDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
> + return ret;
> +
> + ret = virPCIIsVirtualFunction(sysfs_path);
> +
> + VIR_FREE(sysfs_path);
> +
> + return ret;
> +}
> +
> +static int
> +virDomainHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev,
> + int *vf)
> +{
> + int ret = -1;
> + char *sysfs_path = NULL;
> +
> + if (virDomainHostdevPciSysfsPath(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
> +virDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
> + virNetDevVPortProfilePtr virtPort,
> + const virMacAddrPtr macaddr,
> + const unsigned char *uuid,
> + int 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
> +virDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
> + const unsigned char *uuid,
> + char *stateDir)
> +{
> + char *linkdev = NULL;
> + virNetDevVlanPtr vlan;
> + virNetDevVPortProfilePtr virtPort;
> + int ret = -1;
> + int vf = -1;
> + int vlanid = -1;
> + int port_profile_associate = 1;
> + int isvf;
> +
> + isvf = virDomainHostdevIsVirtualFunction(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 (virDomainHostdevNetDevice(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 = virDomainHostdevNetConfigVirtPortProfile(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;
> +}
> +
> +static int
> +virDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
> + char *stateDir)
> +{
> + char *linkdev = NULL;
> + virNetDevVPortProfilePtr virtPort;
> + int ret = -1;
> + int vf = -1;
> + int port_profile_associate = 0;
> + int isvf;
> +
> + isvf = virDomainHostdevIsVirtualFunction(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 (virDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
> + return ret;
> +
> + virtPort = virDomainNetGetActualVirtPortProfile(
> + hostdev->parent.data.net);
> + if (virtPort)
> + ret = virDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
> + &hostdev->parent.data.net->mac, NULL,
> + port_profile_associate);
> + else
> + ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);
> +
> + VIR_FREE(linkdev);
> +
> + return ret;
> +}
> +
> +static virPCIDeviceListPtr
> +virHostdevManagerGetPciHostDeviceList(
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + virPCIDeviceListPtr list;
> + int 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);
> + }
> +
> + return list;
> +}
> +
> +int
> +virHostdevManagerPreparePciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + const unsigned char *uuid,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + unsigned int flags)
> +{
> + virPCIDeviceListPtr pcidevs;
> + int last_processed_hostdev_vf = -1;
> + int i;
> + int ret = -1;
> +
> + virObjectLock(mgr->activePciHostdevs);
> + virObjectLock(mgr->inactivePciHostdevs);
> +
> + if (!(pcidevs = virHostdevManagerGetPciHostDeviceList(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)?true:false;
> +
> + 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(mgr->activePciHostdevs, dev))) {
> + char *other_drvname = NULL;
> + char *other_domname = NULL;
> + 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));
> + VIR_FREE(other_drvname);
> + VIR_FREE(other_domname);
> + goto cleanup;
> + }
> + }
> +
> + /* Loop 2: detach managed devices */
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + const char *stub_driver;
> + if (STREQ_NULLABLE(drv_name, "xenlight"))
> + stub_driver = "pciback";
> + else
> + stub_driver = "pci_stub";
Perhaps this can be passes as parameter (with default to "pci_stub" if NULL)?
Or set by driver before calling this function (virPCIDeviceSetSubDriver?).
Yes, it's better to set by driver before calling this function by virPCIDeviceSetSubDriver. Will update.
Same as earlier, perhaps the better approach will be checking for current stub> +
> + if (virPCIDeviceGetManaged(dev) &&
> + virPCIDeviceDetach(dev, mgr->activePciHostdevs, NULL, stub_driver) < 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, mgr->activePciHostdevs,
> + 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 (virDomainHostdevNetConfigReplace(hostdev, uuid,
> + 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(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(mgr->inactivePciHostdevs, dev);
> + }
> +
> + /* Loop 7: Now set the used_by_domain of the device in
> + * driver->activePciHostdevs as domain name.
> + */
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev, activeDev;
> +
> + dev = virPCIDeviceListGet(pcidevs, i);
> + activeDev = virPCIDeviceListFind(mgr->activePciHostdevs, dev);
> +
> + if (activeDev)
> + virPCIDeviceSetUsedBy(activeDev, drv_name, dom_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 driver->activePciHostdevs. We will
> + * free them in virObjectUnref().
> + */
> + while (virPCIDeviceListCount(pcidevs) > 0) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, 0);
> + virPCIDeviceListSteal(mgr->activePciHostdevs, dev);
> + }
> +
> +resetvfnetconfig:
> + for (i = 0; i < last_processed_hostdev_vf; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
> + hostdev->parent.data.net) {
> + virDomainHostdevNetConfigRestore(hostdev, mgr->stateDir);
> + }
> + }
> +
> +reattachdevs:
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + virPCIDeviceReattach(dev, mgr->activePciHostdevs, NULL);
> + }
> +
> +cleanup:
> + virObjectUnlock(mgr->activePciHostdevs);
> + virObjectUnlock(mgr->inactivePciHostdevs);
> + virObjectUnref(pcidevs);
> + return ret;
> +}
> +
> +static int
> +virFindHostdevUSBDevice(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
> +virHostdevManagerMarkUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virUSBDeviceListPtr list)
> +{
> + int 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))) {
> + char *other_drvname = NULL;
> + char *other_domname = NULL;
> + 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));
> + VIR_FREE(other_drvname);
> + VIR_FREE(other_domname);
> + goto error;
> + }
> +
> + virUSBDeviceSetUsedBy(usb, drv_name, dom_name);
> + VIR_DEBUG("Adding %03d.%03d driver= %s dom=%s to activeUsbHostdevs",
> + virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb),drv_name, dom_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;
> +}
> +
> +int virHostdevManagerPrepareUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + bool coldBoot)
> +{
> + int i, ret = -1;
> + virUSBDeviceListPtr list;
> + virUSBDevicePtr tmp;
> + virDomainHostdevDefPtr *hostdevs = def->hostdevs;
> + int nhostdevs = def->nhostdevs;
> +
> + /* 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.
> + */
> + 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 (virFindHostdevUSBDevice(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 (virHostdevManagerMarkUsbHostdevs(mgr, 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;
> +
> +cleanup:
> + virObjectUnref(list);
> + return ret;
> +}
> +
> +int virHostdevManagerPrepareHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags)
> +{
> + if (!def->nhostdevs)
> + return 0;
> +
> + if (flags & VIR_SP_PCI_HOSTDEV) {
> + if(virHostdevManagerPreparePciHostdevs(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)?true:false;
> + if(virHostdevManagerPrepareUsbHostdevs(mgr, driver, def, coldBoot) < 0)
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * Pre-condition: mgr->inactivePciHostdevs & mgr->activePciHostdevs
> + * are locked
> + */
> +static void
> +virReattachPciDevice(virHostdevManagerPtr mgr, virPCIDevicePtr dev, const char *driver)
> +{
> + /* 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;
> + }
> +
> + if (STREQ_NULLABLE(driver, "QEMU")) {
driver here?
virReportOOMError?
> + 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);
> +}
> +
> +/*
> + * Pre-condition: driver->activePciHostdevs is locked
> + */
> +static virPCIDeviceListPtr
> +virGetActivePciHostDeviceList(virHostdevManagerPtr mgr,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + virPCIDeviceListPtr list;
> + int i;
> +
> + if (!(list = virPCIDeviceListNew()))
> + return NULL;
> +
> + for (i = 0 ; i < nhostdevs ; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + virPCIDevicePtr dev;
> + virPCIDevicePtr activeDev;
> +
> + 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 ((activeDev = virPCIDeviceListFind(mgr->activePciHostdevs, dev))) {
> + if (virPCIDeviceListAdd(list, activeDev) < 0) {
> + virPCIDeviceFree(dev);
> + virObjectUnref(list);
> + return NULL;
> + }
> + }
> +
> + virPCIDeviceFree(dev);
> + }
> +
> + return list;
> +}
> +
> +void
> +virHostdevManagerReAttachPciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + virPCIDeviceListPtr pcidevs;
> + int i;
> +
> + virObjectLock(mgr->activePciHostdevs);
> + virObjectLock(mgr->inactivePciHostdevs);
> +
> + if (!(pcidevs = virGetActivePciHostDeviceList(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;
> +
> + /* Never delete the dev from list driver->activePciHostdevs
> + * if it's used by other domain.
> + */
> + activeDev = virPCIDeviceListFind(mgr->activePciHostdevs, dev);
> + if (activeDev) {
> + char *usedby_drvname = NULL;
> + char *usedby_domname = NULL;
> + virPCIDeviceGetUsedBy(activeDev, &usedby_drvname, &usedby_domname);
> + if (STRNEQ_NULLABLE(drv_name, usedby_drvname) &&
> + STRNEQ_NULLABLE(dom_name, usedby_domname)) {
> + virPCIDeviceListSteal(pcidevs, dev);
> + continue;
> + }
> + VIR_FREE(usedby_drvname);
> + VIR_FREE(usedby_domname);
> + }
> +
> + /* virObjectUnref() will take care of freeing the dev. */
> + virPCIDeviceListSteal(mgr->activePciHostdevs, dev);
> + }
> +
> + /*
> + * For SRIOV net host devices, unset mac and port profile before
> + * reset and reattach device
> + */
> + 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) {
> + virDomainHostdevNetConfigRestore(hostdev, mgr->stateDir);
> + }
> + }
> +
> + for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
> + if (virPCIDeviceReset(dev, mgr->activePciHostdevs,
> + 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);
> + virReattachPciDevice(mgr, dev, drv_name);
> + }
> +
> + virObjectUnref(pcidevs);
> +cleanup:
> + virObjectUnlock(mgr->activePciHostdevs);
> + virObjectUnlock(mgr->inactivePciHostdevs);
> +}
> +
> +void
> +virHostdevManagerReAttachUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs)
> +{
> + int i;
> +
> + virObjectLock(mgr->activeUsbHostdevs);
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + virUSBDevicePtr usb, tmp;
> +
> + 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 driver %s domain %s",
> + hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device,
> + drv_name, dom_name);
> + continue;
> + }
> +
> + /* Delete only those USB devices which belongs
> + * to domain. Therefore we want to steal only
> + * those devices from the list which were taken
> + * by domain */
> +
> + tmp = virUSBDeviceListFind(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;
> + }
> +
> + char *usedby_drvname = NULL;
> + char *usedby_domname = NULL;
> + virUSBDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname);
> + if (STREQ_NULLABLE(drv_name, usedby_drvname) &&
> + STREQ_NULLABLE(dom_name, usedby_domname)) {
> + VIR_DEBUG("Removing %03d.%03d dom=%s:%s",
> + hostdev->source.subsys.u.usb.bus,
> + hostdev->source.subsys.u.usb.device,
> + drv_name, dom_name);
> + virUSBDeviceListDel(mgr->activeUsbHostdevs, tmp);
> + }
> + VIR_FREE(usedby_drvname);
> + VIR_FREE(usedby_domname);
> +
> + }
> + virObjectUnlock(mgr->activeUsbHostdevs);
> +}
> +
> +void virHostdevManagerReAttachHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags)
> +{
> + if (!def->nhostdevs)
> + return;
> +
> + if (flags & VIR_SP_PCI_HOSTDEV) {
> + virHostdevManagerReAttachPciHostdevs(mgr, driver, def->name, def->hostdevs, def->nhostdevs);
> + }
> +
> + if (flags & VIR_SP_USB_HOSTDEV) {
> + virHostdevManagerReAttachUsbHostdevs(mgr, driver, def->name, def->hostdevs, def->nhostdevs);
> + }
> +}
> +
> +
> +/*After using any of the above four *Get* APIs, virFreeHostdevNameList should
> + *be called to free memory.
> + */
> +void virFreeHostdevNameList(virHostdevNameListPtr list){
> + int i;
> +
> + if (list && list->names) {
> + for (i = 0; i < list->nnames; i++) {
> + if (list->names[i])
> + VIR_FREE(list->names[i]);
> + }
> + VIR_FREE(list->names);
> + }
> + VIR_FREE(list);
> +}
> +
> +virHostdevNameListPtr
> +virGetActivePciHostdevs(virHostdevManagerPtr mgr)
> +{
> + int i,count;
> + virHostdevNameListPtr list = NULL;
> + virObjectLock(mgr->activePciHostdevs);
> +
> + count = virPCIDeviceListCount(mgr->activePciHostdevs);
> + if (count > 0) {
> + if (VIR_ALLOC_N(list, 1) < 0) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("Fail to alloc memory"));
virReportOOMError?
> + goto cleanup;
> + }
> +
> + if (VIR_ALLOC_N(list->names,count) < 0) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("Fail to alloc memory"));
virReportOOMError?
> + goto cleanup;
> + }
> + list->nnames = 0;
> +
> + for (i = 0; i < count; i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(mgr->activePciHostdevs, i);
> + list->names[list->nnames++] = strdup(virPCIDeviceGetName(dev));
> + }
> + }
> +
> +cleanup:
> + virFreeHostdevNameList(list);
> + virObjectUnlock(mgr->activePciHostdevs);
> + return list;
> +
> +
> +}
> +
> +virHostdevNameListPtr
> +virGetActiveUsbHostdevs(virHostdevManagerPtr mgr)
> +{
> + int i,count;
> + virHostdevNameListPtr list = NULL;
> + virObjectLock(mgr->activeUsbHostdevs);
> +
> + count = virUSBDeviceListCount(mgr->activeUsbHostdevs);
> + if (count > 0) {
> + if (VIR_ALLOC_N(list, 1) < 0) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("Fail to alloc memory"));
virReportOOMError?
> + goto cleanup;
> + }
> +
> + if (VIR_ALLOC_N(list->names,count) < 0) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("Fail to alloc memory"));
virReportOOMError?
> + goto cleanup;
> + }
> + list->nnames = 0;
> +
> + for (i = 0; i < count; i++) {
> + virUSBDevicePtr usb = virUSBDeviceListGet(mgr->activeUsbHostdevs, i);
> + list->names[list->nnames++] = strdup(virUSBDeviceGetName(usb));
> + }
> + }
> +
> +cleanup:
> + virFreeHostdevNameList(list);
> + virObjectUnlock(mgr->activeUsbHostdevs);
> + return list;
> +}
> +
> +virHostdevNameListPtr
> +virGetDomainActivePciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name)
> +{
> + int i;
> + size_t count;
> + virHostdevNameListPtr list = NULL;
> + virObjectLock(mgr->activePciHostdevs);
> +
> + count = virPCIDeviceListCount(mgr->activePciHostdevs);
> + if (count > 0) {
> + if (VIR_ALLOC_N(list, 1) < 0) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("Fail to alloc memory"));
virReportOOMError?
> + goto cleanup;
> + }
> +
> + if (VIR_ALLOC_N(list->names,count) < 0) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("Fail to alloc memory"));
virReportOOMError?
> + goto cleanup;
> + }
> + list->nnames = 0;
> +
> + for (i = 0; i < count; i++) {
> + virPCIDevicePtr dev = virPCIDeviceListGet(mgr->activePciHostdevs, i);
> + char *usedby_drvname = NULL;
> + char *usedby_domname = NULL;
> + virPCIDeviceGetUsedBy(dev, &usedby_drvname, &usedby_domname);
> + if (STRNEQ(drv_name, usedby_drvname) &&
> + STRNEQ(dom_name, usedby_domname)) {
> + list->names[list->nnames++] = strdup(virPCIDeviceGetName(dev));
> + }
> + VIR_FREE(usedby_drvname);
> + VIR_FREE(usedby_domname);
> + }
> +
> + VIR_SHRINK_N(list->names, count, count - list->nnames);
> + }
> +
> +cleanup:
> + virFreeHostdevNameList(list);
> + virObjectUnlock(mgr->activePciHostdevs);
> + return list;
> +}
> +
> +virHostdevNameListPtr
> +virGetDomainActiveUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name)
> +{
> + int i;
> + size_t count;
> + virHostdevNameListPtr list = NULL;
> + virObjectLock(mgr->activeUsbHostdevs);
> +
> + count = virUSBDeviceListCount(mgr->activeUsbHostdevs);
> + if (count > 0) {
> + if (VIR_ALLOC_N(list, 1) < 0) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("Fail to alloc memory"));
virReportOOMError?
> + goto cleanup;
> + }
> +
> + if (VIR_ALLOC_N(list->names,count) < 0) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("Fail to alloc memory"));
This change gives qemu and lxc drivers compile fail. So those drivers needs
> + goto cleanup;
> + }
> + list->nnames = 0;
> +
> + for (i = 0; i < count; i++) {
> + virUSBDevicePtr usb = virUSBDeviceListGet(mgr->activeUsbHostdevs, i);
> + char *usedby_drvname = NULL;
> + char *usedby_domname = NULL;
> + virUSBDeviceGetUsedBy(usb, &usedby_drvname, &usedby_domname);
> + if (STRNEQ(drv_name, usedby_drvname) &&
> + STRNEQ(dom_name, usedby_domname)) {
> + list->names[list->nnames++] = strdup(virUSBDeviceGetName(usb));
> + }
> + VIR_FREE(usedby_drvname);
> + VIR_FREE(usedby_domname);
> + }
> +
> + VIR_SHRINK_N(list->names, count, count - list->nnames);
> + }
> +
> +cleanup:
> + virFreeHostdevNameList(list);
> + virObjectUnlock(mgr->activeUsbHostdevs);
> + return list;
> +}
> diff --git a/src/util/virhostdevmanager.h b/src/util/virhostdevmanager.h
> new file mode 100644
> index 0000000..e493ac5
> --- /dev/null
> +++ b/src/util/virhostdevmanager.h
> @@ -0,0 +1,91 @@
> +/*
> + * Copyright (C) 2013 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@xxxxxxxx>
> + */
> +
> +#ifndef __VIR_HOSTDEV_MANAGER_H__
> +# define __VIR_HOSTDEV_MANAGER_H__
> +
> +# include "internal.h"
> +# include "configmake.h"
> +# include "conf/domain_conf.h"
> +
> +# define HOSTDEV_STATE_DIR LOCALSTATEDIR "/run/libvirt/hostdevmanager"
> +
> +typedef enum {
> + VIR_SP_PCI_HOSTDEV = (1 << 0), /* support pci passthrough */
> + VIR_SP_USB_HOSTDEV = (1 << 1), /* support usb passthrough */
> + VIR_COLD_BOOT = (1 << 2), /* cold boot */
> + VIR_STRICT_ACS_CHECK = (1 << 3), /* strict acs check */
> +} virHostdevManagerFlag;
> +
> +typedef struct _virHostdevManager virHostdevManager;
> +typedef virHostdevManager *virHostdevManagerPtr;
> +
> +struct virHostdevNameList {
> + char **names;
> + size_t nnames;
> +};
> +typedef struct virHostdevNameList *virHostdevNameListPtr;
> +
> +virHostdevManagerPtr virHostdevManagerGetDefault(void);
> +int virHostdevManagerInit(void);
> +void virHostdevManagerCleanup(void);
> +int virHostdevManagerPrepareHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags);
> +void virHostdevManagerReAttachHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + unsigned int flags);
> +int virHostdevManagerPreparePciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + const unsigned char *uuid,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs,
> + unsigned int flags);
> +int virHostdevManagerPrepareUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *driver,
> + virDomainDefPtr def,
> + bool coldBoot);
> +void virHostdevManagerReAttachPciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs);
> +void virHostdevManagerReAttachUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name,
> + virDomainHostdevDefPtr *hostdevs,
> + int nhostdevs);
> +virHostdevNameListPtr virGetActivePciHostdevs(virHostdevManagerPtr mgr);
> +virHostdevNameListPtr virGetActiveUsbHostdevs(virHostdevManagerPtr mgr);
> +virHostdevNameListPtr virGetDomainActivePciHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name);
> +virHostdevNameListPtr virGetDomainActiveUsbHostdevs(virHostdevManagerPtr mgr,
> + const char *drv_name,
> + const char *dom_name);
> +/*After using any of the above four *Get* APIs, virFreeHostdevNameList should
> + *be called to free memory.
> + */
> +void virFreeHostdevNameList(virHostdevNameListPtr list);
> +
> +#endif /* __VIR_HOSTDEV_MANAGER_H__ */
> diff --git a/src/util/virpci.c b/src/util/virpci.c
> index 5865613..7fe0921 100644
> --- a/src/util/virpci.c
> +++ b/src/util/virpci.c
> @@ -62,7 +62,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 */
> + const char *used_by_drvname;
> + const char *used_by_domname;
>
> unsigned int pcie_cap_pos;
> unsigned int pci_pm_cap_pos;
> @@ -1553,15 +1556,17 @@ virPCIDeviceSetReprobe(virPCIDevicePtr dev, bool reprobe)
> }
>
> void
> -virPCIDeviceSetUsedBy(virPCIDevicePtr dev, const char *name)
> +virPCIDeviceSetUsedBy(virPCIDevicePtr dev, const char *drv_name, const char *dom_name)
> {
> - dev->used_by = name;
> + dev->used_by_drvname = drv_name;
> + dev->used_by_domname = dom_name;
> }
>
> -const char *
> -virPCIDeviceGetUsedBy(virPCIDevicePtr dev)
> +void
> +virPCIDeviceGetUsedBy(virPCIDevicePtr dev, char **drv_name, char **dom_name)
> {
> - return dev->used_by;
> + *drv_name = strdup(dev->used_by_drvname);
> + *dom_name = strdup(dev->used_by_domname);
> }
>
> void virPCIDeviceReattachInit(virPCIDevicePtr pci)
> diff --git a/src/util/virpci.h b/src/util/virpci.h
> index 7bcadb4..294cb0e 100644
> --- a/src/util/virpci.h
> +++ b/src/util/virpci.h
> @@ -66,8 +66,11 @@ void virPCIDeviceSetStubDriver(virPCIDevicePtr dev,
> const char *driver);
> const char *virPCIDeviceGetStubDriver(virPCIDevicePtr dev);
> void virPCIDeviceSetUsedBy(virPCIDevice *dev,
> - const char *used_by);
> -const char *virPCIDeviceGetUsedBy(virPCIDevice *dev);
> + const char *drv_name,
> + const char *dom_name);
> +void virPCIDeviceGetUsedBy(virPCIDevice *dev,
> + char **drv_name,
> + char **dom_name);
> unsigned int virPCIDeviceGetUnbindFromStub(virPCIDevicePtr dev);
> void virPCIDeviceSetUnbindFromStub(virPCIDevice *dev,
> bool unbind);
> diff --git a/src/util/virusb.c b/src/util/virusb.c
> index 27ba9c7..043206e 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 */
> + const char *used_by_drvname;
> + const char *used_by_domname;
> };
>
> struct _virUSBDeviceList {
> @@ -383,16 +386,20 @@ virUSBDeviceFree(virUSBDevicePtr dev)
> VIR_FREE(dev);
> }
>
> -
> void virUSBDeviceSetUsedBy(virUSBDevicePtr dev,
> - const char *name)
> + const char *drv_name,
> + const char *dom_name)
> {
> - dev->used_by = name;
> + dev->used_by_drvname = drv_name;
> + dev->used_by_domname = dom_name;
> }
>
> -const char * virUSBDeviceGetUsedBy(virUSBDevicePtr dev)
> +void virUSBDeviceGetUsedBy(virUSBDevicePtr dev,
> + char **drv_name,
> + char **dom_name)
> {
> - return dev->used_by;
> + *drv_name = strdup(dev->used_by_drvname);
> + *dom_name = strdup(dev->used_by_domname);
> }
>
> const char *virUSBDeviceGetName(virUSBDevicePtr dev)
> diff --git a/src/util/virusb.h b/src/util/virusb.h
> index aa59d12..16e48e5 100644
> --- a/src/util/virusb.h
> +++ b/src/util/virusb.h
> @@ -60,8 +60,8 @@ int virUSBDeviceFind(unsigned int vendor,
> virUSBDevicePtr *usb);
>
> void virUSBDeviceFree(virUSBDevicePtr dev);
> -void virUSBDeviceSetUsedBy(virUSBDevicePtr dev, const char *name);
> -const char *virUSBDeviceGetUsedBy(virUSBDevicePtr dev);
> +void virUSBDeviceSetUsedBy(virUSBDevicePtr dev, const char *drv_name, const char *dom_name);
> +void virUSBDeviceGetUsedBy(virUSBDevicePtr dev, char **drv_name, char **dom_name);
appropriate change.
Yes, you are right. I didn't change qemu and lxc drivers yet. There might be some opinions about these APIs and need to rework many times before acceptable, so I think it's better to have a consensus on the common library, then change qemu and lxc driver.
> const char *virUSBDeviceGetName(virUSBDevicePtr dev);Best Regards / Pozdrawiam,
>
> unsigned int virUSBDeviceGetBus(virUSBDevicePtr dev);
>
--
Marek Marczykowski
Invisible Things Lab
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list