[libvirt] [PATCH 1/2] add hostdev passthrough common library
Chunyan Liu
cyliu at suse.com
Mon May 27 06:13:03 UTC 2013
2013/5/27 Marek Marczykowski <marmarek at invisiblethingslab.com>
> On 16.05.2013 08:07, Chunyan Liu wrote:
> > 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 at suse.com>
>
> Some comments inline. Besides that seems to be working (with your next
> patch
> 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.)
> > ---
> > 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;
>
> "make check" reports wrong symbol order here.
>
> >
> > # 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 at suse.com>
> > + */
> > +#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;
>
> goto out_of_memory ?
>
> > +
> > + 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";
>
> Really need hardcode driver name here? BTW "xen" driver missing here.
> 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.
> > +
> > + 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")) {
>
> Same as earlier, perhaps the better approach will be checking for current
> stub
> driver here?
>
> > + 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"));
>
> virReportOOMError?
>
> > + 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 at suse.com>
> > + */
> > +
> > +#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);
>
> This change gives qemu and lxc drivers compile fail. So those drivers needs
> 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);
> >
> > unsigned int virUSBDeviceGetBus(virUSBDevicePtr dev);
> >
>
>
> --
> Best Regards / Pozdrawiam,
> Marek Marczykowski
> Invisible Things Lab
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20130527/b5c7152d/attachment-0001.htm>
More information about the libvir-list
mailing list