]> xenbits.xensource.com Git - libvirt.git/commitdiff
virhostdev: move to src/hypervisor
authorJán Tomko <jtomko@redhat.com>
Sat, 22 Feb 2020 16:52:59 +0000 (17:52 +0100)
committerJán Tomko <jtomko@redhat.com>
Mon, 24 Feb 2020 15:47:21 +0000 (16:47 +0100)
This module depends on domain_conf and is used directly by various
hypervisor drivers.

Move it to src/hypervisor.

Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
12 files changed:
build-aux/syntax-check.mk
po/POTFILES.in
src/hypervisor/Makefile.inc.am
src/hypervisor/virhostdev.c [new file with mode: 0644]
src/hypervisor/virhostdev.h [new file with mode: 0644]
src/libvirt_private.syms
src/libxl/Makefile.inc.am
src/security/Makefile.inc.am
src/util/Makefile.inc.am
src/util/virhostdev.c [deleted file]
src/util/virhostdev.h [deleted file]
tests/Makefile.am

index ba1874d347a5d19e9bdd4a45ee70fb1fe7d5681c..7d521c1295f30255f9b8f833e53cadebedf3723d 100644 (file)
@@ -2119,7 +2119,7 @@ exclude_file_name_regexp--sc_prohibit_readdir = \
   ^(tests/(.*mock|virfilewrapper)\.c|tools/nss/libvirt_nss\.c)$$
 
 exclude_file_name_regexp--sc_prohibit_cross_inclusion = \
-  ^(src/util/virclosecallbacks\.h|src/util/virhostdev\.h)$$
+  ^(src/util/virclosecallbacks\.h)$$
 
 exclude_file_name_regexp--sc_prohibit_dirent_d_type = \
   ^(src/util/vircgroup.c)$
index 1675c45206865bc7f56ffc8093f16710e3ceda2c..975de75037a9aecd661c5683e04bf6d69ca0558f 100644 (file)
@@ -80,6 +80,7 @@
 @SRCDIR@/src/hyperv/hyperv_wmi.c
 @SRCDIR@/src/hypervisor/domain_cgroup.c
 @SRCDIR@/src/hypervisor/domain_driver.c
+@SRCDIR@/src/hypervisor/virhostdev.c
 @SRCDIR@/src/interface/interface_backend_netcf.c
 @SRCDIR@/src/interface/interface_backend_udev.c
 @SRCDIR@/src/internal.h
 @SRCDIR@/src/util/virhash.c
 @SRCDIR@/src/util/virhook.c
 @SRCDIR@/src/util/virhostcpu.c
-@SRCDIR@/src/util/virhostdev.c
 @SRCDIR@/src/util/virhostmem.c
 @SRCDIR@/src/util/virhostuptime.c
 @SRCDIR@/src/util/viridentity.c
index 02cf2c7cb1201e83dc51901195ecf17615271726..3bd775a4a59fdb9c5a7a7ca8e10878c29f27b235 100644 (file)
@@ -5,6 +5,8 @@ HYPERVISOR_SOURCES = \
        hypervisor/domain_cgroup.c \
        hypervisor/domain_driver.h \
        hypervisor/domain_driver.c \
+       hypervisor/virhostdev.h \
+       hypervisor/virhostdev.c \
        $(NULL)
 
 noinst_LTLIBRARIES += libvirt_hypervisor.la
diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c
new file mode 100644 (file)
index 0000000..6565ceb
--- /dev/null
@@ -0,0 +1,2523 @@
+/* virhostdev.c: hostdev management
+ *
+ * Copyright (C) 2006-2007, 2009-2017 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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/>.
+ */
+
+#include <config.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "virhostdev.h"
+#include "viralloc.h"
+#include "virstring.h"
+#include "virfile.h"
+#include "virerror.h"
+#include "virlog.h"
+#include "virutil.h"
+#include "virnetdev.h"
+#include "configmake.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+VIR_LOG_INIT("util.hostdev");
+
+#define HOSTDEV_STATE_DIR RUNSTATEDIR "/libvirt/hostdevmgr"
+
+static virHostdevManagerPtr manager; /* global hostdev manager, never freed */
+
+static virClassPtr virHostdevManagerClass;
+static void virHostdevManagerDispose(void *obj);
+static virHostdevManagerPtr virHostdevManagerNew(void);
+
+struct virHostdevIsPCINodeDeviceUsedData {
+    virHostdevManagerPtr mgr;
+    const char *driverName;
+    const char *domainName;
+    bool usesVFIO;
+};
+
+/* This module makes heavy use of bookkeeping lists contained inside a
+ * virHostdevManager instance to keep track of the devices' status. To make
+ * it easy to spot potential ownership errors when moving devices from one
+ * list to the other, variable names should comply with the following
+ * conventions when it comes to virPCIDevice and virPCIDeviceList instances:
+ *
+ *   pci - a short-lived virPCIDevice whose purpose is usually just to look
+ *         up the actual PCI device in one of the bookkeeping lists; basically
+ *         little more than a fancy virPCIDeviceAddress
+ *
+ *   pcidevs - a list containing a bunch of the above
+ *
+ *   actual - a virPCIDevice instance that has either been retrieved from one
+ *            of the bookkeeping lists, or is intended to be added or copied
+ *            to one at some point
+ *
+ * Passing an 'actual' to a function that requires a 'pci' is fine, but the
+ * opposite is usually not true; as a rule of thumb, functions in the virpci
+ * module usually expect an 'actual'. Even with these conventions in place,
+ * adding comments to highlight ownership-related issues is recommended */
+
+static int virHostdevIsPCINodeDeviceUsed(virPCIDeviceAddressPtr devAddr, void *opaque)
+{
+    virPCIDevicePtr actual;
+    struct virHostdevIsPCINodeDeviceUsedData *helperData = opaque;
+
+    actual = virPCIDeviceListFindByIDs(helperData->mgr->activePCIHostdevs,
+                                       devAddr->domain, devAddr->bus,
+                                       devAddr->slot, devAddr->function);
+    if (actual) {
+        const char *actual_drvname = NULL;
+        const char *actual_domname = NULL;
+        virPCIDeviceGetUsedBy(actual, &actual_drvname, &actual_domname);
+
+        if (helperData->usesVFIO &&
+            STREQ_NULLABLE(actual_drvname, helperData->driverName) &&
+            STREQ_NULLABLE(actual_domname, helperData->domainName))
+            goto iommu_owner;
+
+        if (actual_drvname && actual_domname)
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("PCI device %s is in use by "
+                             "driver %s, domain %s"),
+                           virPCIDeviceGetName(actual),
+                           actual_drvname, actual_domname);
+        else
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("PCI device %s is in use"),
+                           virPCIDeviceGetName(actual));
+        return -1;
+    }
+ iommu_owner:
+    return 0;
+}
+
+static int virHostdevManagerOnceInit(void)
+{
+    if (!VIR_CLASS_NEW(virHostdevManager, virClassForObject()))
+        return -1;
+
+    if (!(manager = virHostdevManagerNew()))
+        return -1;
+
+    return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virHostdevManager);
+
+static void
+virHostdevManagerDispose(void *obj)
+{
+    virHostdevManagerPtr hostdevMgr = obj;
+
+    virObjectUnref(hostdevMgr->activePCIHostdevs);
+    virObjectUnref(hostdevMgr->inactivePCIHostdevs);
+    virObjectUnref(hostdevMgr->activeUSBHostdevs);
+    virObjectUnref(hostdevMgr->activeSCSIHostdevs);
+    virObjectUnref(hostdevMgr->activeSCSIVHostHostdevs);
+    virObjectUnref(hostdevMgr->activeMediatedHostdevs);
+    virObjectUnref(hostdevMgr->activeNVMeHostdevs);
+    VIR_FREE(hostdevMgr->stateDir);
+}
+
+static virHostdevManagerPtr
+virHostdevManagerNew(void)
+{
+    g_autoptr(virHostdevManager) hostdevMgr = NULL;
+    bool privileged = geteuid() == 0;
+
+    if (!(hostdevMgr = virObjectNew(virHostdevManagerClass)))
+        return NULL;
+
+    if (!(hostdevMgr->activePCIHostdevs = virPCIDeviceListNew()))
+        return NULL;
+
+    if (!(hostdevMgr->activeUSBHostdevs = virUSBDeviceListNew()))
+        return NULL;
+
+    if (!(hostdevMgr->inactivePCIHostdevs = virPCIDeviceListNew()))
+        return NULL;
+
+    if (!(hostdevMgr->activeSCSIHostdevs = virSCSIDeviceListNew()))
+        return NULL;
+
+    if (!(hostdevMgr->activeSCSIVHostHostdevs = virSCSIVHostDeviceListNew()))
+        return NULL;
+
+    if (!(hostdevMgr->activeMediatedHostdevs = virMediatedDeviceListNew()))
+        return NULL;
+
+    if (!(hostdevMgr->activeNVMeHostdevs = virNVMeDeviceListNew()))
+        return NULL;
+
+    if (privileged) {
+        hostdevMgr->stateDir = g_strdup(HOSTDEV_STATE_DIR);
+
+        if (virFileMakePath(hostdevMgr->stateDir) < 0) {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("Failed to create state dir '%s'"),
+                           hostdevMgr->stateDir);
+            return NULL;
+        }
+    } else {
+        g_autofree char *rundir = NULL;
+        mode_t old_umask;
+
+        rundir = virGetUserRuntimeDirectory();
+
+        hostdevMgr->stateDir = g_strdup_printf("%s/hostdevmgr", rundir);
+
+        old_umask = umask(077);
+
+        if (virFileMakePath(hostdevMgr->stateDir) < 0) {
+            umask(old_umask);
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("Failed to create state dir '%s'"),
+                           hostdevMgr->stateDir);
+            return NULL;
+        }
+        umask(old_umask);
+    }
+
+    return g_steal_pointer(&hostdevMgr);
+}
+
+virHostdevManagerPtr
+virHostdevManagerGetDefault(void)
+{
+    if (virHostdevManagerInitialize() < 0)
+        return NULL;
+
+    return virObjectRef(manager);
+}
+
+/**
+ * virHostdevGetPCIHostDevice:
+ * @hostdev: domain hostdev definition
+ * @pci: returned PCI device
+ *
+ * For given @hostdev which represents a PCI device construct its
+ * virPCIDevice representation and return it in @pci. If @hostdev
+ * does not represent a PCI device then @pci is set to NULL and 0
+ * is returned.
+ *
+ * Returns: 0 on success (@pci might be NULL though),
+ *         -1 otherwise (with error reported).
+ */
+static int
+virHostdevGetPCIHostDevice(const virDomainHostdevDef *hostdev,
+                           virPCIDevicePtr *pci)
+{
+    g_autoptr(virPCIDevice) actual = NULL;
+    const virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci;
+
+    *pci = NULL;
+
+    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+        hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+        return 0;
+
+    actual = virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
+                             pcisrc->addr.slot, pcisrc->addr.function);
+
+    if (!actual)
+        return -1;
+
+    virPCIDeviceSetManaged(actual, hostdev->managed);
+
+    if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
+        virPCIDeviceSetStubDriver(actual, VIR_PCI_STUB_DRIVER_VFIO);
+    } else if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN) {
+        virPCIDeviceSetStubDriver(actual, VIR_PCI_STUB_DRIVER_XEN);
+    } else {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("pci backend driver '%s' is not supported"),
+                       virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend));
+        return -1;
+    }
+
+    *pci = g_steal_pointer(&actual);
+    return 0;
+}
+
+static virPCIDeviceListPtr
+virHostdevGetPCIHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
+{
+    g_autoptr(virPCIDeviceList) pcidevs = NULL;
+    size_t i;
+
+    if (!(pcidevs = virPCIDeviceListNew()))
+        return NULL;
+
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        g_autoptr(virPCIDevice) pci = NULL;
+
+        if (virHostdevGetPCIHostDevice(hostdev, &pci) < 0)
+            return NULL;
+
+        if (!pci)
+            continue;
+
+        if (virPCIDeviceListAdd(pcidevs, pci) < 0)
+            return NULL;
+        pci = NULL;
+    }
+
+    return g_steal_pointer(&pcidevs);
+}
+
+static int
+virHostdevPCISysfsPath(virDomainHostdevDefPtr hostdev,
+                       char **sysfs_path)
+{
+    virPCIDeviceAddress config_address;
+
+    config_address.domain = hostdev->source.subsys.u.pci.addr.domain;
+    config_address.bus = hostdev->source.subsys.u.pci.addr.bus;
+    config_address.slot = hostdev->source.subsys.u.pci.addr.slot;
+    config_address.function = hostdev->source.subsys.u.pci.addr.function;
+
+    return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
+}
+
+
+static int
+virHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
+{
+    g_autofree char *sysfs_path = NULL;
+
+    if (virHostdevPCISysfsPath(hostdev, &sysfs_path) < 0)
+        return -1;
+
+    return virPCIIsVirtualFunction(sysfs_path);
+}
+
+
+static int
+virHostdevNetDevice(virDomainHostdevDefPtr hostdev,
+                    int pfNetDevIdx,
+                    char **linkdev,
+                    int *vf)
+{
+    g_autofree char *sysfs_path = NULL;
+
+    if (virHostdevPCISysfsPath(hostdev, &sysfs_path) < 0)
+        return -1;
+
+    if (virPCIIsVirtualFunction(sysfs_path) == 1) {
+        if (virPCIGetVirtualFunctionInfo(sysfs_path, pfNetDevIdx,
+                                         linkdev, vf) < 0)
+            return -1;
+    } else {
+        /* In practice this should never happen, since we currently
+         * only support assigning SRIOV VFs via <interface
+         * type='hostdev'>, and it is only those devices that should
+         * end up calling this function.
+         */
+        if (virPCIGetNetName(sysfs_path, 0, NULL, linkdev) < 0)
+            return -1;
+
+        if (!(*linkdev)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("The device at %s has no network device name"),
+                           sysfs_path);
+            return -1;
+        }
+
+        *vf = -1;
+    }
+
+    return 0;
+}
+
+
+static bool
+virHostdevIsPCINetDevice(const virDomainHostdevDef *hostdev)
+{
+    return hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+        hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
+        hostdev->parentnet != NULL;
+}
+
+
+static int
+virHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
+                                   const virNetDevVPortProfile *virtPort,
+                                   const virMacAddr *macaddr,
+                                   const unsigned char *uuid,
+                                   bool associate)
+{
+    int ret = -1;
+
+    if (!virtPort)
+        return ret;
+
+    switch (virtPort->virtPortType) {
+    case VIR_NETDEV_VPORT_PROFILE_NONE:
+    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
+    case VIR_NETDEV_VPORT_PROFILE_8021QBG:
+    case VIR_NETDEV_VPORT_PROFILE_LAST:
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("virtualport type %s is "
+                         "currently not supported on interfaces of type "
+                         "hostdev"),
+                       virNetDevVPortTypeToString(virtPort->virtPortType));
+        break;
+
+    case VIR_NETDEV_VPORT_PROFILE_8021QBH:
+        if (associate)
+            ret = virNetDevVPortProfileAssociate(NULL, virtPort, macaddr,
+                                                 linkdev, vf, uuid,
+                                                 VIR_NETDEV_VPORT_PROFILE_OP_CREATE, false);
+        else
+            ret = virNetDevVPortProfileDisassociate(NULL, virtPort,
+                                                    macaddr, linkdev, vf,
+                                                    VIR_NETDEV_VPORT_PROFILE_OP_DESTROY);
+        break;
+    }
+
+    return ret;
+}
+
+
+/**
+ * virHostdevSaveNetConfig:
+ * @hostdev: config object describing a hostdev device
+ * @stateDir: directory to save device state into
+ *
+ * If the given hostdev device is an SRIOV network VF and *does not*
+ * have a <virtualport> element (ie, it isn't being configured via
+ * 802.11Qbh), determine its PF+VF#, and use that to save its current
+ * "admin" MAC address and VF tag (the ones saved in the PF
+ * driver).
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+virHostdevSaveNetConfig(virDomainHostdevDefPtr hostdev,
+                        const char *stateDir)
+{
+    g_autofree char *linkdev = NULL;
+    int vf = -1;
+
+    if (!virHostdevIsPCINetDevice(hostdev) ||
+        virDomainNetGetActualVirtPortProfile(hostdev->parentnet))
+       return 0;
+
+    if (virHostdevIsVirtualFunction(hostdev) != 1) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Interface type hostdev is currently supported on"
+                         " SR-IOV Virtual Functions only"));
+        return -1;
+    }
+
+    if (virHostdevNetDevice(hostdev, -1, &linkdev, &vf) < 0)
+        return -1;
+
+    if (virNetDevSaveNetConfig(linkdev, vf, stateDir, true) < 0)
+        return -1;
+
+    return 0;
+}
+
+
+/**
+ * virHostdevSetNetConfig:
+ * @hostdev: config object describing a hostdev device
+ * @uuid: uuid of the domain
+ *
+ * If the given hostdev device is an SRIOV network VF, determine its
+ * PF+VF#, and use that to set the "admin" MAC address and VF tag (the
+ * ones saved in the PF driver).xs
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int
+virHostdevSetNetConfig(virDomainHostdevDefPtr hostdev,
+                       const unsigned char *uuid)
+{
+    g_autofree char *linkdev = NULL;
+    const virNetDevVlan *vlan;
+    const virNetDevVPortProfile *virtPort;
+    int vf = -1;
+    bool port_profile_associate = true;
+
+    if (!virHostdevIsPCINetDevice(hostdev))
+        return 0;
+
+    if (virHostdevNetDevice(hostdev, -1, &linkdev, &vf) < 0)
+        return -1;
+
+    vlan = virDomainNetGetActualVlan(hostdev->parentnet);
+    virtPort = virDomainNetGetActualVirtPortProfile(hostdev->parentnet);
+    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));
+            return -1;
+        }
+        if (virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
+                                               &hostdev->parentnet->mac,
+                                               uuid, port_profile_associate) < 0)
+            return -1;
+    } else {
+        if (virNetDevSetNetConfig(linkdev, vf, &hostdev->parentnet->mac,
+                                  vlan, NULL, true) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
+/* @oldStateDir:
+ * For upgrade purpose:
+ * To an existing VM on QEMU, the hostdev netconfig file is originally stored
+ * in cfg->stateDir (/var/run/libvirt/qemu). Switch to new version, it uses new
+ * location (mgr->stateDir) but certainly will not find it. In this
+ * case, try to find in the old state dir.
+ */
+static int
+virHostdevRestoreNetConfig(virDomainHostdevDefPtr hostdev,
+                           const char *stateDir,
+                           const char *oldStateDir)
+{
+    g_autofree char *linkdev = NULL;
+    g_autofree virMacAddrPtr MAC = NULL;
+    g_autofree virMacAddrPtr adminMAC = NULL;
+    g_autoptr(virNetDevVlan) vlan = NULL;
+    const virNetDevVPortProfile *virtPort;
+    int vf = -1;
+    bool port_profile_associate = false;
+
+
+    /* This is only needed for PCI devices that have been defined
+     * using <interface type='hostdev'>. For all others, it is a NOP.
+     */
+    if (!virHostdevIsPCINetDevice(hostdev))
+       return 0;
+
+    if (virHostdevIsVirtualFunction(hostdev) != 1) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("Interface type hostdev is currently supported on"
+                         " SR-IOV Virtual Functions only"));
+        return -1;
+    }
+
+    if (virHostdevNetDevice(hostdev, 0, &linkdev, &vf) < 0)
+        return -1;
+
+    virtPort = virDomainNetGetActualVirtPortProfile(hostdev->parentnet);
+    if (virtPort) {
+        return virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
+                                                  &hostdev->parentnet->mac,
+                                                  NULL,
+                                                  port_profile_associate);
+    } else {
+        /* we need to try 3 different places for the config file:
+         * 1) ${stateDir}/${PF}_vf${vf}
+         *    This is almost always where the saved config is
+         *
+         * 2) ${oldStateDir/${PF}_vf${vf}
+         *    saved config is only here if this machine was running a
+         *    (by now *very*) old version of libvirt that saved the
+         *    file in a different directory
+         *
+         * 3) ${stateDir}${PF[1]}_vf${VF}
+         *    PF[1] means "the netdev for port 2 of the PF device", and
+         *    is only valid when the PF is a Mellanox dual port NIC with
+         *    a VF that was created in "single port" mode.
+         *
+         *  NB: if virNetDevReadNetConfig() returns < 0, then it found
+         *  the file, but there was a problem, so we should
+         *  immediately return an error to our caller. If it returns
+         *  0, but all of the interesting stuff is NULL, that means
+         *  the file wasn't found, so we can/should check other
+         *  locations for it.
+         */
+
+        /* 1) standard location */
+        if (virNetDevReadNetConfig(linkdev, vf, stateDir,
+                                   &adminMAC, &vlan, &MAC) < 0) {
+            return -1;
+        }
+
+        /* 2) "old" (pre-1.2.3 circa 2014) location - whenever we get
+        *  to the point that nobody will ever upgrade directly from
+        *  1.2.3 (or older) directly to current libvirt, we can
+        *  eliminate this clause
+        **/
+        if (!(adminMAC || vlan || MAC) && oldStateDir &&
+            virNetDevReadNetConfig(linkdev, vf, oldStateDir,
+                                   &adminMAC, &vlan, &MAC) < 0) {
+            return -1;
+        }
+
+        /* 3) try using the PF's "port 2" netdev as the name of the
+         * config file
+         */
+        if (!(adminMAC || vlan || MAC)) {
+            VIR_FREE(linkdev);
+
+            if (virHostdevNetDevice(hostdev, 1, &linkdev, &vf) < 0 ||
+                virNetDevReadNetConfig(linkdev, vf, stateDir,
+                                       &adminMAC, &vlan, &MAC) < 0) {
+                return -1;
+            }
+        }
+
+        /* if a MAC was stored for the VF, we should now restore
+         * that as the adminMAC. We have to do it this way because
+         * the VF is still not bound to the host's net driver, so
+         * we can't directly set its MAC (and even after it is
+         * re-bound to the host net driver, it will still have its
+         * "administratively set" flag on, and that prohibits the
+         * VF's net driver from directly setting the MAC
+         * anyway). But it we set the desired VF MAC as the "admin
+         * MAC" *now*, then when the VF is re-bound to the host
+         * net driver (which will happen soon after returning from
+         * this function), that adminMAC will be set (by the PF)
+         * as the VF's new initial MAC.
+         *
+         * If no MAC was stored for the VF, that means it wasn't
+         * bound to a net driver before we used it anyway, so the
+         * adminMAC is all we have, and we can just restore it
+         * directly.
+         */
+        if (MAC) {
+            VIR_FREE(adminMAC);
+            adminMAC = MAC;
+            MAC = NULL;
+        }
+
+        ignore_value(virNetDevSetNetConfig(linkdev, vf,
+                                           adminMAC, vlan, MAC, true));
+        return 0;
+    }
+}
+
+static int
+virHostdevResetAllPCIDevices(virHostdevManagerPtr mgr,
+                             virPCIDeviceListPtr pcidevs)
+{
+    int ret = 0;
+    size_t i;
+
+    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
+
+        /* We can avoid looking up the actual device here, because performing
+         * a PCI reset on a device doesn't require any information other than
+         * the address, which 'pci' already contains */
+        VIR_DEBUG("Resetting PCI device %s", virPCIDeviceGetName(pci));
+        if (virPCIDeviceReset(pci, mgr->activePCIHostdevs,
+                              mgr->inactivePCIHostdevs) < 0) {
+            VIR_ERROR(_("Failed to reset PCI device: %s"),
+                      virGetLastErrorMessage());
+            ret = -1;
+        }
+    }
+
+    return ret;
+}
+
+static void
+virHostdevReattachAllPCIDevices(virHostdevManagerPtr mgr,
+                                virPCIDeviceListPtr pcidevs)
+{
+    size_t i;
+
+    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
+        virPCIDevicePtr actual;
+
+        /* We need to look up the actual device because that's what
+         * virPCIDeviceReattach() expects as its argument */
+        if (!(actual = virPCIDeviceListFind(mgr->inactivePCIHostdevs, pci)))
+            continue;
+
+        if (virPCIDeviceGetManaged(actual)) {
+            VIR_DEBUG("Reattaching managed PCI device %s",
+                      virPCIDeviceGetName(pci));
+            if (virPCIDeviceReattach(actual,
+                                     mgr->activePCIHostdevs,
+                                     mgr->inactivePCIHostdevs) < 0) {
+                VIR_ERROR(_("Failed to re-attach PCI device: %s"),
+                          virGetLastErrorMessage());
+            }
+        } else {
+            VIR_DEBUG("Not reattaching unmanaged PCI device %s",
+                      virPCIDeviceGetName(actual));
+        }
+    }
+}
+
+
+static int
+virHostdevPreparePCIDevicesImpl(virHostdevManagerPtr mgr,
+                                const char *drv_name,
+                                const char *dom_name,
+                                const unsigned char *uuid,
+                                virPCIDeviceListPtr pcidevs,
+                                virDomainHostdevDefPtr *hostdevs,
+                                int nhostdevs,
+                                unsigned int flags)
+{
+    int last_processed_hostdev_vf = -1;
+    size_t i;
+    int ret = -1;
+    virPCIDeviceAddressPtr devAddr = NULL;
+
+    virObjectLock(mgr->activePCIHostdevs);
+    virObjectLock(mgr->inactivePCIHostdevs);
+
+    /* Detaching devices from the host involves several steps; each
+     * of them is described at length below.
+     *
+     * 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 */
+
+    /* Step 1: Perform some initial checks on the devices */
+    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
+        bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
+        bool usesVFIO = (virPCIDeviceGetStubDriver(pci) == VIR_PCI_STUB_DRIVER_VFIO);
+        struct virHostdevIsPCINodeDeviceUsedData data = {mgr, drv_name, dom_name, false};
+        int hdrType = -1;
+
+        if (virPCIGetHeaderType(pci, &hdrType) < 0)
+            goto cleanup;
+
+        if (hdrType != VIR_PCI_HEADER_ENDPOINT) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Non-endpoint PCI devices cannot be assigned "
+                             "to guests"));
+            goto cleanup;
+        }
+
+        if (!usesVFIO && !virPCIDeviceIsAssignable(pci, strict_acs_check)) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("PCI device %s is not assignable"),
+                           virPCIDeviceGetName(pci));
+            goto cleanup;
+        }
+
+        /* The device is in use by other active domain if
+         * the dev is in list activePCIHostdevs. */
+        devAddr = virPCIDeviceGetAddress(pci);
+        if (virHostdevIsPCINodeDeviceUsed(devAddr, &data))
+            goto cleanup;
+
+        /* VFIO devices belonging to same IOMMU group can't be
+         * shared across guests. Check if that's the case. */
+        if (usesVFIO) {
+            data.usesVFIO = true;
+            if (virPCIDeviceAddressIOMMUGroupIterate(devAddr,
+                                                     virHostdevIsPCINodeDeviceUsed,
+                                                     &data) < 0)
+                goto cleanup;
+        }
+    }
+
+    /* Step 1.5: For non-802.11Qbh SRIOV network devices, save the
+     * current device config
+     */
+    for (i = 0; i < nhostdevs; i++) {
+        if (virHostdevSaveNetConfig(hostdevs[i], mgr->stateDir) < 0)
+            goto cleanup;
+    }
+
+    /* Step 2: detach managed devices and make sure unmanaged devices
+     *         have already been taken care of */
+    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
+
+        if (virPCIDeviceGetManaged(pci)) {
+
+            /* We can't look up the actual device because it has not been
+             * created yet: virPCIDeviceDetach() will insert a copy of 'pci'
+             * into the list of inactive devices, and that copy will be the
+             * actual device going forward */
+            VIR_DEBUG("Detaching managed PCI device %s",
+                      virPCIDeviceGetName(pci));
+            if (virPCIDeviceDetach(pci,
+                                   mgr->activePCIHostdevs,
+                                   mgr->inactivePCIHostdevs) < 0)
+                goto reattachdevs;
+        } else {
+            g_autofree char *driverPath = NULL;
+            g_autofree char *driverName = NULL;
+            int stub;
+
+            /* Unmanaged devices should already have been marked as
+             * inactive: if that's the case, we can simply move on */
+            if (virPCIDeviceListFind(mgr->inactivePCIHostdevs, pci)) {
+                VIR_DEBUG("Not detaching unmanaged PCI device %s",
+                          virPCIDeviceGetName(pci));
+                continue;
+            }
+
+            /* If that's not the case, though, it might be because the
+             * daemon has been restarted, causing us to lose track of the
+             * device. Try and recover by marking the device as inactive
+             * if it happens to be bound to a known stub driver.
+             *
+             * FIXME Get rid of this once a proper way to keep track of
+             *       information about active / inactive device across
+             *       daemon restarts has been implemented */
+
+            if (virPCIDeviceGetDriverPathAndName(pci,
+                                                 &driverPath, &driverName) < 0)
+                goto reattachdevs;
+
+            stub = virPCIStubDriverTypeFromString(driverName);
+
+            if (stub > VIR_PCI_STUB_DRIVER_NONE &&
+                stub < VIR_PCI_STUB_DRIVER_LAST) {
+
+                /* The device is bound to a known stub driver: store this
+                 * information and add a copy to the inactive list */
+                virPCIDeviceSetStubDriver(pci, stub);
+
+                VIR_DEBUG("Adding PCI device %s to inactive list",
+                          virPCIDeviceGetName(pci));
+                if (virPCIDeviceListAddCopy(mgr->inactivePCIHostdevs, pci) < 0)
+                    goto reattachdevs;
+            } else {
+                virReportError(VIR_ERR_OPERATION_INVALID,
+                               _("Unmanaged PCI device %s must be manually "
+                                 "detached from the host"),
+                               virPCIDeviceGetName(pci));
+                goto reattachdevs;
+            }
+        }
+    }
+
+    /* At this point, all devices are attached to the stub driver and have
+     * been marked as inactive */
+
+    /* Step 3: Now that all the PCI hostdevs have been detached, we
+     * can safely reset them */
+    if (virHostdevResetAllPCIDevices(mgr, pcidevs) < 0)
+        goto reattachdevs;
+
+    /* Step 4: For SRIOV network devices, Now that we have detached the
+     * the network device, set the new netdev config */
+    for (i = 0; i < nhostdevs; i++) {
+
+        if (virHostdevSetNetConfig(hostdevs[i], uuid) < 0)
+            goto resetvfnetconfig;
+
+        last_processed_hostdev_vf = i;
+    }
+
+    /* Step 5: Move devices from the inactive list to the active list */
+    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
+        virPCIDevicePtr actual;
+
+        VIR_DEBUG("Removing PCI device %s from inactive list",
+                  virPCIDeviceGetName(pci));
+        actual = virPCIDeviceListSteal(mgr->inactivePCIHostdevs, pci);
+
+        VIR_DEBUG("Adding PCI device %s to active list",
+                  virPCIDeviceGetName(pci));
+        if (!actual || virPCIDeviceListAdd(mgr->activePCIHostdevs, actual) < 0)
+            goto inactivedevs;
+    }
+
+    /* Step 6: Set driver and domain information */
+    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+        virPCIDevicePtr pci, actual;
+
+        /* We need to look up the actual device and set the information
+         * there because 'pci' only contain address information and will
+         * be released at the end of the function */
+        pci = virPCIDeviceListGet(pcidevs, i);
+        actual = virPCIDeviceListFind(mgr->activePCIHostdevs, pci);
+
+        VIR_DEBUG("Setting driver and domain information for PCI device %s",
+                  virPCIDeviceGetName(pci));
+        if (actual)
+            virPCIDeviceSetUsedBy(actual, drv_name, dom_name);
+    }
+
+    /* Step 7: Now set the original states for hostdev def */
+    for (i = 0; i < nhostdevs; i++) {
+        virPCIDevicePtr actual;
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+            continue;
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+            continue;
+
+        /* We need to look up the actual device because it's the one
+         * that contains the information we care about (unbind_from_stub,
+         * remove_slot, reprobe) */
+        actual = virPCIDeviceListFindByIDs(mgr->activePCIHostdevs,
+                                           pcisrc->addr.domain,
+                                           pcisrc->addr.bus,
+                                           pcisrc->addr.slot,
+                                           pcisrc->addr.function);
+
+        /* Appropriate values for the unbind_from_stub, remove_slot
+         * and reprobe properties of the device were set earlier
+         * by virPCIDeviceDetach() */
+        if (actual) {
+            VIR_DEBUG("Saving network configuration of PCI device %s",
+                      virPCIDeviceGetName(actual));
+            hostdev->origstates.states.pci.unbind_from_stub =
+                virPCIDeviceGetUnbindFromStub(actual);
+            hostdev->origstates.states.pci.remove_slot =
+                virPCIDeviceGetRemoveSlot(actual);
+            hostdev->origstates.states.pci.reprobe =
+                virPCIDeviceGetReprobe(actual);
+        }
+    }
+
+    ret = 0;
+    goto cleanup;
+
+ inactivedevs:
+    /* Move devices back to the inactive list so that they can be
+     * processed properly below (reattachdevs label) */
+    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
+        virPCIDevicePtr actual;
+
+        VIR_DEBUG("Removing PCI device %s from active list",
+                  virPCIDeviceGetName(pci));
+        if (!(actual = virPCIDeviceListSteal(mgr->activePCIHostdevs, pci)))
+            continue;
+
+        VIR_DEBUG("Adding PCI device %s to inactive list",
+                  virPCIDeviceGetName(pci));
+        if (virPCIDeviceListAdd(mgr->inactivePCIHostdevs, actual) < 0)
+            VIR_WARN("Failed to add PCI device %s to the inactive list",
+                     virPCIDeviceGetName(pci));
+    }
+
+ resetvfnetconfig:
+    if (last_processed_hostdev_vf >= 0) {
+        for (i = 0; i <= last_processed_hostdev_vf; i++)
+            virHostdevRestoreNetConfig(hostdevs[i], mgr->stateDir, NULL);
+    }
+
+ reattachdevs:
+    virHostdevReattachAllPCIDevices(mgr, pcidevs);
+
+ cleanup:
+    virObjectUnlock(mgr->activePCIHostdevs);
+    virObjectUnlock(mgr->inactivePCIHostdevs);
+
+    return ret;
+}
+
+
+int
+virHostdevPreparePCIDevices(virHostdevManagerPtr mgr,
+                            const char *drv_name,
+                            const char *dom_name,
+                            const unsigned char *uuid,
+                            virDomainHostdevDefPtr *hostdevs,
+                            int nhostdevs,
+                            unsigned int flags)
+{
+    g_autoptr(virPCIDeviceList) pcidevs = NULL;
+
+    if (!nhostdevs)
+        return 0;
+
+    if (!(pcidevs = virHostdevGetPCIHostDeviceList(hostdevs, nhostdevs)))
+        return -1;
+
+    return virHostdevPreparePCIDevicesImpl(mgr, drv_name, dom_name, uuid,
+                                           pcidevs, hostdevs, nhostdevs, flags);
+}
+
+
+static void
+virHostdevReAttachPCIDevicesImpl(virHostdevManagerPtr mgr,
+                                 const char *drv_name,
+                                 const char *dom_name,
+                                 virPCIDeviceListPtr pcidevs,
+                                 virDomainHostdevDefPtr *hostdevs,
+                                 int nhostdevs,
+                                 const char *oldStateDir)
+{
+    size_t i;
+
+    virObjectLock(mgr->activePCIHostdevs);
+    virObjectLock(mgr->inactivePCIHostdevs);
+
+    /* Reattaching devices to the host involves several steps; each
+     * of them is described at length below */
+
+    /* Step 1: Filter out all devices that are either not active or not
+     *         used by the current domain and driver */
+    i = 0;
+    while (i < virPCIDeviceListCount(pcidevs)) {
+        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
+        virPCIDevicePtr actual = NULL;
+
+        /* We need to look up the actual device, which is the one containing
+         * information such as by which domain and driver it is used. As a
+         * side effect, by looking it up we can also tell whether it was
+         * really active in the first place */
+        actual = virPCIDeviceListFind(mgr->activePCIHostdevs, pci);
+        if (actual) {
+            const char *actual_drvname;
+            const char *actual_domname;
+            virPCIDeviceGetUsedBy(actual, &actual_drvname, &actual_domname);
+            if (STRNEQ_NULLABLE(drv_name, actual_drvname) ||
+                STRNEQ_NULLABLE(dom_name, actual_domname)) {
+
+                virPCIDeviceListDel(pcidevs, pci);
+                continue;
+            }
+        } else {
+            virPCIDeviceListDel(pcidevs, pci);
+            continue;
+        }
+
+        i++;
+    }
+
+    /* Step 2: Move devices from the active list to the inactive list */
+    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
+        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
+        virPCIDevicePtr actual;
+
+        VIR_DEBUG("Removing PCI device %s from active list",
+                  virPCIDeviceGetName(pci));
+        actual = virPCIDeviceListSteal(mgr->activePCIHostdevs, pci);
+
+        VIR_DEBUG("Adding PCI device %s to inactive list",
+                  virPCIDeviceGetName(pci));
+        if (!actual ||
+            virPCIDeviceListAdd(mgr->inactivePCIHostdevs, actual) < 0) {
+
+            VIR_ERROR(_("Failed to add PCI device %s to the inactive list"),
+                      virGetLastErrorMessage());
+            virResetLastError();
+        }
+    }
+
+    /* At this point, any device that had been used by the guest has been
+     * moved to the inactive list */
+
+    /* Step 3: restore original network config of hostdevs that used
+     * <interface type='hostdev'>
+     */
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+
+        if (virHostdevIsPCINetDevice(hostdev)) {
+            virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
+            virPCIDevicePtr actual;
+
+            actual = virPCIDeviceListFindByIDs(mgr->inactivePCIHostdevs,
+                                               pcisrc->addr.domain,
+                                               pcisrc->addr.bus,
+                                               pcisrc->addr.slot,
+                                               pcisrc->addr.function);
+
+            if (actual) {
+                VIR_DEBUG("Restoring network configuration of PCI device %s",
+                          virPCIDeviceGetName(actual));
+                virHostdevRestoreNetConfig(hostdev, mgr->stateDir,
+                                           oldStateDir);
+            }
+        }
+    }
+
+    /* Step 4: perform a PCI Reset on all devices */
+    virHostdevResetAllPCIDevices(mgr, pcidevs);
+
+    /* Step 5: Reattach managed devices to their host drivers; unmanaged
+     *         devices don't need to be processed further */
+    virHostdevReattachAllPCIDevices(mgr, pcidevs);
+
+    virObjectUnlock(mgr->activePCIHostdevs);
+    virObjectUnlock(mgr->inactivePCIHostdevs);
+}
+
+
+/* @oldStateDir:
+ * For upgrade purpose: see virHostdevRestoreNetConfig
+ */
+void
+virHostdevReAttachPCIDevices(virHostdevManagerPtr mgr,
+                             const char *drv_name,
+                             const char *dom_name,
+                             virDomainHostdevDefPtr *hostdevs,
+                             int nhostdevs,
+                             const char *oldStateDir)
+{
+    g_autoptr(virPCIDeviceList) pcidevs = NULL;
+
+    if (!nhostdevs)
+        return;
+
+    if (!(pcidevs = virHostdevGetPCIHostDeviceList(hostdevs, nhostdevs))) {
+        VIR_ERROR(_("Failed to allocate PCI device list: %s"),
+                  virGetLastErrorMessage());
+        virResetLastError();
+        return;
+    }
+
+    virHostdevReAttachPCIDevicesImpl(mgr, drv_name, dom_name, pcidevs,
+                                     hostdevs, nhostdevs, oldStateDir);
+}
+
+
+int
+virHostdevUpdateActivePCIDevices(virHostdevManagerPtr mgr,
+                                 virDomainHostdevDefPtr *hostdevs,
+                                 int nhostdevs,
+                                 const char *drv_name,
+                                 const char *dom_name)
+{
+    size_t i;
+    int ret = -1;
+
+    if (!nhostdevs)
+        return 0;
+
+    virObjectLock(mgr->activePCIHostdevs);
+    virObjectLock(mgr->inactivePCIHostdevs);
+
+    for (i = 0; i < nhostdevs; i++) {
+        const virDomainHostdevDef *hostdev = hostdevs[i];
+        g_autoptr(virPCIDevice) actual = NULL;
+
+        if (virHostdevGetPCIHostDevice(hostdev, &actual) < 0)
+            goto cleanup;
+
+        if (!actual)
+            continue;
+
+        if (virPCIDeviceSetUsedBy(actual, drv_name, dom_name) < 0)
+            goto cleanup;
+
+        /* Setup the original states for the PCI device */
+        virPCIDeviceSetUnbindFromStub(actual, hostdev->origstates.states.pci.unbind_from_stub);
+        virPCIDeviceSetRemoveSlot(actual, hostdev->origstates.states.pci.remove_slot);
+        virPCIDeviceSetReprobe(actual, hostdev->origstates.states.pci.reprobe);
+
+        if (virPCIDeviceListAdd(mgr->activePCIHostdevs, actual) < 0)
+            goto cleanup;
+        actual = NULL;
+    }
+
+    ret = 0;
+ cleanup:
+    virObjectUnlock(mgr->activePCIHostdevs);
+    virObjectUnlock(mgr->inactivePCIHostdevs);
+    return ret;
+}
+
+int
+virHostdevUpdateActiveUSBDevices(virHostdevManagerPtr mgr,
+                                 virDomainHostdevDefPtr *hostdevs,
+                                 int nhostdevs,
+                                 const char *drv_name,
+                                 const char *dom_name)
+{
+    virDomainHostdevDefPtr hostdev = NULL;
+    size_t i;
+    int ret = -1;
+
+    if (!nhostdevs)
+        return 0;
+
+    virObjectLock(mgr->activeUSBHostdevs);
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevSubsysUSBPtr usbsrc;
+        g_autoptr(virUSBDevice) usb = NULL;
+        hostdev = hostdevs[i];
+        usbsrc = &hostdev->source.subsys.u.usb;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+            continue;
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
+            continue;
+
+        if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL))) {
+            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
+                     usbsrc->bus, usbsrc->device, dom_name);
+            continue;
+        }
+
+        virUSBDeviceSetUsedBy(usb, drv_name, dom_name);
+
+        if (virUSBDeviceListAdd(mgr->activeUSBHostdevs, &usb) < 0)
+            goto cleanup;
+        usb = NULL;
+    }
+    ret = 0;
+ cleanup:
+    virObjectUnlock(mgr->activeUSBHostdevs);
+    return ret;
+}
+
+static int
+virHostdevUpdateActiveSCSIHostDevices(virHostdevManagerPtr mgr,
+                                      virDomainHostdevDefPtr hostdev,
+                                      virDomainHostdevSubsysSCSIPtr scsisrc,
+                                      const char *drv_name,
+                                      const char *dom_name)
+{
+    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
+    g_autoptr(virSCSIDevice) scsi = NULL;
+    virSCSIDevicePtr tmp = NULL;
+
+    if (!(scsi = virSCSIDeviceNew(NULL,
+                                  scsihostsrc->adapter, scsihostsrc->bus,
+                                  scsihostsrc->target, scsihostsrc->unit,
+                                  hostdev->readonly, hostdev->shareable)))
+        return -1;
+
+    if ((tmp = virSCSIDeviceListFind(mgr->activeSCSIHostdevs, scsi))) {
+        if (virSCSIDeviceSetUsedBy(tmp, drv_name, dom_name) < 0)
+            return -1;
+    } else {
+        if (virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name) < 0 ||
+            virSCSIDeviceListAdd(mgr->activeSCSIHostdevs, scsi) < 0)
+            return -1;
+        scsi = NULL;
+    }
+    return 0;
+}
+
+int
+virHostdevUpdateActiveSCSIDevices(virHostdevManagerPtr mgr,
+                                  virDomainHostdevDefPtr *hostdevs,
+                                  int nhostdevs,
+                                  const char *drv_name,
+                                  const char *dom_name)
+{
+    virDomainHostdevDefPtr hostdev = NULL;
+    size_t i;
+    int ret = -1;
+
+    if (!nhostdevs)
+        return 0;
+
+    virObjectLock(mgr->activeSCSIHostdevs);
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevSubsysSCSIPtr scsisrc;
+        hostdev = hostdevs[i];
+        scsisrc = &hostdev->source.subsys.u.scsi;
+
+        if (!virHostdevIsSCSIDevice(hostdev))
+            continue;
+
+        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
+            continue;  /* Not supported for iSCSI */
+        } else {
+            if (virHostdevUpdateActiveSCSIHostDevices(mgr, hostdev, scsisrc,
+                                                      drv_name, dom_name) < 0)
+                goto cleanup;
+        }
+    }
+    ret = 0;
+
+ cleanup:
+    virObjectUnlock(mgr->activeSCSIHostdevs);
+    return ret;
+}
+
+
+int
+virHostdevUpdateActiveMediatedDevices(virHostdevManagerPtr mgr,
+                                      virDomainHostdevDefPtr *hostdevs,
+                                      int nhostdevs,
+                                      const char *drv_name,
+                                      const char *dom_name)
+{
+    int ret = -1;
+    size_t i;
+    g_autoptr(virMediatedDevice) mdev = NULL;
+
+    if (nhostdevs == 0)
+        return 0;
+
+    virObjectLock(mgr->activeMediatedHostdevs);
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        virDomainHostdevSubsysMediatedDevPtr mdevsrc;
+
+        mdevsrc = &hostdev->source.subsys.u.mdev;
+
+        if (!virHostdevIsMdevDevice(hostdev))
+            continue;
+
+        if (!(mdev = virMediatedDeviceNew(mdevsrc->uuidstr, mdevsrc->model)))
+            goto cleanup;
+
+        virMediatedDeviceSetUsedBy(mdev, drv_name, dom_name);
+
+        if (virMediatedDeviceListAdd(mgr->activeMediatedHostdevs, &mdev) < 0)
+            goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    virObjectUnlock(mgr->activeMediatedHostdevs);
+    return ret;
+}
+
+
+static int
+virHostdevMarkUSBDevices(virHostdevManagerPtr mgr,
+                         const char *drv_name,
+                         const char *dom_name,
+                         virUSBDeviceListPtr list)
+{
+    size_t i, j;
+    unsigned int count;
+    virUSBDevicePtr tmp;
+
+    virObjectLock(mgr->activeUSBHostdevs);
+    count = virUSBDeviceListCount(list);
+
+    for (i = 0; i < count; i++) {
+        virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
+        if ((tmp = virUSBDeviceListFind(mgr->activeUSBHostdevs, usb))) {
+            const char *other_drvname;
+            const char *other_domname;
+
+            virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname);
+            if (other_drvname && other_domname)
+                virReportError(VIR_ERR_OPERATION_INVALID,
+                               _("USB device %s is in use by "
+                                 "driver %s, domain %s"),
+                               virUSBDeviceGetName(tmp),
+                               other_drvname, other_domname);
+            else
+                virReportError(VIR_ERR_OPERATION_INVALID,
+                               _("USB device %s is already in use"),
+                               virUSBDeviceGetName(tmp));
+            goto error;
+        }
+
+        virUSBDeviceSetUsedBy(usb, drv_name, dom_name);
+        VIR_DEBUG("Adding %03d.%03d dom=%s to activeUSBHostdevs",
+                  virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb),
+                  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
+virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
+                        bool mandatory,
+                        virUSBDevicePtr *usb)
+{
+    virDomainHostdevSubsysUSBPtr usbsrc = &hostdev->source.subsys.u.usb;
+    unsigned vendor = usbsrc->vendor;
+    unsigned product = usbsrc->product;
+    unsigned bus = usbsrc->bus;
+    unsigned device = usbsrc->device;
+    bool autoAddress = usbsrc->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) {
+        g_autoptr(virUSBDeviceList) devs = NULL;
+
+        rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
+        if (rc < 0) {
+            return -1;
+        } else 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;
+        }
+
+        *usb = virUSBDeviceListGet(devs, 0);
+        virUSBDeviceListSteal(devs, *usb);
+
+        usbsrc->bus = virUSBDeviceGetBus(*usb);
+        usbsrc->device = virUSBDeviceGetDevno(*usb);
+        usbsrc->autoAddress = true;
+
+        if (autoAddress) {
+            VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
+                     " from bus:%u device:%u)",
+                     vendor, product,
+                     usbsrc->bus, usbsrc->device,
+                     bus, device);
+        }
+    } else if (!vendor && bus) {
+        if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
+            return -1;
+    }
+
+ out:
+    if (!*usb)
+        hostdev->missing = true;
+    return 0;
+}
+
+int
+virHostdevPrepareUSBDevices(virHostdevManagerPtr mgr,
+                            const char *drv_name,
+                            const char *dom_name,
+                            virDomainHostdevDefPtr *hostdevs,
+                            int nhostdevs,
+                            unsigned int flags)
+{
+    size_t i;
+    g_autoptr(virUSBDeviceList) list = NULL;
+    virUSBDevicePtr tmp;
+    bool coldBoot = !!(flags & VIR_HOSTDEV_COLD_BOOT);
+
+    if (!nhostdevs)
+        return 0;
+
+    /* To prevent situation where USB device is assigned to two domains
+     * we need to keep a list of currently assigned USB devices.
+     * This is done in several loops which cannot be joined into one big
+     * loop. See virHostdevPreparePCIDevices()
+     */
+    if (!(list = virUSBDeviceListNew()))
+        return -1;
+
+    /* Loop 1: build temporary list
+     */
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        bool required = true;
+        g_autoptr(virUSBDevice) usb = NULL;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+            continue;
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
+            continue;
+
+        if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
+            (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
+             !coldBoot))
+            required = false;
+
+        if (virHostdevFindUSBDevice(hostdev, required, &usb) < 0)
+            return -1;
+
+        if (usb && virUSBDeviceListAdd(list, &usb) < 0)
+            return -1;
+        usb = NULL;
+    }
+
+    /* Mark devices in temporary list as used by @dom_name
+     * and add them do driver list. However, if something goes
+     * wrong, perform rollback.
+     */
+    if (virHostdevMarkUSBDevices(mgr, drv_name, dom_name, list) < 0)
+        return -1;
+
+    /* 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);
+    }
+
+    return 0;
+}
+
+static int
+virHostdevPrepareSCSIHostDevices(virDomainHostdevDefPtr hostdev,
+                                 virDomainHostdevSubsysSCSIPtr scsisrc,
+                                 virSCSIDeviceListPtr list)
+{
+    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
+    g_autoptr(virSCSIDevice) scsi = NULL;
+
+    if (hostdev->managed) {
+        virReportError(VIR_ERR_XML_ERROR, "%s",
+                       _("SCSI host device doesn't support managed mode"));
+        return -1;
+    }
+
+    if (!(scsi = virSCSIDeviceNew(NULL,
+                                  scsihostsrc->adapter, scsihostsrc->bus,
+                                  scsihostsrc->target, scsihostsrc->unit,
+                                  hostdev->readonly, hostdev->shareable)))
+        return -1;
+
+    if (virSCSIDeviceListAdd(list, scsi) < 0)
+        return -1;
+    scsi = NULL;
+
+    return 0;
+}
+
+int
+virHostdevPrepareSCSIDevices(virHostdevManagerPtr mgr,
+                             const char *drv_name,
+                             const char *dom_name,
+                             virDomainHostdevDefPtr *hostdevs,
+                             int nhostdevs)
+{
+    size_t i, j;
+    int count;
+    g_autoptr(virSCSIDeviceList) list = NULL;
+    virSCSIDevicePtr tmp;
+
+    if (!nhostdevs)
+        return 0;
+
+    /* To prevent situation where SCSI device is assigned to two domains
+     * we need to keep a list of currently assigned SCSI devices.
+     * This is done in several loops which cannot be joined into one big
+     * loop. See virHostdevPreparePCIDevices()
+     */
+    if (!(list = virSCSIDeviceListNew()))
+        return -1;
+
+    /* Loop 1: build temporary list */
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
+
+        if (!virHostdevIsSCSIDevice(hostdev))
+            continue;
+
+        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
+            continue;  /* Not supported for iSCSI */
+        } else {
+            if (virHostdevPrepareSCSIHostDevices(hostdev, scsisrc, list) < 0)
+                return -1;
+        }
+    }
+
+    /* Loop 2: Mark devices in temporary list as used by @name
+     * and add them to driver list. However, if something goes
+     * wrong, perform rollback.
+     */
+    virObjectLock(mgr->activeSCSIHostdevs);
+    count = virSCSIDeviceListCount(list);
+
+    for (i = 0; i < count; i++) {
+        virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
+        if ((tmp = virSCSIDeviceListFind(mgr->activeSCSIHostdevs,
+                                         scsi))) {
+            bool scsi_shareable = virSCSIDeviceGetShareable(scsi);
+            bool tmp_shareable = virSCSIDeviceGetShareable(tmp);
+
+            if (!(scsi_shareable && tmp_shareable)) {
+                virReportError(VIR_ERR_OPERATION_INVALID,
+                               _("SCSI device %s is already in use by "
+                                 "other domain(s) as '%s'"),
+                               virSCSIDeviceGetName(tmp),
+                               tmp_shareable ? "shareable" : "non-shareable");
+                goto error;
+            }
+
+            if (virSCSIDeviceSetUsedBy(tmp, drv_name, dom_name) < 0)
+                goto error;
+        } else {
+            if (virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name) < 0)
+                goto error;
+
+            VIR_DEBUG("Adding %s to activeSCSIHostdevs", virSCSIDeviceGetName(scsi));
+
+            if (virSCSIDeviceListAdd(mgr->activeSCSIHostdevs, scsi) < 0)
+                goto error;
+        }
+    }
+
+    virObjectUnlock(mgr->activeSCSIHostdevs);
+
+    /* Loop 3: Temporary list was successfully merged with
+     * driver list, so steal all items to avoid freeing them
+     * when freeing temporary list.
+     */
+    while (virSCSIDeviceListCount(list) > 0) {
+        tmp = virSCSIDeviceListGet(list, 0);
+        virSCSIDeviceListSteal(list, tmp);
+    }
+
+    return 0;
+
+ error:
+    for (j = 0; j < i; j++) {
+        tmp = virSCSIDeviceListGet(list, i);
+        virSCSIDeviceListSteal(mgr->activeSCSIHostdevs, tmp);
+    }
+    virObjectUnlock(mgr->activeSCSIHostdevs);
+    return -1;
+}
+
+int
+virHostdevPrepareSCSIVHostDevices(virHostdevManagerPtr mgr,
+                                  const char *drv_name,
+                                  const char *dom_name,
+                                  virDomainHostdevDefPtr *hostdevs,
+                                  int nhostdevs)
+{
+    g_autoptr(virSCSIVHostDeviceList) list = NULL;
+    virSCSIVHostDevicePtr tmp;
+    size_t i, j;
+
+    if (!nhostdevs)
+        return 0;
+
+    /* To prevent situation where scsi_host device is assigned to two domains
+     * we need to keep a list of currently assigned scsi_host devices.
+     * This is done in several loops which cannot be joined into one big
+     * loop. See virHostdevPreparePCIDevices()
+     */
+    if (!(list = virSCSIVHostDeviceListNew()))
+        return -1;
+
+    /* Loop 1: build temporary list */
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        virDomainHostdevSubsysSCSIVHostPtr hostsrc = &hostdev->source.subsys.u.scsi_host;
+        g_autoptr(virSCSIVHostDevice) host = NULL;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST)
+            continue;
+
+        if (hostsrc->protocol != VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST)
+            continue;  /* Not supported */
+
+        if (!(host = virSCSIVHostDeviceNew(hostsrc->wwpn)))
+            return -1;
+
+        if (virSCSIVHostDeviceSetUsedBy(host, drv_name, dom_name) < 0)
+            return -1;
+
+        if (virSCSIVHostDeviceListAdd(list, host) < 0)
+            return -1;
+        host = NULL;
+    }
+
+    /* Loop 2: Mark devices in temporary list as used by @name
+     * and add them to driver list. However, if something goes
+     * wrong, perform rollback.
+     */
+    virObjectLock(mgr->activeSCSIVHostHostdevs);
+
+    for (i = 0; i < virSCSIVHostDeviceListCount(list); i++) {
+        tmp = virSCSIVHostDeviceListGet(list, i);
+
+        VIR_DEBUG("Adding %s to activeSCSIVHostHostdevs",
+                  virSCSIVHostDeviceGetName(tmp));
+
+        if (virSCSIVHostDeviceListAdd(mgr->activeSCSIVHostHostdevs, tmp) < 0)
+            goto rollback;
+    }
+
+    virObjectUnlock(mgr->activeSCSIVHostHostdevs);
+
+    /* Loop 3: Temporary list was successfully merged with
+     * driver list, so steal all items to avoid freeing them
+     * when freeing temporary list.
+     */
+    while (virSCSIVHostDeviceListCount(list) > 0) {
+        tmp = virSCSIVHostDeviceListGet(list, 0);
+        virSCSIVHostDeviceListSteal(list, tmp);
+    }
+
+    return 0;
+
+ rollback:
+    for (j = 0; j < i; j++) {
+        tmp = virSCSIVHostDeviceListGet(list, i);
+        virSCSIVHostDeviceListSteal(mgr->activeSCSIVHostHostdevs, tmp);
+    }
+    virObjectUnlock(mgr->activeSCSIVHostHostdevs);
+    return -1;
+}
+
+
+int
+virHostdevPrepareMediatedDevices(virHostdevManagerPtr mgr,
+                                 const char *drv_name,
+                                 const char *dom_name,
+                                 virDomainHostdevDefPtr *hostdevs,
+                                 int nhostdevs)
+{
+    size_t i;
+    g_autoptr(virMediatedDeviceList) list = NULL;
+
+    if (!nhostdevs)
+        return 0;
+
+    /* To prevent situation where mediated device is assigned to multiple
+     * domains we maintain a driver list of currently assigned mediated devices.
+     * A device is appended to the driver list after a series of preparations.
+     */
+    if (!(list = virMediatedDeviceListNew()))
+        return -1;
+
+    /* Loop 1: Build a temporary list of ALL mediated devices. */
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        virDomainHostdevSubsysMediatedDevPtr src = &hostdev->source.subsys.u.mdev;
+        g_autoptr(virMediatedDevice) mdev = NULL;
+
+        if (!virHostdevIsMdevDevice(hostdev))
+            continue;
+
+        if (!(mdev = virMediatedDeviceNew(src->uuidstr, src->model)))
+            return -1;
+
+        if (virMediatedDeviceListAdd(list, &mdev) < 0)
+            return -1;
+        mdev = NULL;
+    }
+
+    /* Mark the devices in the list as used by @drv_name-@dom_name and copy the
+     * references to the driver list
+     */
+    if (virMediatedDeviceListMarkDevices(mgr->activeMediatedHostdevs,
+                                         list, drv_name, dom_name) < 0)
+        return -1;
+
+    /* Loop 2: Temporary list was successfully merged with
+     * driver list, so steal all items to avoid freeing them
+     * in cleanup label.
+     */
+    while (virMediatedDeviceListCount(list) > 0) {
+        virMediatedDevicePtr tmp = virMediatedDeviceListGet(list, 0);
+        virMediatedDeviceListSteal(list, tmp);
+    }
+
+    return 0;
+}
+
+void
+virHostdevReAttachUSBDevices(virHostdevManagerPtr mgr,
+                             const char *drv_name,
+                             const char *dom_name,
+                             virDomainHostdevDefPtr *hostdevs,
+                             int nhostdevs)
+{
+    size_t i;
+
+    if (!nhostdevs)
+        return;
+
+    virObjectLock(mgr->activeUSBHostdevs);
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        virDomainHostdevSubsysUSBPtr usbsrc = &hostdev->source.subsys.u.usb;
+        g_autoptr(virUSBDevice) usb = NULL;
+        virUSBDevicePtr tmp;
+        const char *usedby_drvname;
+        const char *usedby_domname;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+            continue;
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
+            continue;
+        if (hostdev->missing)
+            continue;
+
+        if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL))) {
+            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
+                     usbsrc->bus, usbsrc->device, NULLSTR(dom_name));
+            continue;
+        }
+
+        /* Delete only those USB devices which belongs
+         * to domain @name because qemuProcessStart() might
+         * have failed because USB device is already taken.
+         * Therefore we want to steal only those devices from
+         * the list which were taken by @name */
+
+        tmp = virUSBDeviceListFind(mgr->activeUSBHostdevs, usb);
+
+        if (!tmp) {
+            VIR_WARN("Unable to find device %03d.%03d "
+                     "in list of active USB devices",
+                     usbsrc->bus, usbsrc->device);
+            continue;
+        }
+
+        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 from activeUSBHostdevs",
+                      usbsrc->bus, usbsrc->device, dom_name);
+            virUSBDeviceListDel(mgr->activeUSBHostdevs, tmp);
+        }
+    }
+    virObjectUnlock(mgr->activeUSBHostdevs);
+}
+
+static void
+virHostdevReAttachSCSIHostDevices(virHostdevManagerPtr mgr,
+                                  virDomainHostdevDefPtr hostdev,
+                                  virDomainHostdevSubsysSCSIPtr scsisrc,
+                                  const char *drv_name,
+                                  const char *dom_name)
+{
+    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
+    g_autoptr(virSCSIDevice) scsi = NULL;
+    virSCSIDevicePtr tmp;
+
+    if (!(scsi = virSCSIDeviceNew(NULL,
+                                  scsihostsrc->adapter, scsihostsrc->bus,
+                                  scsihostsrc->target, scsihostsrc->unit,
+                                  hostdev->readonly, hostdev->shareable))) {
+        VIR_WARN("Unable to reattach SCSI device %s:%u:%u:%llu on domain %s",
+                 scsihostsrc->adapter, scsihostsrc->bus, scsihostsrc->target,
+                 scsihostsrc->unit, dom_name);
+        return;
+    }
+
+    /* Only delete the devices which are marked as being used by @name,
+     * because qemuProcessStart could fail half way through. */
+
+    if (!(tmp = virSCSIDeviceListFind(mgr->activeSCSIHostdevs, scsi))) {
+        VIR_WARN("Unable to find device %s:%u:%u:%llu "
+                 "in list of active SCSI devices",
+                 scsihostsrc->adapter, scsihostsrc->bus,
+                 scsihostsrc->target, scsihostsrc->unit);
+        return;
+    }
+
+    VIR_DEBUG("Removing %s:%u:%u:%llu dom=%s from activeSCSIHostdevs",
+              scsihostsrc->adapter, scsihostsrc->bus, scsihostsrc->target,
+              scsihostsrc->unit, dom_name);
+
+    virSCSIDeviceListDel(mgr->activeSCSIHostdevs, tmp,
+                         drv_name, dom_name);
+}
+
+void
+virHostdevReAttachSCSIDevices(virHostdevManagerPtr mgr,
+                              const char *drv_name,
+                              const char *dom_name,
+                              virDomainHostdevDefPtr *hostdevs,
+                              int nhostdevs)
+{
+    size_t i;
+
+    if (!nhostdevs)
+        return;
+
+    virObjectLock(mgr->activeSCSIHostdevs);
+    for (i = 0; i < nhostdevs; i++) {
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
+
+        if (!virHostdevIsSCSIDevice(hostdev))
+            continue;
+
+        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
+            continue; /* Not supported for iSCSI */
+        else
+            virHostdevReAttachSCSIHostDevices(mgr, hostdev, scsisrc,
+                                              drv_name, dom_name);
+    }
+    virObjectUnlock(mgr->activeSCSIHostdevs);
+}
+
+void
+virHostdevReAttachSCSIVHostDevices(virHostdevManagerPtr mgr,
+                                   const char *drv_name,
+                                   const char *dom_name,
+                                   virDomainHostdevDefPtr *hostdevs,
+                                   int nhostdevs)
+{
+    size_t i;
+
+    if (!nhostdevs)
+        return;
+
+    virObjectLock(mgr->activeSCSIVHostHostdevs);
+    for (i = 0; i < nhostdevs; i++) {
+        g_autoptr(virSCSIVHostDevice) host = NULL;
+        virSCSIVHostDevicePtr tmp;
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+        virDomainHostdevSubsysSCSIVHostPtr hostsrc = &hostdev->source.subsys.u.scsi_host;
+        const char *usedby_drvname;
+        const char *usedby_domname;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST)
+            continue;
+
+        if (hostsrc->protocol != VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST)
+            continue; /* Not supported */
+
+        if (!(host = virSCSIVHostDeviceNew(hostsrc->wwpn))) {
+            VIR_WARN("Unable to reattach SCSI_host device %s on domain %s",
+                     hostsrc->wwpn, NULLSTR(dom_name));
+            virObjectUnlock(mgr->activeSCSIVHostHostdevs);
+            return;
+        }
+
+        /* Only delete the devices which are marked as being used by @name,
+         * because qemuProcessStart could fail half way through. */
+
+        if (!(tmp = virSCSIVHostDeviceListFind(mgr->activeSCSIVHostHostdevs,
+                                               host))) {
+            VIR_WARN("Unable to find device %s "
+                     "in list of active SCSI_host devices",
+                     hostsrc->wwpn);
+            virObjectUnlock(mgr->activeSCSIVHostHostdevs);
+            return;
+        }
+
+        virSCSIVHostDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname);
+
+        if (STREQ_NULLABLE(drv_name, usedby_drvname) &&
+            STREQ_NULLABLE(dom_name, usedby_domname)) {
+            VIR_DEBUG("Removing %s dom=%s from activeSCSIVHostHostdevs",
+                      hostsrc->wwpn, dom_name);
+
+            virSCSIVHostDeviceListDel(mgr->activeSCSIVHostHostdevs, tmp);
+        }
+    }
+    virObjectUnlock(mgr->activeSCSIVHostHostdevs);
+}
+
+/* TODO: Rename this function along with all virHostdevReAttach* functions that
+ * have nothing to do with an explicit re-attachment of a device back to the
+ * host driver (like PCI).
+ * Despite what the function name suggests, there's nothing to be re-attached
+ * for mediated devices, the function merely removes a mediated device from the
+ * list of active host devices.
+ */
+void
+virHostdevReAttachMediatedDevices(virHostdevManagerPtr mgr,
+                                  const char *drv_name,
+                                  const char *dom_name,
+                                  virDomainHostdevDefPtr *hostdevs,
+                                  int nhostdevs)
+{
+    const char *used_by_drvname = NULL;
+    const char *used_by_domname = NULL;
+    size_t i;
+
+    if (nhostdevs == 0)
+        return;
+
+    virObjectLock(mgr->activeMediatedHostdevs);
+    for (i = 0; i < nhostdevs; i++) {
+        g_autoptr(virMediatedDevice) mdev = NULL;
+        virMediatedDevicePtr tmp;
+        virDomainHostdevSubsysMediatedDevPtr mdevsrc;
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
+
+        mdevsrc = &hostdev->source.subsys.u.mdev;
+
+        if (!virHostdevIsMdevDevice(hostdev))
+            continue;
+
+        if (!(mdev = virMediatedDeviceNew(mdevsrc->uuidstr,
+                                          mdevsrc->model)))
+            continue;
+
+        /* Remove from the list only mdevs assigned to @drv_name/@dom_name */
+
+        tmp = virMediatedDeviceListFind(mgr->activeMediatedHostdevs, mdev);
+
+        /* skip inactive devices */
+        if (!tmp)
+            continue;
+
+        virMediatedDeviceGetUsedBy(tmp, &used_by_drvname, &used_by_domname);
+        if (STREQ_NULLABLE(drv_name, used_by_drvname) &&
+            STREQ_NULLABLE(dom_name, used_by_domname)) {
+            VIR_DEBUG("Removing %s dom=%s from activeMediatedHostdevs",
+                      mdevsrc->uuidstr, dom_name);
+            virMediatedDeviceListDel(mgr->activeMediatedHostdevs, tmp);
+        }
+    }
+    virObjectUnlock(mgr->activeMediatedHostdevs);
+}
+
+int
+virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr,
+                              virPCIDevicePtr pci)
+{
+    struct virHostdevIsPCINodeDeviceUsedData data = {mgr, NULL, NULL, false};
+    int ret = -1;
+
+    virObjectLock(mgr->activePCIHostdevs);
+    virObjectLock(mgr->inactivePCIHostdevs);
+
+    if (virHostdevIsPCINodeDeviceUsed(virPCIDeviceGetAddress(pci), &data))
+        goto cleanup;
+
+    if (virPCIDeviceDetach(pci, mgr->activePCIHostdevs,
+                           mgr->inactivePCIHostdevs) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virObjectUnlock(mgr->inactivePCIHostdevs);
+    virObjectUnlock(mgr->activePCIHostdevs);
+
+    return ret;
+}
+
+int
+virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr mgr,
+                                virPCIDevicePtr pci)
+{
+    struct virHostdevIsPCINodeDeviceUsedData data = {mgr, NULL, NULL, false};
+    int ret = -1;
+
+    virObjectLock(mgr->activePCIHostdevs);
+    virObjectLock(mgr->inactivePCIHostdevs);
+
+    if (virHostdevIsPCINodeDeviceUsed(virPCIDeviceGetAddress(pci), &data))
+        goto cleanup;
+
+    virPCIDeviceSetUnbindFromStub(pci, true);
+    virPCIDeviceSetRemoveSlot(pci, true);
+    virPCIDeviceSetReprobe(pci, true);
+
+    if (virPCIDeviceReattach(pci, mgr->activePCIHostdevs,
+                             mgr->inactivePCIHostdevs) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virObjectUnlock(mgr->inactivePCIHostdevs);
+    virObjectUnlock(mgr->activePCIHostdevs);
+
+    return ret;
+}
+
+int
+virHostdevPCINodeDeviceReset(virHostdevManagerPtr mgr,
+                             virPCIDevicePtr pci)
+{
+    int ret = -1;
+
+    virObjectLock(mgr->activePCIHostdevs);
+    virObjectLock(mgr->inactivePCIHostdevs);
+    if (virPCIDeviceReset(pci, mgr->activePCIHostdevs,
+                          mgr->inactivePCIHostdevs) < 0)
+        goto out;
+
+    ret = 0;
+ out:
+    virObjectUnlock(mgr->inactivePCIHostdevs);
+    virObjectUnlock(mgr->activePCIHostdevs);
+    return ret;
+}
+
+int
+virHostdevPrepareDomainDevices(virHostdevManagerPtr mgr,
+                               const char *driver,
+                               virDomainDefPtr def,
+                               unsigned int flags)
+{
+    if (!def->nhostdevs)
+        return 0;
+
+    if (!mgr) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("no host device manager defined"));
+        return -1;
+    }
+
+    if (flags & VIR_HOSTDEV_SP_PCI) {
+        if (virHostdevPreparePCIDevices(mgr, driver,
+                                        def->name, def->uuid,
+                                        def->hostdevs,
+                                        def->nhostdevs,
+                                        flags) < 0)
+            return -1;
+    }
+
+    if (flags & VIR_HOSTDEV_SP_USB) {
+        if (virHostdevPrepareUSBDevices(mgr, driver, def->name,
+                                        def->hostdevs, def->nhostdevs,
+                                        flags) < 0)
+            return -1;
+    }
+
+    if (flags & VIR_HOSTDEV_SP_SCSI) {
+        if (virHostdevPrepareSCSIDevices(mgr, driver, def->name,
+                                         def->hostdevs, def->nhostdevs) < 0)
+        return -1;
+    }
+
+    return 0;
+}
+
+/* @oldStateDir
+ * For upgrade purpose: see virHostdevReAttachPCIHostdevs
+ */
+void
+virHostdevReAttachDomainDevices(virHostdevManagerPtr mgr,
+                                const char *driver,
+                                virDomainDefPtr def,
+                                unsigned int flags,
+                                const char *oldStateDir)
+{
+    if (!def->nhostdevs || !mgr)
+        return;
+
+    if (flags & VIR_HOSTDEV_SP_PCI) {
+        virHostdevReAttachPCIDevices(mgr, driver, def->name,
+                                     def->hostdevs, def->nhostdevs,
+                                     oldStateDir);
+    }
+
+    if (flags & VIR_HOSTDEV_SP_USB) {
+        virHostdevReAttachUSBDevices(mgr, driver, def->name,
+                                     def->hostdevs, def->nhostdevs);
+    }
+
+    if (flags & VIR_HOSTDEV_SP_SCSI) {
+        virHostdevReAttachSCSIDevices(mgr, driver, def->name,
+                                      def->hostdevs, def->nhostdevs);
+    }
+}
+
+int
+virHostdevUpdateActiveDomainDevices(virHostdevManagerPtr mgr,
+                                    const char *driver,
+                                    virDomainDefPtr def,
+                                    unsigned int flags)
+{
+    if (!def->nhostdevs)
+        return 0;
+
+    if (flags & VIR_HOSTDEV_SP_PCI) {
+        if (virHostdevUpdateActivePCIDevices(mgr,
+                                             def->hostdevs,
+                                             def->nhostdevs,
+                                             driver, def->name) < 0)
+            return -1;
+    }
+
+    if (flags & VIR_HOSTDEV_SP_USB) {
+        if (virHostdevUpdateActiveUSBDevices(mgr,
+                                             def->hostdevs,
+                                             def->nhostdevs,
+                                             driver, def->name) < 0)
+            return -1;
+    }
+
+    if (flags & VIR_HOSTDEV_SP_SCSI) {
+        if (virHostdevUpdateActiveSCSIDevices(mgr,
+                                              def->hostdevs,
+                                              def->nhostdevs,
+                                              driver, def->name) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
+static int
+virHostdevGetNVMeDeviceList(virNVMeDeviceListPtr nvmeDevices,
+                            virStorageSourcePtr src,
+                            const char *drv_name,
+                            const char *dom_name)
+{
+    virStorageSourcePtr n;
+
+    for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
+        g_autoptr(virNVMeDevice) dev = NULL;
+        const virStorageSourceNVMeDef *srcNVMe = n->nvme;
+
+        if (n->type != VIR_STORAGE_TYPE_NVME)
+            continue;
+
+        if (!(dev = virNVMeDeviceNew(&srcNVMe->pciAddr,
+                                     srcNVMe->namespace,
+                                     srcNVMe->managed)))
+            return -1;
+
+        virNVMeDeviceUsedBySet(dev, drv_name, dom_name);
+
+        if (virNVMeDeviceListAdd(nvmeDevices, dev) < 0)
+            return -1;
+    }
+
+    return 0;
+}
+
+
+int
+virHostdevPrepareOneNVMeDevice(virHostdevManagerPtr hostdev_mgr,
+                               const char *drv_name,
+                               const char *dom_name,
+                               virStorageSourcePtr src)
+{
+    g_autoptr(virNVMeDeviceList) nvmeDevices = NULL;
+    g_autoptr(virPCIDeviceList) pciDevices = NULL;
+    const unsigned int pciFlags = 0;
+    virNVMeDevicePtr temp = NULL;
+    size_t i;
+    ssize_t lastGoodNVMeIdx = -1;
+    int ret = -1;
+
+    if (!(nvmeDevices = virNVMeDeviceListNew()))
+        return -1;
+
+    if (virHostdevGetNVMeDeviceList(nvmeDevices, src, drv_name, dom_name) < 0)
+        return -1;
+
+    if (virNVMeDeviceListCount(nvmeDevices) == 0)
+        return 0;
+
+    virObjectLock(hostdev_mgr->activeNVMeHostdevs);
+
+    /* Firstly, let's check if all devices are free */
+    for (i = 0; i < virNVMeDeviceListCount(nvmeDevices); i++) {
+        const virNVMeDevice *dev = virNVMeDeviceListGet(nvmeDevices, i);
+        const virPCIDeviceAddress *addr = NULL;
+        g_autofree char *addrStr = NULL;
+        const char *actual_drvname = NULL;
+        const char *actual_domname = NULL;
+
+        temp = virNVMeDeviceListLookup(hostdev_mgr->activeNVMeHostdevs, dev);
+
+        /* Not on the list means not used */
+        if (!temp)
+            continue;
+
+        virNVMeDeviceUsedByGet(temp, &actual_drvname, &actual_domname);
+        addr = virNVMeDeviceAddressGet(dev);
+        addrStr = virPCIDeviceAddressAsString(addr);
+
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("NVMe device %s already in use by driver %s domain %s"),
+                       NULLSTR(addrStr), actual_drvname, actual_domname);
+        goto cleanup;
+    }
+
+    if (!(pciDevices = virNVMeDeviceListCreateDetachList(hostdev_mgr->activeNVMeHostdevs,
+                                                         nvmeDevices)))
+        goto cleanup;
+
+    /* Let's check if all PCI devices are NVMe disks. */
+    for (i = 0; i < virPCIDeviceListCount(pciDevices); i++) {
+        virPCIDevicePtr pci = virPCIDeviceListGet(pciDevices, i);
+        g_autofree char *drvPath = NULL;
+        g_autofree char *drvName = NULL;
+        int stub = VIR_PCI_STUB_DRIVER_NONE;
+
+        if (virPCIDeviceGetDriverPathAndName(pci, &drvPath, &drvName) < 0)
+            goto cleanup;
+
+        if (drvName)
+            stub = virPCIStubDriverTypeFromString(drvName);
+
+        if (stub == VIR_PCI_STUB_DRIVER_VFIO ||
+            STREQ_NULLABLE(drvName, "nvme"))
+            continue;
+
+        VIR_WARN("Suspicious NVMe disk assignment. PCI device "
+                 "%s is not an NVMe disk, it has %s driver",
+                 virPCIDeviceGetName(pci), NULLSTR(drvName));
+    }
+
+    /* This looks like a good opportunity to merge inactive NVMe devices onto
+     * the active list. This, however, means that if something goes wrong we
+     * have to perform a rollback before returning. */
+    for (i = 0; i < virNVMeDeviceListCount(nvmeDevices); i++) {
+        temp = virNVMeDeviceListGet(nvmeDevices, i);
+
+        if (virNVMeDeviceListAdd(hostdev_mgr->activeNVMeHostdevs, temp) < 0)
+            goto rollback;
+
+        lastGoodNVMeIdx = i;
+    }
+
+    if (virHostdevPreparePCIDevicesImpl(hostdev_mgr,
+                                        drv_name, dom_name, NULL,
+                                        pciDevices, NULL, 0, pciFlags) < 0)
+        goto rollback;
+
+    ret = 0;
+ cleanup:
+    virObjectUnlock(hostdev_mgr->activeNVMeHostdevs);
+    return ret;
+
+ rollback:
+    while (lastGoodNVMeIdx >= 0) {
+        temp = virNVMeDeviceListGet(nvmeDevices, lastGoodNVMeIdx);
+
+        virNVMeDeviceListDel(hostdev_mgr->activeNVMeHostdevs, temp);
+
+        lastGoodNVMeIdx--;
+    }
+    goto cleanup;
+}
+
+
+int
+virHostdevPrepareNVMeDevices(virHostdevManagerPtr hostdev_mgr,
+                             const char *drv_name,
+                             const char *dom_name,
+                             virDomainDiskDefPtr *disks,
+                             size_t ndisks)
+{
+    size_t i;
+    ssize_t lastGoodDiskIdx = -1;
+
+    for (i = 0; i < ndisks; i++) {
+        if (virHostdevPrepareOneNVMeDevice(hostdev_mgr, drv_name,
+                                           dom_name, disks[i]->src) < 0)
+            goto rollback;
+
+        lastGoodDiskIdx = i;
+    }
+
+    return 0;
+
+ rollback:
+    while (lastGoodDiskIdx >= 0) {
+        if (virHostdevReAttachOneNVMeDevice(hostdev_mgr, drv_name, dom_name,
+                                            disks[lastGoodDiskIdx]->src) < 0) {
+            VIR_ERROR(_("Failed to reattach NVMe for disk target: %s"),
+                      disks[lastGoodDiskIdx]->dst);
+        }
+
+        lastGoodDiskIdx--;
+    }
+
+    return -1;
+}
+
+
+int
+virHostdevReAttachOneNVMeDevice(virHostdevManagerPtr hostdev_mgr,
+                                const char *drv_name,
+                                const char *dom_name,
+                                virStorageSourcePtr src)
+{
+    g_autoptr(virNVMeDeviceList) nvmeDevices = NULL;
+    g_autoptr(virPCIDeviceList) pciDevices = NULL;
+    size_t i;
+    int ret = -1;
+
+    if (!(nvmeDevices = virNVMeDeviceListNew()))
+        return -1;
+
+    if (virHostdevGetNVMeDeviceList(nvmeDevices, src, drv_name, dom_name) < 0)
+        return -1;
+
+    if (virNVMeDeviceListCount(nvmeDevices) == 0)
+        return 0;
+
+    virObjectLock(hostdev_mgr->activeNVMeHostdevs);
+
+    if (!(pciDevices = virNVMeDeviceListCreateReAttachList(hostdev_mgr->activeNVMeHostdevs,
+                                                           nvmeDevices)))
+        goto cleanup;
+
+    virHostdevReAttachPCIDevicesImpl(hostdev_mgr,
+                                     drv_name, dom_name, pciDevices,
+                                     NULL, 0, NULL);
+
+    for (i = 0; i < virNVMeDeviceListCount(nvmeDevices); i++) {
+        virNVMeDevicePtr temp = virNVMeDeviceListGet(nvmeDevices, i);
+
+        if (virNVMeDeviceListDel(hostdev_mgr->activeNVMeHostdevs, temp) < 0)
+            goto cleanup;
+    }
+
+    ret = 0;
+ cleanup:
+    virObjectUnlock(hostdev_mgr->activeNVMeHostdevs);
+    return ret;
+}
+
+
+int
+virHostdevReAttachNVMeDevices(virHostdevManagerPtr hostdev_mgr,
+                              const char *drv_name,
+                              const char *dom_name,
+                              virDomainDiskDefPtr *disks,
+                              size_t ndisks)
+{
+    size_t i;
+    int ret = 0;
+
+    /* Contrary to virHostdevPrepareNVMeDevices, this is a best
+     * effort approach. Just iterate over all disks and try to
+     * reattach them. Don't stop at the first failure. */
+    for (i = 0; i < ndisks; i++) {
+        if (virHostdevReAttachOneNVMeDevice(hostdev_mgr, drv_name,
+                                            dom_name, disks[i]->src) < 0) {
+            VIR_ERROR(_("Failed to reattach NVMe for disk target: %s"),
+                      disks[i]->dst);
+            ret = -1;
+        }
+    }
+
+    return ret;
+}
+
+
+int
+virHostdevUpdateActiveNVMeDevices(virHostdevManagerPtr hostdev_mgr,
+                                  const char *drv_name,
+                                  const char *dom_name,
+                                  virDomainDiskDefPtr *disks,
+                                  size_t ndisks)
+{
+    g_autoptr(virNVMeDeviceList) nvmeDevices = NULL;
+    g_autoptr(virPCIDeviceList) pciDevices = NULL;
+    virNVMeDevicePtr temp = NULL;
+    size_t i;
+    ssize_t lastGoodNVMeIdx = -1;
+    ssize_t lastGoodPCIIdx = -1;
+    int ret = -1;
+
+    if (!(nvmeDevices = virNVMeDeviceListNew()))
+        return -1;
+
+    for (i = 0; i < ndisks; i++) {
+        if (virHostdevGetNVMeDeviceList(nvmeDevices, disks[i]->src, drv_name, dom_name) < 0)
+            return -1;
+    }
+
+    if (virNVMeDeviceListCount(nvmeDevices) == 0)
+        return 0;
+
+    virObjectLock(hostdev_mgr->activeNVMeHostdevs);
+    virObjectLock(hostdev_mgr->activePCIHostdevs);
+    virObjectLock(hostdev_mgr->inactivePCIHostdevs);
+
+    if (!(pciDevices = virNVMeDeviceListCreateDetachList(hostdev_mgr->activeNVMeHostdevs,
+                                                         nvmeDevices)))
+        goto cleanup;
+
+    for (i = 0; i < virNVMeDeviceListCount(nvmeDevices); i++) {
+        temp = virNVMeDeviceListGet(nvmeDevices, i);
+
+        if (virNVMeDeviceListAdd(hostdev_mgr->activeNVMeHostdevs, temp) < 0)
+            goto rollback;
+
+        lastGoodNVMeIdx = i;
+    }
+
+    for (i = 0; i < virPCIDeviceListCount(pciDevices); i++) {
+        virPCIDevicePtr actual = virPCIDeviceListGet(pciDevices, i);
+
+        /* We must restore some attributes that were lost on daemon restart. */
+        virPCIDeviceSetUnbindFromStub(actual, true);
+        if (virPCIDeviceSetUsedBy(actual, drv_name, dom_name) < 0)
+            goto rollback;
+
+        if (virPCIDeviceListAddCopy(hostdev_mgr->activePCIHostdevs, actual) < 0)
+            goto rollback;
+
+        lastGoodPCIIdx = i;
+    }
+
+    ret = 0;
+ cleanup:
+    virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
+    virObjectUnlock(hostdev_mgr->activePCIHostdevs);
+    virObjectUnlock(hostdev_mgr->activeNVMeHostdevs);
+    return ret;
+
+ rollback:
+    while (lastGoodNVMeIdx >= 0) {
+        temp = virNVMeDeviceListGet(nvmeDevices, lastGoodNVMeIdx);
+
+        virNVMeDeviceListDel(hostdev_mgr->activeNVMeHostdevs, temp);
+
+        lastGoodNVMeIdx--;
+    }
+    while (lastGoodPCIIdx >= 0) {
+        virPCIDevicePtr actual = virPCIDeviceListGet(pciDevices, i);
+
+        virPCIDeviceListDel(hostdev_mgr->activePCIHostdevs, actual);
+
+        lastGoodPCIIdx--;
+    }
+    goto cleanup;
+}
diff --git a/src/hypervisor/virhostdev.h b/src/hypervisor/virhostdev.h
new file mode 100644 (file)
index 0000000..811bda4
--- /dev/null
@@ -0,0 +1,237 @@
+/* virhostdev.h: hostdev management
+ *
+ * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
+ *
+ * This library is free software; you can redistribute it and/or
+ * 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/>.
+ */
+
+#pragma once
+
+#include "internal.h"
+
+#include "virpci.h"
+#include "virusb.h"
+#include "virscsi.h"
+#include "virscsivhost.h"
+#include "conf/domain_conf.h"
+#include "virmdev.h"
+#include "virnvme.h"
+
+typedef enum {
+    VIR_HOSTDEV_STRICT_ACS_CHECK     = (1 << 0), /* strict acs check */
+    VIR_HOSTDEV_COLD_BOOT            = (1 << 1), /* cold boot */
+
+    VIR_HOSTDEV_SP_PCI               = (1 << 8), /* support pci passthrough */
+    VIR_HOSTDEV_SP_USB               = (1 << 9), /* support usb passthrough */
+    VIR_HOSTDEV_SP_SCSI              = (1 << 10), /* support scsi passthrough */
+} virHostdevFlag;
+
+
+typedef struct _virHostdevManager virHostdevManager;
+typedef virHostdevManager *virHostdevManagerPtr;
+struct _virHostdevManager {
+    virObject parent;
+
+    char *stateDir;
+
+    virPCIDeviceListPtr activePCIHostdevs;
+    virPCIDeviceListPtr inactivePCIHostdevs;
+    virUSBDeviceListPtr activeUSBHostdevs;
+    virSCSIDeviceListPtr activeSCSIHostdevs;
+    virSCSIVHostDeviceListPtr activeSCSIVHostHostdevs;
+    virMediatedDeviceListPtr activeMediatedHostdevs;
+    /* NVMe devices are PCI devices really, but one NVMe disk can
+     * have multiple namespaces. */
+    virNVMeDeviceListPtr activeNVMeHostdevs;
+};
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(virHostdevManager, virObjectUnref);
+
+
+virHostdevManagerPtr virHostdevManagerGetDefault(void);
+int
+virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
+                            const char *drv_name,
+                            const char *dom_name,
+                            const unsigned char *uuid,
+                            virDomainHostdevDefPtr *hostdevs,
+                            int nhostdevs,
+                            unsigned int flags)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
+    ATTRIBUTE_NONNULL(4);
+
+int
+virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
+                        bool mandatory,
+                        virUSBDevicePtr *usb)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
+int
+virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr,
+                            const char *drv_name,
+                            const char *dom_name,
+                            virDomainHostdevDefPtr *hostdevs,
+                            int nhostdevs,
+                            unsigned int flags)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+int
+virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr,
+                             const char *drv_name,
+                             const char *dom_name,
+                             virDomainHostdevDefPtr *hostdevs,
+                             int nhostdevs)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+int
+virHostdevPrepareSCSIVHostDevices(virHostdevManagerPtr hostdev_mgr,
+                                  const char *drv_name,
+                                  const char *dom_name,
+                                  virDomainHostdevDefPtr *hostdevs,
+                                  int nhostdevs)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+int
+virHostdevPrepareMediatedDevices(virHostdevManagerPtr hostdev_mgr,
+                                 const char *drv_name,
+                                 const char *dom_name,
+                                 virDomainHostdevDefPtr *hostdevs,
+                                 int nhostdevs)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+void
+virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
+                             const char *drv_name,
+                             const char *dom_name,
+                             virDomainHostdevDefPtr *hostdevs,
+                             int nhostdevs,
+                             const char *oldStateDir)
+    ATTRIBUTE_NONNULL(1);
+void
+virHostdevReAttachUSBDevices(virHostdevManagerPtr hostdev_mgr,
+                              const char *drv_name,
+                              const char *dom_name,
+                              virDomainHostdevDefPtr *hostdevs,
+                              int nhostdevs)
+    ATTRIBUTE_NONNULL(1);
+void
+virHostdevReAttachSCSIDevices(virHostdevManagerPtr hostdev_mgr,
+                              const char *drv_name,
+                              const char *dom_name,
+                              virDomainHostdevDefPtr *hostdevs,
+                              int nhostdevs)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+void
+virHostdevReAttachSCSIVHostDevices(virHostdevManagerPtr hostdev_mgr,
+                                   const char *drv_name,
+                                   const char *dom_name,
+                                   virDomainHostdevDefPtr *hostdevs,
+                                   int nhostdevs)
+    ATTRIBUTE_NONNULL(1);
+void
+virHostdevReAttachMediatedDevices(virHostdevManagerPtr hostdev_mgr,
+                                  const char *drv_name,
+                                  const char *dom_name,
+                                  virDomainHostdevDefPtr *hostdevs,
+                                  int nhostdevs)
+    ATTRIBUTE_NONNULL(1);
+int
+virHostdevUpdateActivePCIDevices(virHostdevManagerPtr mgr,
+                                 virDomainHostdevDefPtr *hostdevs,
+                                 int nhostdevs,
+                                 const char *drv_name,
+                                 const char *dom_name)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
+int
+virHostdevUpdateActiveUSBDevices(virHostdevManagerPtr mgr,
+                                 virDomainHostdevDefPtr *hostdevs,
+                                 int nhostdevs,
+                                 const char *drv_name,
+                                 const char *dom_name)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
+int
+virHostdevUpdateActiveSCSIDevices(virHostdevManagerPtr mgr,
+                                  virDomainHostdevDefPtr *hostdevs,
+                                  int nhostdevs,
+                                  const char *drv_name,
+                                  const char *dom_name)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
+int
+virHostdevUpdateActiveMediatedDevices(virHostdevManagerPtr mgr,
+                                      virDomainHostdevDefPtr *hostdevs,
+                                      int nhostdevs,
+                                      const char *drv_name,
+                                      const char *dom_name)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
+int
+virHostdevUpdateActiveDomainDevices(virHostdevManagerPtr mgr,
+                                    const char *driver,
+                                    virDomainDefPtr def,
+                                    unsigned int flags)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+int
+virHostdevPrepareDomainDevices(virHostdevManagerPtr mgr,
+                               const char *driver,
+                               virDomainDefPtr def,
+                               unsigned int flags)
+    ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+void
+virHostdevReAttachDomainDevices(virHostdevManagerPtr mgr,
+                                const char *driver,
+                                virDomainDefPtr def,
+                                unsigned int flags,
+                                const char *oldStateDir)
+    ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
+
+/* functions used by NodeDevDetach/Reattach/Reset */
+int virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr,
+                                  virPCIDevicePtr pci)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr mgr,
+                                    virPCIDevicePtr pci)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int virHostdevPCINodeDeviceReset(virHostdevManagerPtr mgr,
+                                 virPCIDevicePtr pci)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+
+int
+virHostdevPrepareOneNVMeDevice(virHostdevManagerPtr hostdev_mgr,
+                               const char *drv_name,
+                               const char *dom_name,
+                               virStorageSourcePtr src);
+
+int
+virHostdevPrepareNVMeDevices(virHostdevManagerPtr hostdev_mgr,
+                             const char *drv_name,
+                             const char *dom_name,
+                             virDomainDiskDefPtr *disks,
+                             size_t ndisks);
+
+int
+virHostdevReAttachOneNVMeDevice(virHostdevManagerPtr hostdev_mgr,
+                                const char *drv_name,
+                                const char *dom_name,
+                                virStorageSourcePtr src);
+
+int
+virHostdevReAttachNVMeDevices(virHostdevManagerPtr hostdev_mgr,
+                              const char *drv_name,
+                              const char *dom_name,
+                              virDomainDiskDefPtr *disks,
+                              size_t ndisks);
+
+int
+virHostdevUpdateActiveNVMeDevices(virHostdevManagerPtr hostdev_mgr,
+                                  const char *drv_name,
+                                  const char *dom_name,
+                                  virDomainDiskDefPtr *disks,
+                                  size_t ndisks);
index 05e1bc875b537a65038f371f8646881905f765da..85b1eca72f3c8ed5b82a8e504197e351e7a2920b 100644 (file)
@@ -1406,6 +1406,36 @@ virDomainDriverParseBlkioDeviceStr;
 virDomainDriverSetupPersistentDefBlkioParams;
 
 
+# hypervisor/virhostdev.h
+virHostdevFindUSBDevice;
+virHostdevManagerGetDefault;
+virHostdevPCINodeDeviceDetach;
+virHostdevPCINodeDeviceReAttach;
+virHostdevPCINodeDeviceReset;
+virHostdevPrepareDomainDevices;
+virHostdevPrepareMediatedDevices;
+virHostdevPrepareNVMeDevices;
+virHostdevPrepareOneNVMeDevice;
+virHostdevPreparePCIDevices;
+virHostdevPrepareSCSIDevices;
+virHostdevPrepareSCSIVHostDevices;
+virHostdevPrepareUSBDevices;
+virHostdevReAttachDomainDevices;
+virHostdevReAttachMediatedDevices;
+virHostdevReAttachNVMeDevices;
+virHostdevReAttachOneNVMeDevice;
+virHostdevReAttachPCIDevices;
+virHostdevReAttachSCSIDevices;
+virHostdevReAttachSCSIVHostDevices;
+virHostdevReAttachUSBDevices;
+virHostdevUpdateActiveDomainDevices;
+virHostdevUpdateActiveMediatedDevices;
+virHostdevUpdateActiveNVMeDevices;
+virHostdevUpdateActivePCIDevices;
+virHostdevUpdateActiveSCSIDevices;
+virHostdevUpdateActiveUSBDevices;
+
+
 # libvirt_internal.h
 virConnectSupportsFeature;
 virDomainMigrateBegin3;
@@ -2169,36 +2199,6 @@ virHostCPUHasBitmap;
 virHostCPUStatsAssign;
 
 
-# util/virhostdev.h
-virHostdevFindUSBDevice;
-virHostdevManagerGetDefault;
-virHostdevPCINodeDeviceDetach;
-virHostdevPCINodeDeviceReAttach;
-virHostdevPCINodeDeviceReset;
-virHostdevPrepareDomainDevices;
-virHostdevPrepareMediatedDevices;
-virHostdevPrepareNVMeDevices;
-virHostdevPrepareOneNVMeDevice;
-virHostdevPreparePCIDevices;
-virHostdevPrepareSCSIDevices;
-virHostdevPrepareSCSIVHostDevices;
-virHostdevPrepareUSBDevices;
-virHostdevReAttachDomainDevices;
-virHostdevReAttachMediatedDevices;
-virHostdevReAttachNVMeDevices;
-virHostdevReAttachOneNVMeDevice;
-virHostdevReAttachPCIDevices;
-virHostdevReAttachSCSIDevices;
-virHostdevReAttachSCSIVHostDevices;
-virHostdevReAttachUSBDevices;
-virHostdevUpdateActiveDomainDevices;
-virHostdevUpdateActiveMediatedDevices;
-virHostdevUpdateActiveNVMeDevices;
-virHostdevUpdateActivePCIDevices;
-virHostdevUpdateActiveSCSIDevices;
-virHostdevUpdateActiveUSBDevices;
-
-
 # util/virhostmem.h
 virHostMemAllocPages;
 virHostMemGetCellsFree;
index 4dc1b9d039ea16cd4fa8d663cef8a482c7a02c4c..ff6a2b0f69ac719db021b169c61bfbd04d4ed519 100644 (file)
@@ -46,6 +46,7 @@ libvirt_driver_libxl_impl_la_CFLAGS = \
        -I$(builddir)/access \
        -I$(srcdir)/conf \
        -I$(srcdir)/secret \
+       -I$(srcdir)/hypervisor \
        $(AM_CFLAGS) \
        $(NULL)
 libvirt_driver_libxl_impl_la_LDFLAGS = $(AM_LDFLAGS)
index 823d80c5dd4a4cfe7b5800e102984b55a6be9d2a..5f2f4c8e2de4427f89aaa4e52d83b7e956e2fcba 100644 (file)
@@ -100,6 +100,7 @@ virt_aa_helper_LDADD += libvirt_probes.lo
 endif WITH_DTRACE_PROBES
 virt_aa_helper_CFLAGS = \
        -I$(srcdir)/conf \
+       -I$(top_srcdir)/src/hypervisor \
        -I$(srcdir)/security \
        $(AM_CFLAGS) \
        $(PIE_CFLAGS) \
index fbe67090d3993a7ab59ba072967f3138cabe5868..a340fdeffb5e0734bce87def05a744a51b807368 100644 (file)
@@ -92,8 +92,6 @@ UTIL_SOURCES = \
        util/virhostcpu.c \
        util/virhostcpu.h \
        util/virhostcpupriv.h \
-       util/virhostdev.c \
-       util/virhostdev.h \
        util/virhostmem.c \
        util/virhostmem.h \
        util/virhostuptime.c \
diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c
deleted file mode 100644 (file)
index 6565ceb..0000000
+++ /dev/null
@@ -1,2523 +0,0 @@
-/* virhostdev.c: hostdev management
- *
- * Copyright (C) 2006-2007, 2009-2017 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
- *
- * This library is free software; you can redistribute it and/or
- * 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/>.
- */
-
-#include <config.h>
-
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "virhostdev.h"
-#include "viralloc.h"
-#include "virstring.h"
-#include "virfile.h"
-#include "virerror.h"
-#include "virlog.h"
-#include "virutil.h"
-#include "virnetdev.h"
-#include "configmake.h"
-
-#define VIR_FROM_THIS VIR_FROM_NONE
-
-VIR_LOG_INIT("util.hostdev");
-
-#define HOSTDEV_STATE_DIR RUNSTATEDIR "/libvirt/hostdevmgr"
-
-static virHostdevManagerPtr manager; /* global hostdev manager, never freed */
-
-static virClassPtr virHostdevManagerClass;
-static void virHostdevManagerDispose(void *obj);
-static virHostdevManagerPtr virHostdevManagerNew(void);
-
-struct virHostdevIsPCINodeDeviceUsedData {
-    virHostdevManagerPtr mgr;
-    const char *driverName;
-    const char *domainName;
-    bool usesVFIO;
-};
-
-/* This module makes heavy use of bookkeeping lists contained inside a
- * virHostdevManager instance to keep track of the devices' status. To make
- * it easy to spot potential ownership errors when moving devices from one
- * list to the other, variable names should comply with the following
- * conventions when it comes to virPCIDevice and virPCIDeviceList instances:
- *
- *   pci - a short-lived virPCIDevice whose purpose is usually just to look
- *         up the actual PCI device in one of the bookkeeping lists; basically
- *         little more than a fancy virPCIDeviceAddress
- *
- *   pcidevs - a list containing a bunch of the above
- *
- *   actual - a virPCIDevice instance that has either been retrieved from one
- *            of the bookkeeping lists, or is intended to be added or copied
- *            to one at some point
- *
- * Passing an 'actual' to a function that requires a 'pci' is fine, but the
- * opposite is usually not true; as a rule of thumb, functions in the virpci
- * module usually expect an 'actual'. Even with these conventions in place,
- * adding comments to highlight ownership-related issues is recommended */
-
-static int virHostdevIsPCINodeDeviceUsed(virPCIDeviceAddressPtr devAddr, void *opaque)
-{
-    virPCIDevicePtr actual;
-    struct virHostdevIsPCINodeDeviceUsedData *helperData = opaque;
-
-    actual = virPCIDeviceListFindByIDs(helperData->mgr->activePCIHostdevs,
-                                       devAddr->domain, devAddr->bus,
-                                       devAddr->slot, devAddr->function);
-    if (actual) {
-        const char *actual_drvname = NULL;
-        const char *actual_domname = NULL;
-        virPCIDeviceGetUsedBy(actual, &actual_drvname, &actual_domname);
-
-        if (helperData->usesVFIO &&
-            STREQ_NULLABLE(actual_drvname, helperData->driverName) &&
-            STREQ_NULLABLE(actual_domname, helperData->domainName))
-            goto iommu_owner;
-
-        if (actual_drvname && actual_domname)
-            virReportError(VIR_ERR_OPERATION_INVALID,
-                           _("PCI device %s is in use by "
-                             "driver %s, domain %s"),
-                           virPCIDeviceGetName(actual),
-                           actual_drvname, actual_domname);
-        else
-            virReportError(VIR_ERR_OPERATION_INVALID,
-                           _("PCI device %s is in use"),
-                           virPCIDeviceGetName(actual));
-        return -1;
-    }
- iommu_owner:
-    return 0;
-}
-
-static int virHostdevManagerOnceInit(void)
-{
-    if (!VIR_CLASS_NEW(virHostdevManager, virClassForObject()))
-        return -1;
-
-    if (!(manager = virHostdevManagerNew()))
-        return -1;
-
-    return 0;
-}
-
-VIR_ONCE_GLOBAL_INIT(virHostdevManager);
-
-static void
-virHostdevManagerDispose(void *obj)
-{
-    virHostdevManagerPtr hostdevMgr = obj;
-
-    virObjectUnref(hostdevMgr->activePCIHostdevs);
-    virObjectUnref(hostdevMgr->inactivePCIHostdevs);
-    virObjectUnref(hostdevMgr->activeUSBHostdevs);
-    virObjectUnref(hostdevMgr->activeSCSIHostdevs);
-    virObjectUnref(hostdevMgr->activeSCSIVHostHostdevs);
-    virObjectUnref(hostdevMgr->activeMediatedHostdevs);
-    virObjectUnref(hostdevMgr->activeNVMeHostdevs);
-    VIR_FREE(hostdevMgr->stateDir);
-}
-
-static virHostdevManagerPtr
-virHostdevManagerNew(void)
-{
-    g_autoptr(virHostdevManager) hostdevMgr = NULL;
-    bool privileged = geteuid() == 0;
-
-    if (!(hostdevMgr = virObjectNew(virHostdevManagerClass)))
-        return NULL;
-
-    if (!(hostdevMgr->activePCIHostdevs = virPCIDeviceListNew()))
-        return NULL;
-
-    if (!(hostdevMgr->activeUSBHostdevs = virUSBDeviceListNew()))
-        return NULL;
-
-    if (!(hostdevMgr->inactivePCIHostdevs = virPCIDeviceListNew()))
-        return NULL;
-
-    if (!(hostdevMgr->activeSCSIHostdevs = virSCSIDeviceListNew()))
-        return NULL;
-
-    if (!(hostdevMgr->activeSCSIVHostHostdevs = virSCSIVHostDeviceListNew()))
-        return NULL;
-
-    if (!(hostdevMgr->activeMediatedHostdevs = virMediatedDeviceListNew()))
-        return NULL;
-
-    if (!(hostdevMgr->activeNVMeHostdevs = virNVMeDeviceListNew()))
-        return NULL;
-
-    if (privileged) {
-        hostdevMgr->stateDir = g_strdup(HOSTDEV_STATE_DIR);
-
-        if (virFileMakePath(hostdevMgr->stateDir) < 0) {
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           _("Failed to create state dir '%s'"),
-                           hostdevMgr->stateDir);
-            return NULL;
-        }
-    } else {
-        g_autofree char *rundir = NULL;
-        mode_t old_umask;
-
-        rundir = virGetUserRuntimeDirectory();
-
-        hostdevMgr->stateDir = g_strdup_printf("%s/hostdevmgr", rundir);
-
-        old_umask = umask(077);
-
-        if (virFileMakePath(hostdevMgr->stateDir) < 0) {
-            umask(old_umask);
-            virReportError(VIR_ERR_OPERATION_FAILED,
-                           _("Failed to create state dir '%s'"),
-                           hostdevMgr->stateDir);
-            return NULL;
-        }
-        umask(old_umask);
-    }
-
-    return g_steal_pointer(&hostdevMgr);
-}
-
-virHostdevManagerPtr
-virHostdevManagerGetDefault(void)
-{
-    if (virHostdevManagerInitialize() < 0)
-        return NULL;
-
-    return virObjectRef(manager);
-}
-
-/**
- * virHostdevGetPCIHostDevice:
- * @hostdev: domain hostdev definition
- * @pci: returned PCI device
- *
- * For given @hostdev which represents a PCI device construct its
- * virPCIDevice representation and return it in @pci. If @hostdev
- * does not represent a PCI device then @pci is set to NULL and 0
- * is returned.
- *
- * Returns: 0 on success (@pci might be NULL though),
- *         -1 otherwise (with error reported).
- */
-static int
-virHostdevGetPCIHostDevice(const virDomainHostdevDef *hostdev,
-                           virPCIDevicePtr *pci)
-{
-    g_autoptr(virPCIDevice) actual = NULL;
-    const virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci;
-
-    *pci = NULL;
-
-    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
-        hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
-        return 0;
-
-    actual = virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
-                             pcisrc->addr.slot, pcisrc->addr.function);
-
-    if (!actual)
-        return -1;
-
-    virPCIDeviceSetManaged(actual, hostdev->managed);
-
-    if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
-        virPCIDeviceSetStubDriver(actual, VIR_PCI_STUB_DRIVER_VFIO);
-    } else if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN) {
-        virPCIDeviceSetStubDriver(actual, VIR_PCI_STUB_DRIVER_XEN);
-    } else {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("pci backend driver '%s' is not supported"),
-                       virDomainHostdevSubsysPCIBackendTypeToString(pcisrc->backend));
-        return -1;
-    }
-
-    *pci = g_steal_pointer(&actual);
-    return 0;
-}
-
-static virPCIDeviceListPtr
-virHostdevGetPCIHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
-{
-    g_autoptr(virPCIDeviceList) pcidevs = NULL;
-    size_t i;
-
-    if (!(pcidevs = virPCIDeviceListNew()))
-        return NULL;
-
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        g_autoptr(virPCIDevice) pci = NULL;
-
-        if (virHostdevGetPCIHostDevice(hostdev, &pci) < 0)
-            return NULL;
-
-        if (!pci)
-            continue;
-
-        if (virPCIDeviceListAdd(pcidevs, pci) < 0)
-            return NULL;
-        pci = NULL;
-    }
-
-    return g_steal_pointer(&pcidevs);
-}
-
-static int
-virHostdevPCISysfsPath(virDomainHostdevDefPtr hostdev,
-                       char **sysfs_path)
-{
-    virPCIDeviceAddress config_address;
-
-    config_address.domain = hostdev->source.subsys.u.pci.addr.domain;
-    config_address.bus = hostdev->source.subsys.u.pci.addr.bus;
-    config_address.slot = hostdev->source.subsys.u.pci.addr.slot;
-    config_address.function = hostdev->source.subsys.u.pci.addr.function;
-
-    return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
-}
-
-
-static int
-virHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
-{
-    g_autofree char *sysfs_path = NULL;
-
-    if (virHostdevPCISysfsPath(hostdev, &sysfs_path) < 0)
-        return -1;
-
-    return virPCIIsVirtualFunction(sysfs_path);
-}
-
-
-static int
-virHostdevNetDevice(virDomainHostdevDefPtr hostdev,
-                    int pfNetDevIdx,
-                    char **linkdev,
-                    int *vf)
-{
-    g_autofree char *sysfs_path = NULL;
-
-    if (virHostdevPCISysfsPath(hostdev, &sysfs_path) < 0)
-        return -1;
-
-    if (virPCIIsVirtualFunction(sysfs_path) == 1) {
-        if (virPCIGetVirtualFunctionInfo(sysfs_path, pfNetDevIdx,
-                                         linkdev, vf) < 0)
-            return -1;
-    } else {
-        /* In practice this should never happen, since we currently
-         * only support assigning SRIOV VFs via <interface
-         * type='hostdev'>, and it is only those devices that should
-         * end up calling this function.
-         */
-        if (virPCIGetNetName(sysfs_path, 0, NULL, linkdev) < 0)
-            return -1;
-
-        if (!(*linkdev)) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("The device at %s has no network device name"),
-                           sysfs_path);
-            return -1;
-        }
-
-        *vf = -1;
-    }
-
-    return 0;
-}
-
-
-static bool
-virHostdevIsPCINetDevice(const virDomainHostdevDef *hostdev)
-{
-    return hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
-        hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
-        hostdev->parentnet != NULL;
-}
-
-
-static int
-virHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
-                                   const virNetDevVPortProfile *virtPort,
-                                   const virMacAddr *macaddr,
-                                   const unsigned char *uuid,
-                                   bool associate)
-{
-    int ret = -1;
-
-    if (!virtPort)
-        return ret;
-
-    switch (virtPort->virtPortType) {
-    case VIR_NETDEV_VPORT_PROFILE_NONE:
-    case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
-    case VIR_NETDEV_VPORT_PROFILE_8021QBG:
-    case VIR_NETDEV_VPORT_PROFILE_LAST:
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("virtualport type %s is "
-                         "currently not supported on interfaces of type "
-                         "hostdev"),
-                       virNetDevVPortTypeToString(virtPort->virtPortType));
-        break;
-
-    case VIR_NETDEV_VPORT_PROFILE_8021QBH:
-        if (associate)
-            ret = virNetDevVPortProfileAssociate(NULL, virtPort, macaddr,
-                                                 linkdev, vf, uuid,
-                                                 VIR_NETDEV_VPORT_PROFILE_OP_CREATE, false);
-        else
-            ret = virNetDevVPortProfileDisassociate(NULL, virtPort,
-                                                    macaddr, linkdev, vf,
-                                                    VIR_NETDEV_VPORT_PROFILE_OP_DESTROY);
-        break;
-    }
-
-    return ret;
-}
-
-
-/**
- * virHostdevSaveNetConfig:
- * @hostdev: config object describing a hostdev device
- * @stateDir: directory to save device state into
- *
- * If the given hostdev device is an SRIOV network VF and *does not*
- * have a <virtualport> element (ie, it isn't being configured via
- * 802.11Qbh), determine its PF+VF#, and use that to save its current
- * "admin" MAC address and VF tag (the ones saved in the PF
- * driver).
- *
- * Returns 0 on success, -1 on failure.
- */
-static int
-virHostdevSaveNetConfig(virDomainHostdevDefPtr hostdev,
-                        const char *stateDir)
-{
-    g_autofree char *linkdev = NULL;
-    int vf = -1;
-
-    if (!virHostdevIsPCINetDevice(hostdev) ||
-        virDomainNetGetActualVirtPortProfile(hostdev->parentnet))
-       return 0;
-
-    if (virHostdevIsVirtualFunction(hostdev) != 1) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Interface type hostdev is currently supported on"
-                         " SR-IOV Virtual Functions only"));
-        return -1;
-    }
-
-    if (virHostdevNetDevice(hostdev, -1, &linkdev, &vf) < 0)
-        return -1;
-
-    if (virNetDevSaveNetConfig(linkdev, vf, stateDir, true) < 0)
-        return -1;
-
-    return 0;
-}
-
-
-/**
- * virHostdevSetNetConfig:
- * @hostdev: config object describing a hostdev device
- * @uuid: uuid of the domain
- *
- * If the given hostdev device is an SRIOV network VF, determine its
- * PF+VF#, and use that to set the "admin" MAC address and VF tag (the
- * ones saved in the PF driver).xs
- *
- * Returns 0 on success, -1 on failure.
- */
-static int
-virHostdevSetNetConfig(virDomainHostdevDefPtr hostdev,
-                       const unsigned char *uuid)
-{
-    g_autofree char *linkdev = NULL;
-    const virNetDevVlan *vlan;
-    const virNetDevVPortProfile *virtPort;
-    int vf = -1;
-    bool port_profile_associate = true;
-
-    if (!virHostdevIsPCINetDevice(hostdev))
-        return 0;
-
-    if (virHostdevNetDevice(hostdev, -1, &linkdev, &vf) < 0)
-        return -1;
-
-    vlan = virDomainNetGetActualVlan(hostdev->parentnet);
-    virtPort = virDomainNetGetActualVirtPortProfile(hostdev->parentnet);
-    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));
-            return -1;
-        }
-        if (virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
-                                               &hostdev->parentnet->mac,
-                                               uuid, port_profile_associate) < 0)
-            return -1;
-    } else {
-        if (virNetDevSetNetConfig(linkdev, vf, &hostdev->parentnet->mac,
-                                  vlan, NULL, true) < 0)
-            return -1;
-    }
-
-    return 0;
-}
-
-
-/* @oldStateDir:
- * For upgrade purpose:
- * To an existing VM on QEMU, the hostdev netconfig file is originally stored
- * in cfg->stateDir (/var/run/libvirt/qemu). Switch to new version, it uses new
- * location (mgr->stateDir) but certainly will not find it. In this
- * case, try to find in the old state dir.
- */
-static int
-virHostdevRestoreNetConfig(virDomainHostdevDefPtr hostdev,
-                           const char *stateDir,
-                           const char *oldStateDir)
-{
-    g_autofree char *linkdev = NULL;
-    g_autofree virMacAddrPtr MAC = NULL;
-    g_autofree virMacAddrPtr adminMAC = NULL;
-    g_autoptr(virNetDevVlan) vlan = NULL;
-    const virNetDevVPortProfile *virtPort;
-    int vf = -1;
-    bool port_profile_associate = false;
-
-
-    /* This is only needed for PCI devices that have been defined
-     * using <interface type='hostdev'>. For all others, it is a NOP.
-     */
-    if (!virHostdevIsPCINetDevice(hostdev))
-       return 0;
-
-    if (virHostdevIsVirtualFunction(hostdev) != 1) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                       _("Interface type hostdev is currently supported on"
-                         " SR-IOV Virtual Functions only"));
-        return -1;
-    }
-
-    if (virHostdevNetDevice(hostdev, 0, &linkdev, &vf) < 0)
-        return -1;
-
-    virtPort = virDomainNetGetActualVirtPortProfile(hostdev->parentnet);
-    if (virtPort) {
-        return virHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
-                                                  &hostdev->parentnet->mac,
-                                                  NULL,
-                                                  port_profile_associate);
-    } else {
-        /* we need to try 3 different places for the config file:
-         * 1) ${stateDir}/${PF}_vf${vf}
-         *    This is almost always where the saved config is
-         *
-         * 2) ${oldStateDir/${PF}_vf${vf}
-         *    saved config is only here if this machine was running a
-         *    (by now *very*) old version of libvirt that saved the
-         *    file in a different directory
-         *
-         * 3) ${stateDir}${PF[1]}_vf${VF}
-         *    PF[1] means "the netdev for port 2 of the PF device", and
-         *    is only valid when the PF is a Mellanox dual port NIC with
-         *    a VF that was created in "single port" mode.
-         *
-         *  NB: if virNetDevReadNetConfig() returns < 0, then it found
-         *  the file, but there was a problem, so we should
-         *  immediately return an error to our caller. If it returns
-         *  0, but all of the interesting stuff is NULL, that means
-         *  the file wasn't found, so we can/should check other
-         *  locations for it.
-         */
-
-        /* 1) standard location */
-        if (virNetDevReadNetConfig(linkdev, vf, stateDir,
-                                   &adminMAC, &vlan, &MAC) < 0) {
-            return -1;
-        }
-
-        /* 2) "old" (pre-1.2.3 circa 2014) location - whenever we get
-        *  to the point that nobody will ever upgrade directly from
-        *  1.2.3 (or older) directly to current libvirt, we can
-        *  eliminate this clause
-        **/
-        if (!(adminMAC || vlan || MAC) && oldStateDir &&
-            virNetDevReadNetConfig(linkdev, vf, oldStateDir,
-                                   &adminMAC, &vlan, &MAC) < 0) {
-            return -1;
-        }
-
-        /* 3) try using the PF's "port 2" netdev as the name of the
-         * config file
-         */
-        if (!(adminMAC || vlan || MAC)) {
-            VIR_FREE(linkdev);
-
-            if (virHostdevNetDevice(hostdev, 1, &linkdev, &vf) < 0 ||
-                virNetDevReadNetConfig(linkdev, vf, stateDir,
-                                       &adminMAC, &vlan, &MAC) < 0) {
-                return -1;
-            }
-        }
-
-        /* if a MAC was stored for the VF, we should now restore
-         * that as the adminMAC. We have to do it this way because
-         * the VF is still not bound to the host's net driver, so
-         * we can't directly set its MAC (and even after it is
-         * re-bound to the host net driver, it will still have its
-         * "administratively set" flag on, and that prohibits the
-         * VF's net driver from directly setting the MAC
-         * anyway). But it we set the desired VF MAC as the "admin
-         * MAC" *now*, then when the VF is re-bound to the host
-         * net driver (which will happen soon after returning from
-         * this function), that adminMAC will be set (by the PF)
-         * as the VF's new initial MAC.
-         *
-         * If no MAC was stored for the VF, that means it wasn't
-         * bound to a net driver before we used it anyway, so the
-         * adminMAC is all we have, and we can just restore it
-         * directly.
-         */
-        if (MAC) {
-            VIR_FREE(adminMAC);
-            adminMAC = MAC;
-            MAC = NULL;
-        }
-
-        ignore_value(virNetDevSetNetConfig(linkdev, vf,
-                                           adminMAC, vlan, MAC, true));
-        return 0;
-    }
-}
-
-static int
-virHostdevResetAllPCIDevices(virHostdevManagerPtr mgr,
-                             virPCIDeviceListPtr pcidevs)
-{
-    int ret = 0;
-    size_t i;
-
-    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
-        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
-
-        /* We can avoid looking up the actual device here, because performing
-         * a PCI reset on a device doesn't require any information other than
-         * the address, which 'pci' already contains */
-        VIR_DEBUG("Resetting PCI device %s", virPCIDeviceGetName(pci));
-        if (virPCIDeviceReset(pci, mgr->activePCIHostdevs,
-                              mgr->inactivePCIHostdevs) < 0) {
-            VIR_ERROR(_("Failed to reset PCI device: %s"),
-                      virGetLastErrorMessage());
-            ret = -1;
-        }
-    }
-
-    return ret;
-}
-
-static void
-virHostdevReattachAllPCIDevices(virHostdevManagerPtr mgr,
-                                virPCIDeviceListPtr pcidevs)
-{
-    size_t i;
-
-    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
-        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
-        virPCIDevicePtr actual;
-
-        /* We need to look up the actual device because that's what
-         * virPCIDeviceReattach() expects as its argument */
-        if (!(actual = virPCIDeviceListFind(mgr->inactivePCIHostdevs, pci)))
-            continue;
-
-        if (virPCIDeviceGetManaged(actual)) {
-            VIR_DEBUG("Reattaching managed PCI device %s",
-                      virPCIDeviceGetName(pci));
-            if (virPCIDeviceReattach(actual,
-                                     mgr->activePCIHostdevs,
-                                     mgr->inactivePCIHostdevs) < 0) {
-                VIR_ERROR(_("Failed to re-attach PCI device: %s"),
-                          virGetLastErrorMessage());
-            }
-        } else {
-            VIR_DEBUG("Not reattaching unmanaged PCI device %s",
-                      virPCIDeviceGetName(actual));
-        }
-    }
-}
-
-
-static int
-virHostdevPreparePCIDevicesImpl(virHostdevManagerPtr mgr,
-                                const char *drv_name,
-                                const char *dom_name,
-                                const unsigned char *uuid,
-                                virPCIDeviceListPtr pcidevs,
-                                virDomainHostdevDefPtr *hostdevs,
-                                int nhostdevs,
-                                unsigned int flags)
-{
-    int last_processed_hostdev_vf = -1;
-    size_t i;
-    int ret = -1;
-    virPCIDeviceAddressPtr devAddr = NULL;
-
-    virObjectLock(mgr->activePCIHostdevs);
-    virObjectLock(mgr->inactivePCIHostdevs);
-
-    /* Detaching devices from the host involves several steps; each
-     * of them is described at length below.
-     *
-     * 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 */
-
-    /* Step 1: Perform some initial checks on the devices */
-    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
-        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
-        bool strict_acs_check = !!(flags & VIR_HOSTDEV_STRICT_ACS_CHECK);
-        bool usesVFIO = (virPCIDeviceGetStubDriver(pci) == VIR_PCI_STUB_DRIVER_VFIO);
-        struct virHostdevIsPCINodeDeviceUsedData data = {mgr, drv_name, dom_name, false};
-        int hdrType = -1;
-
-        if (virPCIGetHeaderType(pci, &hdrType) < 0)
-            goto cleanup;
-
-        if (hdrType != VIR_PCI_HEADER_ENDPOINT) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("Non-endpoint PCI devices cannot be assigned "
-                             "to guests"));
-            goto cleanup;
-        }
-
-        if (!usesVFIO && !virPCIDeviceIsAssignable(pci, strict_acs_check)) {
-            virReportError(VIR_ERR_OPERATION_INVALID,
-                           _("PCI device %s is not assignable"),
-                           virPCIDeviceGetName(pci));
-            goto cleanup;
-        }
-
-        /* The device is in use by other active domain if
-         * the dev is in list activePCIHostdevs. */
-        devAddr = virPCIDeviceGetAddress(pci);
-        if (virHostdevIsPCINodeDeviceUsed(devAddr, &data))
-            goto cleanup;
-
-        /* VFIO devices belonging to same IOMMU group can't be
-         * shared across guests. Check if that's the case. */
-        if (usesVFIO) {
-            data.usesVFIO = true;
-            if (virPCIDeviceAddressIOMMUGroupIterate(devAddr,
-                                                     virHostdevIsPCINodeDeviceUsed,
-                                                     &data) < 0)
-                goto cleanup;
-        }
-    }
-
-    /* Step 1.5: For non-802.11Qbh SRIOV network devices, save the
-     * current device config
-     */
-    for (i = 0; i < nhostdevs; i++) {
-        if (virHostdevSaveNetConfig(hostdevs[i], mgr->stateDir) < 0)
-            goto cleanup;
-    }
-
-    /* Step 2: detach managed devices and make sure unmanaged devices
-     *         have already been taken care of */
-    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
-        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
-
-        if (virPCIDeviceGetManaged(pci)) {
-
-            /* We can't look up the actual device because it has not been
-             * created yet: virPCIDeviceDetach() will insert a copy of 'pci'
-             * into the list of inactive devices, and that copy will be the
-             * actual device going forward */
-            VIR_DEBUG("Detaching managed PCI device %s",
-                      virPCIDeviceGetName(pci));
-            if (virPCIDeviceDetach(pci,
-                                   mgr->activePCIHostdevs,
-                                   mgr->inactivePCIHostdevs) < 0)
-                goto reattachdevs;
-        } else {
-            g_autofree char *driverPath = NULL;
-            g_autofree char *driverName = NULL;
-            int stub;
-
-            /* Unmanaged devices should already have been marked as
-             * inactive: if that's the case, we can simply move on */
-            if (virPCIDeviceListFind(mgr->inactivePCIHostdevs, pci)) {
-                VIR_DEBUG("Not detaching unmanaged PCI device %s",
-                          virPCIDeviceGetName(pci));
-                continue;
-            }
-
-            /* If that's not the case, though, it might be because the
-             * daemon has been restarted, causing us to lose track of the
-             * device. Try and recover by marking the device as inactive
-             * if it happens to be bound to a known stub driver.
-             *
-             * FIXME Get rid of this once a proper way to keep track of
-             *       information about active / inactive device across
-             *       daemon restarts has been implemented */
-
-            if (virPCIDeviceGetDriverPathAndName(pci,
-                                                 &driverPath, &driverName) < 0)
-                goto reattachdevs;
-
-            stub = virPCIStubDriverTypeFromString(driverName);
-
-            if (stub > VIR_PCI_STUB_DRIVER_NONE &&
-                stub < VIR_PCI_STUB_DRIVER_LAST) {
-
-                /* The device is bound to a known stub driver: store this
-                 * information and add a copy to the inactive list */
-                virPCIDeviceSetStubDriver(pci, stub);
-
-                VIR_DEBUG("Adding PCI device %s to inactive list",
-                          virPCIDeviceGetName(pci));
-                if (virPCIDeviceListAddCopy(mgr->inactivePCIHostdevs, pci) < 0)
-                    goto reattachdevs;
-            } else {
-                virReportError(VIR_ERR_OPERATION_INVALID,
-                               _("Unmanaged PCI device %s must be manually "
-                                 "detached from the host"),
-                               virPCIDeviceGetName(pci));
-                goto reattachdevs;
-            }
-        }
-    }
-
-    /* At this point, all devices are attached to the stub driver and have
-     * been marked as inactive */
-
-    /* Step 3: Now that all the PCI hostdevs have been detached, we
-     * can safely reset them */
-    if (virHostdevResetAllPCIDevices(mgr, pcidevs) < 0)
-        goto reattachdevs;
-
-    /* Step 4: For SRIOV network devices, Now that we have detached the
-     * the network device, set the new netdev config */
-    for (i = 0; i < nhostdevs; i++) {
-
-        if (virHostdevSetNetConfig(hostdevs[i], uuid) < 0)
-            goto resetvfnetconfig;
-
-        last_processed_hostdev_vf = i;
-    }
-
-    /* Step 5: Move devices from the inactive list to the active list */
-    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
-        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
-        virPCIDevicePtr actual;
-
-        VIR_DEBUG("Removing PCI device %s from inactive list",
-                  virPCIDeviceGetName(pci));
-        actual = virPCIDeviceListSteal(mgr->inactivePCIHostdevs, pci);
-
-        VIR_DEBUG("Adding PCI device %s to active list",
-                  virPCIDeviceGetName(pci));
-        if (!actual || virPCIDeviceListAdd(mgr->activePCIHostdevs, actual) < 0)
-            goto inactivedevs;
-    }
-
-    /* Step 6: Set driver and domain information */
-    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
-        virPCIDevicePtr pci, actual;
-
-        /* We need to look up the actual device and set the information
-         * there because 'pci' only contain address information and will
-         * be released at the end of the function */
-        pci = virPCIDeviceListGet(pcidevs, i);
-        actual = virPCIDeviceListFind(mgr->activePCIHostdevs, pci);
-
-        VIR_DEBUG("Setting driver and domain information for PCI device %s",
-                  virPCIDeviceGetName(pci));
-        if (actual)
-            virPCIDeviceSetUsedBy(actual, drv_name, dom_name);
-    }
-
-    /* Step 7: Now set the original states for hostdev def */
-    for (i = 0; i < nhostdevs; i++) {
-        virPCIDevicePtr actual;
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
-
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
-            continue;
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
-            continue;
-
-        /* We need to look up the actual device because it's the one
-         * that contains the information we care about (unbind_from_stub,
-         * remove_slot, reprobe) */
-        actual = virPCIDeviceListFindByIDs(mgr->activePCIHostdevs,
-                                           pcisrc->addr.domain,
-                                           pcisrc->addr.bus,
-                                           pcisrc->addr.slot,
-                                           pcisrc->addr.function);
-
-        /* Appropriate values for the unbind_from_stub, remove_slot
-         * and reprobe properties of the device were set earlier
-         * by virPCIDeviceDetach() */
-        if (actual) {
-            VIR_DEBUG("Saving network configuration of PCI device %s",
-                      virPCIDeviceGetName(actual));
-            hostdev->origstates.states.pci.unbind_from_stub =
-                virPCIDeviceGetUnbindFromStub(actual);
-            hostdev->origstates.states.pci.remove_slot =
-                virPCIDeviceGetRemoveSlot(actual);
-            hostdev->origstates.states.pci.reprobe =
-                virPCIDeviceGetReprobe(actual);
-        }
-    }
-
-    ret = 0;
-    goto cleanup;
-
- inactivedevs:
-    /* Move devices back to the inactive list so that they can be
-     * processed properly below (reattachdevs label) */
-    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
-        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
-        virPCIDevicePtr actual;
-
-        VIR_DEBUG("Removing PCI device %s from active list",
-                  virPCIDeviceGetName(pci));
-        if (!(actual = virPCIDeviceListSteal(mgr->activePCIHostdevs, pci)))
-            continue;
-
-        VIR_DEBUG("Adding PCI device %s to inactive list",
-                  virPCIDeviceGetName(pci));
-        if (virPCIDeviceListAdd(mgr->inactivePCIHostdevs, actual) < 0)
-            VIR_WARN("Failed to add PCI device %s to the inactive list",
-                     virPCIDeviceGetName(pci));
-    }
-
- resetvfnetconfig:
-    if (last_processed_hostdev_vf >= 0) {
-        for (i = 0; i <= last_processed_hostdev_vf; i++)
-            virHostdevRestoreNetConfig(hostdevs[i], mgr->stateDir, NULL);
-    }
-
- reattachdevs:
-    virHostdevReattachAllPCIDevices(mgr, pcidevs);
-
- cleanup:
-    virObjectUnlock(mgr->activePCIHostdevs);
-    virObjectUnlock(mgr->inactivePCIHostdevs);
-
-    return ret;
-}
-
-
-int
-virHostdevPreparePCIDevices(virHostdevManagerPtr mgr,
-                            const char *drv_name,
-                            const char *dom_name,
-                            const unsigned char *uuid,
-                            virDomainHostdevDefPtr *hostdevs,
-                            int nhostdevs,
-                            unsigned int flags)
-{
-    g_autoptr(virPCIDeviceList) pcidevs = NULL;
-
-    if (!nhostdevs)
-        return 0;
-
-    if (!(pcidevs = virHostdevGetPCIHostDeviceList(hostdevs, nhostdevs)))
-        return -1;
-
-    return virHostdevPreparePCIDevicesImpl(mgr, drv_name, dom_name, uuid,
-                                           pcidevs, hostdevs, nhostdevs, flags);
-}
-
-
-static void
-virHostdevReAttachPCIDevicesImpl(virHostdevManagerPtr mgr,
-                                 const char *drv_name,
-                                 const char *dom_name,
-                                 virPCIDeviceListPtr pcidevs,
-                                 virDomainHostdevDefPtr *hostdevs,
-                                 int nhostdevs,
-                                 const char *oldStateDir)
-{
-    size_t i;
-
-    virObjectLock(mgr->activePCIHostdevs);
-    virObjectLock(mgr->inactivePCIHostdevs);
-
-    /* Reattaching devices to the host involves several steps; each
-     * of them is described at length below */
-
-    /* Step 1: Filter out all devices that are either not active or not
-     *         used by the current domain and driver */
-    i = 0;
-    while (i < virPCIDeviceListCount(pcidevs)) {
-        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
-        virPCIDevicePtr actual = NULL;
-
-        /* We need to look up the actual device, which is the one containing
-         * information such as by which domain and driver it is used. As a
-         * side effect, by looking it up we can also tell whether it was
-         * really active in the first place */
-        actual = virPCIDeviceListFind(mgr->activePCIHostdevs, pci);
-        if (actual) {
-            const char *actual_drvname;
-            const char *actual_domname;
-            virPCIDeviceGetUsedBy(actual, &actual_drvname, &actual_domname);
-            if (STRNEQ_NULLABLE(drv_name, actual_drvname) ||
-                STRNEQ_NULLABLE(dom_name, actual_domname)) {
-
-                virPCIDeviceListDel(pcidevs, pci);
-                continue;
-            }
-        } else {
-            virPCIDeviceListDel(pcidevs, pci);
-            continue;
-        }
-
-        i++;
-    }
-
-    /* Step 2: Move devices from the active list to the inactive list */
-    for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
-        virPCIDevicePtr pci = virPCIDeviceListGet(pcidevs, i);
-        virPCIDevicePtr actual;
-
-        VIR_DEBUG("Removing PCI device %s from active list",
-                  virPCIDeviceGetName(pci));
-        actual = virPCIDeviceListSteal(mgr->activePCIHostdevs, pci);
-
-        VIR_DEBUG("Adding PCI device %s to inactive list",
-                  virPCIDeviceGetName(pci));
-        if (!actual ||
-            virPCIDeviceListAdd(mgr->inactivePCIHostdevs, actual) < 0) {
-
-            VIR_ERROR(_("Failed to add PCI device %s to the inactive list"),
-                      virGetLastErrorMessage());
-            virResetLastError();
-        }
-    }
-
-    /* At this point, any device that had been used by the guest has been
-     * moved to the inactive list */
-
-    /* Step 3: restore original network config of hostdevs that used
-     * <interface type='hostdev'>
-     */
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-
-        if (virHostdevIsPCINetDevice(hostdev)) {
-            virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
-            virPCIDevicePtr actual;
-
-            actual = virPCIDeviceListFindByIDs(mgr->inactivePCIHostdevs,
-                                               pcisrc->addr.domain,
-                                               pcisrc->addr.bus,
-                                               pcisrc->addr.slot,
-                                               pcisrc->addr.function);
-
-            if (actual) {
-                VIR_DEBUG("Restoring network configuration of PCI device %s",
-                          virPCIDeviceGetName(actual));
-                virHostdevRestoreNetConfig(hostdev, mgr->stateDir,
-                                           oldStateDir);
-            }
-        }
-    }
-
-    /* Step 4: perform a PCI Reset on all devices */
-    virHostdevResetAllPCIDevices(mgr, pcidevs);
-
-    /* Step 5: Reattach managed devices to their host drivers; unmanaged
-     *         devices don't need to be processed further */
-    virHostdevReattachAllPCIDevices(mgr, pcidevs);
-
-    virObjectUnlock(mgr->activePCIHostdevs);
-    virObjectUnlock(mgr->inactivePCIHostdevs);
-}
-
-
-/* @oldStateDir:
- * For upgrade purpose: see virHostdevRestoreNetConfig
- */
-void
-virHostdevReAttachPCIDevices(virHostdevManagerPtr mgr,
-                             const char *drv_name,
-                             const char *dom_name,
-                             virDomainHostdevDefPtr *hostdevs,
-                             int nhostdevs,
-                             const char *oldStateDir)
-{
-    g_autoptr(virPCIDeviceList) pcidevs = NULL;
-
-    if (!nhostdevs)
-        return;
-
-    if (!(pcidevs = virHostdevGetPCIHostDeviceList(hostdevs, nhostdevs))) {
-        VIR_ERROR(_("Failed to allocate PCI device list: %s"),
-                  virGetLastErrorMessage());
-        virResetLastError();
-        return;
-    }
-
-    virHostdevReAttachPCIDevicesImpl(mgr, drv_name, dom_name, pcidevs,
-                                     hostdevs, nhostdevs, oldStateDir);
-}
-
-
-int
-virHostdevUpdateActivePCIDevices(virHostdevManagerPtr mgr,
-                                 virDomainHostdevDefPtr *hostdevs,
-                                 int nhostdevs,
-                                 const char *drv_name,
-                                 const char *dom_name)
-{
-    size_t i;
-    int ret = -1;
-
-    if (!nhostdevs)
-        return 0;
-
-    virObjectLock(mgr->activePCIHostdevs);
-    virObjectLock(mgr->inactivePCIHostdevs);
-
-    for (i = 0; i < nhostdevs; i++) {
-        const virDomainHostdevDef *hostdev = hostdevs[i];
-        g_autoptr(virPCIDevice) actual = NULL;
-
-        if (virHostdevGetPCIHostDevice(hostdev, &actual) < 0)
-            goto cleanup;
-
-        if (!actual)
-            continue;
-
-        if (virPCIDeviceSetUsedBy(actual, drv_name, dom_name) < 0)
-            goto cleanup;
-
-        /* Setup the original states for the PCI device */
-        virPCIDeviceSetUnbindFromStub(actual, hostdev->origstates.states.pci.unbind_from_stub);
-        virPCIDeviceSetRemoveSlot(actual, hostdev->origstates.states.pci.remove_slot);
-        virPCIDeviceSetReprobe(actual, hostdev->origstates.states.pci.reprobe);
-
-        if (virPCIDeviceListAdd(mgr->activePCIHostdevs, actual) < 0)
-            goto cleanup;
-        actual = NULL;
-    }
-
-    ret = 0;
- cleanup:
-    virObjectUnlock(mgr->activePCIHostdevs);
-    virObjectUnlock(mgr->inactivePCIHostdevs);
-    return ret;
-}
-
-int
-virHostdevUpdateActiveUSBDevices(virHostdevManagerPtr mgr,
-                                 virDomainHostdevDefPtr *hostdevs,
-                                 int nhostdevs,
-                                 const char *drv_name,
-                                 const char *dom_name)
-{
-    virDomainHostdevDefPtr hostdev = NULL;
-    size_t i;
-    int ret = -1;
-
-    if (!nhostdevs)
-        return 0;
-
-    virObjectLock(mgr->activeUSBHostdevs);
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevSubsysUSBPtr usbsrc;
-        g_autoptr(virUSBDevice) usb = NULL;
-        hostdev = hostdevs[i];
-        usbsrc = &hostdev->source.subsys.u.usb;
-
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
-            continue;
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
-            continue;
-
-        if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL))) {
-            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
-                     usbsrc->bus, usbsrc->device, dom_name);
-            continue;
-        }
-
-        virUSBDeviceSetUsedBy(usb, drv_name, dom_name);
-
-        if (virUSBDeviceListAdd(mgr->activeUSBHostdevs, &usb) < 0)
-            goto cleanup;
-        usb = NULL;
-    }
-    ret = 0;
- cleanup:
-    virObjectUnlock(mgr->activeUSBHostdevs);
-    return ret;
-}
-
-static int
-virHostdevUpdateActiveSCSIHostDevices(virHostdevManagerPtr mgr,
-                                      virDomainHostdevDefPtr hostdev,
-                                      virDomainHostdevSubsysSCSIPtr scsisrc,
-                                      const char *drv_name,
-                                      const char *dom_name)
-{
-    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
-    g_autoptr(virSCSIDevice) scsi = NULL;
-    virSCSIDevicePtr tmp = NULL;
-
-    if (!(scsi = virSCSIDeviceNew(NULL,
-                                  scsihostsrc->adapter, scsihostsrc->bus,
-                                  scsihostsrc->target, scsihostsrc->unit,
-                                  hostdev->readonly, hostdev->shareable)))
-        return -1;
-
-    if ((tmp = virSCSIDeviceListFind(mgr->activeSCSIHostdevs, scsi))) {
-        if (virSCSIDeviceSetUsedBy(tmp, drv_name, dom_name) < 0)
-            return -1;
-    } else {
-        if (virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name) < 0 ||
-            virSCSIDeviceListAdd(mgr->activeSCSIHostdevs, scsi) < 0)
-            return -1;
-        scsi = NULL;
-    }
-    return 0;
-}
-
-int
-virHostdevUpdateActiveSCSIDevices(virHostdevManagerPtr mgr,
-                                  virDomainHostdevDefPtr *hostdevs,
-                                  int nhostdevs,
-                                  const char *drv_name,
-                                  const char *dom_name)
-{
-    virDomainHostdevDefPtr hostdev = NULL;
-    size_t i;
-    int ret = -1;
-
-    if (!nhostdevs)
-        return 0;
-
-    virObjectLock(mgr->activeSCSIHostdevs);
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevSubsysSCSIPtr scsisrc;
-        hostdev = hostdevs[i];
-        scsisrc = &hostdev->source.subsys.u.scsi;
-
-        if (!virHostdevIsSCSIDevice(hostdev))
-            continue;
-
-        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
-            continue;  /* Not supported for iSCSI */
-        } else {
-            if (virHostdevUpdateActiveSCSIHostDevices(mgr, hostdev, scsisrc,
-                                                      drv_name, dom_name) < 0)
-                goto cleanup;
-        }
-    }
-    ret = 0;
-
- cleanup:
-    virObjectUnlock(mgr->activeSCSIHostdevs);
-    return ret;
-}
-
-
-int
-virHostdevUpdateActiveMediatedDevices(virHostdevManagerPtr mgr,
-                                      virDomainHostdevDefPtr *hostdevs,
-                                      int nhostdevs,
-                                      const char *drv_name,
-                                      const char *dom_name)
-{
-    int ret = -1;
-    size_t i;
-    g_autoptr(virMediatedDevice) mdev = NULL;
-
-    if (nhostdevs == 0)
-        return 0;
-
-    virObjectLock(mgr->activeMediatedHostdevs);
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        virDomainHostdevSubsysMediatedDevPtr mdevsrc;
-
-        mdevsrc = &hostdev->source.subsys.u.mdev;
-
-        if (!virHostdevIsMdevDevice(hostdev))
-            continue;
-
-        if (!(mdev = virMediatedDeviceNew(mdevsrc->uuidstr, mdevsrc->model)))
-            goto cleanup;
-
-        virMediatedDeviceSetUsedBy(mdev, drv_name, dom_name);
-
-        if (virMediatedDeviceListAdd(mgr->activeMediatedHostdevs, &mdev) < 0)
-            goto cleanup;
-    }
-
-    ret = 0;
- cleanup:
-    virObjectUnlock(mgr->activeMediatedHostdevs);
-    return ret;
-}
-
-
-static int
-virHostdevMarkUSBDevices(virHostdevManagerPtr mgr,
-                         const char *drv_name,
-                         const char *dom_name,
-                         virUSBDeviceListPtr list)
-{
-    size_t i, j;
-    unsigned int count;
-    virUSBDevicePtr tmp;
-
-    virObjectLock(mgr->activeUSBHostdevs);
-    count = virUSBDeviceListCount(list);
-
-    for (i = 0; i < count; i++) {
-        virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
-        if ((tmp = virUSBDeviceListFind(mgr->activeUSBHostdevs, usb))) {
-            const char *other_drvname;
-            const char *other_domname;
-
-            virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_domname);
-            if (other_drvname && other_domname)
-                virReportError(VIR_ERR_OPERATION_INVALID,
-                               _("USB device %s is in use by "
-                                 "driver %s, domain %s"),
-                               virUSBDeviceGetName(tmp),
-                               other_drvname, other_domname);
-            else
-                virReportError(VIR_ERR_OPERATION_INVALID,
-                               _("USB device %s is already in use"),
-                               virUSBDeviceGetName(tmp));
-            goto error;
-        }
-
-        virUSBDeviceSetUsedBy(usb, drv_name, dom_name);
-        VIR_DEBUG("Adding %03d.%03d dom=%s to activeUSBHostdevs",
-                  virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb),
-                  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
-virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
-                        bool mandatory,
-                        virUSBDevicePtr *usb)
-{
-    virDomainHostdevSubsysUSBPtr usbsrc = &hostdev->source.subsys.u.usb;
-    unsigned vendor = usbsrc->vendor;
-    unsigned product = usbsrc->product;
-    unsigned bus = usbsrc->bus;
-    unsigned device = usbsrc->device;
-    bool autoAddress = usbsrc->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) {
-        g_autoptr(virUSBDeviceList) devs = NULL;
-
-        rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
-        if (rc < 0) {
-            return -1;
-        } else 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;
-        }
-
-        *usb = virUSBDeviceListGet(devs, 0);
-        virUSBDeviceListSteal(devs, *usb);
-
-        usbsrc->bus = virUSBDeviceGetBus(*usb);
-        usbsrc->device = virUSBDeviceGetDevno(*usb);
-        usbsrc->autoAddress = true;
-
-        if (autoAddress) {
-            VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
-                     " from bus:%u device:%u)",
-                     vendor, product,
-                     usbsrc->bus, usbsrc->device,
-                     bus, device);
-        }
-    } else if (!vendor && bus) {
-        if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
-            return -1;
-    }
-
- out:
-    if (!*usb)
-        hostdev->missing = true;
-    return 0;
-}
-
-int
-virHostdevPrepareUSBDevices(virHostdevManagerPtr mgr,
-                            const char *drv_name,
-                            const char *dom_name,
-                            virDomainHostdevDefPtr *hostdevs,
-                            int nhostdevs,
-                            unsigned int flags)
-{
-    size_t i;
-    g_autoptr(virUSBDeviceList) list = NULL;
-    virUSBDevicePtr tmp;
-    bool coldBoot = !!(flags & VIR_HOSTDEV_COLD_BOOT);
-
-    if (!nhostdevs)
-        return 0;
-
-    /* To prevent situation where USB device is assigned to two domains
-     * we need to keep a list of currently assigned USB devices.
-     * This is done in several loops which cannot be joined into one big
-     * loop. See virHostdevPreparePCIDevices()
-     */
-    if (!(list = virUSBDeviceListNew()))
-        return -1;
-
-    /* Loop 1: build temporary list
-     */
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        bool required = true;
-        g_autoptr(virUSBDevice) usb = NULL;
-
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
-            continue;
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
-            continue;
-
-        if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
-            (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
-             !coldBoot))
-            required = false;
-
-        if (virHostdevFindUSBDevice(hostdev, required, &usb) < 0)
-            return -1;
-
-        if (usb && virUSBDeviceListAdd(list, &usb) < 0)
-            return -1;
-        usb = NULL;
-    }
-
-    /* Mark devices in temporary list as used by @dom_name
-     * and add them do driver list. However, if something goes
-     * wrong, perform rollback.
-     */
-    if (virHostdevMarkUSBDevices(mgr, drv_name, dom_name, list) < 0)
-        return -1;
-
-    /* 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);
-    }
-
-    return 0;
-}
-
-static int
-virHostdevPrepareSCSIHostDevices(virDomainHostdevDefPtr hostdev,
-                                 virDomainHostdevSubsysSCSIPtr scsisrc,
-                                 virSCSIDeviceListPtr list)
-{
-    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
-    g_autoptr(virSCSIDevice) scsi = NULL;
-
-    if (hostdev->managed) {
-        virReportError(VIR_ERR_XML_ERROR, "%s",
-                       _("SCSI host device doesn't support managed mode"));
-        return -1;
-    }
-
-    if (!(scsi = virSCSIDeviceNew(NULL,
-                                  scsihostsrc->adapter, scsihostsrc->bus,
-                                  scsihostsrc->target, scsihostsrc->unit,
-                                  hostdev->readonly, hostdev->shareable)))
-        return -1;
-
-    if (virSCSIDeviceListAdd(list, scsi) < 0)
-        return -1;
-    scsi = NULL;
-
-    return 0;
-}
-
-int
-virHostdevPrepareSCSIDevices(virHostdevManagerPtr mgr,
-                             const char *drv_name,
-                             const char *dom_name,
-                             virDomainHostdevDefPtr *hostdevs,
-                             int nhostdevs)
-{
-    size_t i, j;
-    int count;
-    g_autoptr(virSCSIDeviceList) list = NULL;
-    virSCSIDevicePtr tmp;
-
-    if (!nhostdevs)
-        return 0;
-
-    /* To prevent situation where SCSI device is assigned to two domains
-     * we need to keep a list of currently assigned SCSI devices.
-     * This is done in several loops which cannot be joined into one big
-     * loop. See virHostdevPreparePCIDevices()
-     */
-    if (!(list = virSCSIDeviceListNew()))
-        return -1;
-
-    /* Loop 1: build temporary list */
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
-
-        if (!virHostdevIsSCSIDevice(hostdev))
-            continue;
-
-        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI) {
-            continue;  /* Not supported for iSCSI */
-        } else {
-            if (virHostdevPrepareSCSIHostDevices(hostdev, scsisrc, list) < 0)
-                return -1;
-        }
-    }
-
-    /* Loop 2: Mark devices in temporary list as used by @name
-     * and add them to driver list. However, if something goes
-     * wrong, perform rollback.
-     */
-    virObjectLock(mgr->activeSCSIHostdevs);
-    count = virSCSIDeviceListCount(list);
-
-    for (i = 0; i < count; i++) {
-        virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
-        if ((tmp = virSCSIDeviceListFind(mgr->activeSCSIHostdevs,
-                                         scsi))) {
-            bool scsi_shareable = virSCSIDeviceGetShareable(scsi);
-            bool tmp_shareable = virSCSIDeviceGetShareable(tmp);
-
-            if (!(scsi_shareable && tmp_shareable)) {
-                virReportError(VIR_ERR_OPERATION_INVALID,
-                               _("SCSI device %s is already in use by "
-                                 "other domain(s) as '%s'"),
-                               virSCSIDeviceGetName(tmp),
-                               tmp_shareable ? "shareable" : "non-shareable");
-                goto error;
-            }
-
-            if (virSCSIDeviceSetUsedBy(tmp, drv_name, dom_name) < 0)
-                goto error;
-        } else {
-            if (virSCSIDeviceSetUsedBy(scsi, drv_name, dom_name) < 0)
-                goto error;
-
-            VIR_DEBUG("Adding %s to activeSCSIHostdevs", virSCSIDeviceGetName(scsi));
-
-            if (virSCSIDeviceListAdd(mgr->activeSCSIHostdevs, scsi) < 0)
-                goto error;
-        }
-    }
-
-    virObjectUnlock(mgr->activeSCSIHostdevs);
-
-    /* Loop 3: Temporary list was successfully merged with
-     * driver list, so steal all items to avoid freeing them
-     * when freeing temporary list.
-     */
-    while (virSCSIDeviceListCount(list) > 0) {
-        tmp = virSCSIDeviceListGet(list, 0);
-        virSCSIDeviceListSteal(list, tmp);
-    }
-
-    return 0;
-
- error:
-    for (j = 0; j < i; j++) {
-        tmp = virSCSIDeviceListGet(list, i);
-        virSCSIDeviceListSteal(mgr->activeSCSIHostdevs, tmp);
-    }
-    virObjectUnlock(mgr->activeSCSIHostdevs);
-    return -1;
-}
-
-int
-virHostdevPrepareSCSIVHostDevices(virHostdevManagerPtr mgr,
-                                  const char *drv_name,
-                                  const char *dom_name,
-                                  virDomainHostdevDefPtr *hostdevs,
-                                  int nhostdevs)
-{
-    g_autoptr(virSCSIVHostDeviceList) list = NULL;
-    virSCSIVHostDevicePtr tmp;
-    size_t i, j;
-
-    if (!nhostdevs)
-        return 0;
-
-    /* To prevent situation where scsi_host device is assigned to two domains
-     * we need to keep a list of currently assigned scsi_host devices.
-     * This is done in several loops which cannot be joined into one big
-     * loop. See virHostdevPreparePCIDevices()
-     */
-    if (!(list = virSCSIVHostDeviceListNew()))
-        return -1;
-
-    /* Loop 1: build temporary list */
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        virDomainHostdevSubsysSCSIVHostPtr hostsrc = &hostdev->source.subsys.u.scsi_host;
-        g_autoptr(virSCSIVHostDevice) host = NULL;
-
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
-            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST)
-            continue;
-
-        if (hostsrc->protocol != VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST)
-            continue;  /* Not supported */
-
-        if (!(host = virSCSIVHostDeviceNew(hostsrc->wwpn)))
-            return -1;
-
-        if (virSCSIVHostDeviceSetUsedBy(host, drv_name, dom_name) < 0)
-            return -1;
-
-        if (virSCSIVHostDeviceListAdd(list, host) < 0)
-            return -1;
-        host = NULL;
-    }
-
-    /* Loop 2: Mark devices in temporary list as used by @name
-     * and add them to driver list. However, if something goes
-     * wrong, perform rollback.
-     */
-    virObjectLock(mgr->activeSCSIVHostHostdevs);
-
-    for (i = 0; i < virSCSIVHostDeviceListCount(list); i++) {
-        tmp = virSCSIVHostDeviceListGet(list, i);
-
-        VIR_DEBUG("Adding %s to activeSCSIVHostHostdevs",
-                  virSCSIVHostDeviceGetName(tmp));
-
-        if (virSCSIVHostDeviceListAdd(mgr->activeSCSIVHostHostdevs, tmp) < 0)
-            goto rollback;
-    }
-
-    virObjectUnlock(mgr->activeSCSIVHostHostdevs);
-
-    /* Loop 3: Temporary list was successfully merged with
-     * driver list, so steal all items to avoid freeing them
-     * when freeing temporary list.
-     */
-    while (virSCSIVHostDeviceListCount(list) > 0) {
-        tmp = virSCSIVHostDeviceListGet(list, 0);
-        virSCSIVHostDeviceListSteal(list, tmp);
-    }
-
-    return 0;
-
- rollback:
-    for (j = 0; j < i; j++) {
-        tmp = virSCSIVHostDeviceListGet(list, i);
-        virSCSIVHostDeviceListSteal(mgr->activeSCSIVHostHostdevs, tmp);
-    }
-    virObjectUnlock(mgr->activeSCSIVHostHostdevs);
-    return -1;
-}
-
-
-int
-virHostdevPrepareMediatedDevices(virHostdevManagerPtr mgr,
-                                 const char *drv_name,
-                                 const char *dom_name,
-                                 virDomainHostdevDefPtr *hostdevs,
-                                 int nhostdevs)
-{
-    size_t i;
-    g_autoptr(virMediatedDeviceList) list = NULL;
-
-    if (!nhostdevs)
-        return 0;
-
-    /* To prevent situation where mediated device is assigned to multiple
-     * domains we maintain a driver list of currently assigned mediated devices.
-     * A device is appended to the driver list after a series of preparations.
-     */
-    if (!(list = virMediatedDeviceListNew()))
-        return -1;
-
-    /* Loop 1: Build a temporary list of ALL mediated devices. */
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        virDomainHostdevSubsysMediatedDevPtr src = &hostdev->source.subsys.u.mdev;
-        g_autoptr(virMediatedDevice) mdev = NULL;
-
-        if (!virHostdevIsMdevDevice(hostdev))
-            continue;
-
-        if (!(mdev = virMediatedDeviceNew(src->uuidstr, src->model)))
-            return -1;
-
-        if (virMediatedDeviceListAdd(list, &mdev) < 0)
-            return -1;
-        mdev = NULL;
-    }
-
-    /* Mark the devices in the list as used by @drv_name-@dom_name and copy the
-     * references to the driver list
-     */
-    if (virMediatedDeviceListMarkDevices(mgr->activeMediatedHostdevs,
-                                         list, drv_name, dom_name) < 0)
-        return -1;
-
-    /* Loop 2: Temporary list was successfully merged with
-     * driver list, so steal all items to avoid freeing them
-     * in cleanup label.
-     */
-    while (virMediatedDeviceListCount(list) > 0) {
-        virMediatedDevicePtr tmp = virMediatedDeviceListGet(list, 0);
-        virMediatedDeviceListSteal(list, tmp);
-    }
-
-    return 0;
-}
-
-void
-virHostdevReAttachUSBDevices(virHostdevManagerPtr mgr,
-                             const char *drv_name,
-                             const char *dom_name,
-                             virDomainHostdevDefPtr *hostdevs,
-                             int nhostdevs)
-{
-    size_t i;
-
-    if (!nhostdevs)
-        return;
-
-    virObjectLock(mgr->activeUSBHostdevs);
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        virDomainHostdevSubsysUSBPtr usbsrc = &hostdev->source.subsys.u.usb;
-        g_autoptr(virUSBDevice) usb = NULL;
-        virUSBDevicePtr tmp;
-        const char *usedby_drvname;
-        const char *usedby_domname;
-
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
-            continue;
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
-            continue;
-        if (hostdev->missing)
-            continue;
-
-        if (!(usb = virUSBDeviceNew(usbsrc->bus, usbsrc->device, NULL))) {
-            VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
-                     usbsrc->bus, usbsrc->device, NULLSTR(dom_name));
-            continue;
-        }
-
-        /* Delete only those USB devices which belongs
-         * to domain @name because qemuProcessStart() might
-         * have failed because USB device is already taken.
-         * Therefore we want to steal only those devices from
-         * the list which were taken by @name */
-
-        tmp = virUSBDeviceListFind(mgr->activeUSBHostdevs, usb);
-
-        if (!tmp) {
-            VIR_WARN("Unable to find device %03d.%03d "
-                     "in list of active USB devices",
-                     usbsrc->bus, usbsrc->device);
-            continue;
-        }
-
-        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 from activeUSBHostdevs",
-                      usbsrc->bus, usbsrc->device, dom_name);
-            virUSBDeviceListDel(mgr->activeUSBHostdevs, tmp);
-        }
-    }
-    virObjectUnlock(mgr->activeUSBHostdevs);
-}
-
-static void
-virHostdevReAttachSCSIHostDevices(virHostdevManagerPtr mgr,
-                                  virDomainHostdevDefPtr hostdev,
-                                  virDomainHostdevSubsysSCSIPtr scsisrc,
-                                  const char *drv_name,
-                                  const char *dom_name)
-{
-    virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
-    g_autoptr(virSCSIDevice) scsi = NULL;
-    virSCSIDevicePtr tmp;
-
-    if (!(scsi = virSCSIDeviceNew(NULL,
-                                  scsihostsrc->adapter, scsihostsrc->bus,
-                                  scsihostsrc->target, scsihostsrc->unit,
-                                  hostdev->readonly, hostdev->shareable))) {
-        VIR_WARN("Unable to reattach SCSI device %s:%u:%u:%llu on domain %s",
-                 scsihostsrc->adapter, scsihostsrc->bus, scsihostsrc->target,
-                 scsihostsrc->unit, dom_name);
-        return;
-    }
-
-    /* Only delete the devices which are marked as being used by @name,
-     * because qemuProcessStart could fail half way through. */
-
-    if (!(tmp = virSCSIDeviceListFind(mgr->activeSCSIHostdevs, scsi))) {
-        VIR_WARN("Unable to find device %s:%u:%u:%llu "
-                 "in list of active SCSI devices",
-                 scsihostsrc->adapter, scsihostsrc->bus,
-                 scsihostsrc->target, scsihostsrc->unit);
-        return;
-    }
-
-    VIR_DEBUG("Removing %s:%u:%u:%llu dom=%s from activeSCSIHostdevs",
-              scsihostsrc->adapter, scsihostsrc->bus, scsihostsrc->target,
-              scsihostsrc->unit, dom_name);
-
-    virSCSIDeviceListDel(mgr->activeSCSIHostdevs, tmp,
-                         drv_name, dom_name);
-}
-
-void
-virHostdevReAttachSCSIDevices(virHostdevManagerPtr mgr,
-                              const char *drv_name,
-                              const char *dom_name,
-                              virDomainHostdevDefPtr *hostdevs,
-                              int nhostdevs)
-{
-    size_t i;
-
-    if (!nhostdevs)
-        return;
-
-    virObjectLock(mgr->activeSCSIHostdevs);
-    for (i = 0; i < nhostdevs; i++) {
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
-
-        if (!virHostdevIsSCSIDevice(hostdev))
-            continue;
-
-        if (scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
-            continue; /* Not supported for iSCSI */
-        else
-            virHostdevReAttachSCSIHostDevices(mgr, hostdev, scsisrc,
-                                              drv_name, dom_name);
-    }
-    virObjectUnlock(mgr->activeSCSIHostdevs);
-}
-
-void
-virHostdevReAttachSCSIVHostDevices(virHostdevManagerPtr mgr,
-                                   const char *drv_name,
-                                   const char *dom_name,
-                                   virDomainHostdevDefPtr *hostdevs,
-                                   int nhostdevs)
-{
-    size_t i;
-
-    if (!nhostdevs)
-        return;
-
-    virObjectLock(mgr->activeSCSIVHostHostdevs);
-    for (i = 0; i < nhostdevs; i++) {
-        g_autoptr(virSCSIVHostDevice) host = NULL;
-        virSCSIVHostDevicePtr tmp;
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-        virDomainHostdevSubsysSCSIVHostPtr hostsrc = &hostdev->source.subsys.u.scsi_host;
-        const char *usedby_drvname;
-        const char *usedby_domname;
-
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
-            hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST)
-            continue;
-
-        if (hostsrc->protocol != VIR_DOMAIN_HOSTDEV_SUBSYS_SCSI_HOST_PROTOCOL_TYPE_VHOST)
-            continue; /* Not supported */
-
-        if (!(host = virSCSIVHostDeviceNew(hostsrc->wwpn))) {
-            VIR_WARN("Unable to reattach SCSI_host device %s on domain %s",
-                     hostsrc->wwpn, NULLSTR(dom_name));
-            virObjectUnlock(mgr->activeSCSIVHostHostdevs);
-            return;
-        }
-
-        /* Only delete the devices which are marked as being used by @name,
-         * because qemuProcessStart could fail half way through. */
-
-        if (!(tmp = virSCSIVHostDeviceListFind(mgr->activeSCSIVHostHostdevs,
-                                               host))) {
-            VIR_WARN("Unable to find device %s "
-                     "in list of active SCSI_host devices",
-                     hostsrc->wwpn);
-            virObjectUnlock(mgr->activeSCSIVHostHostdevs);
-            return;
-        }
-
-        virSCSIVHostDeviceGetUsedBy(tmp, &usedby_drvname, &usedby_domname);
-
-        if (STREQ_NULLABLE(drv_name, usedby_drvname) &&
-            STREQ_NULLABLE(dom_name, usedby_domname)) {
-            VIR_DEBUG("Removing %s dom=%s from activeSCSIVHostHostdevs",
-                      hostsrc->wwpn, dom_name);
-
-            virSCSIVHostDeviceListDel(mgr->activeSCSIVHostHostdevs, tmp);
-        }
-    }
-    virObjectUnlock(mgr->activeSCSIVHostHostdevs);
-}
-
-/* TODO: Rename this function along with all virHostdevReAttach* functions that
- * have nothing to do with an explicit re-attachment of a device back to the
- * host driver (like PCI).
- * Despite what the function name suggests, there's nothing to be re-attached
- * for mediated devices, the function merely removes a mediated device from the
- * list of active host devices.
- */
-void
-virHostdevReAttachMediatedDevices(virHostdevManagerPtr mgr,
-                                  const char *drv_name,
-                                  const char *dom_name,
-                                  virDomainHostdevDefPtr *hostdevs,
-                                  int nhostdevs)
-{
-    const char *used_by_drvname = NULL;
-    const char *used_by_domname = NULL;
-    size_t i;
-
-    if (nhostdevs == 0)
-        return;
-
-    virObjectLock(mgr->activeMediatedHostdevs);
-    for (i = 0; i < nhostdevs; i++) {
-        g_autoptr(virMediatedDevice) mdev = NULL;
-        virMediatedDevicePtr tmp;
-        virDomainHostdevSubsysMediatedDevPtr mdevsrc;
-        virDomainHostdevDefPtr hostdev = hostdevs[i];
-
-        mdevsrc = &hostdev->source.subsys.u.mdev;
-
-        if (!virHostdevIsMdevDevice(hostdev))
-            continue;
-
-        if (!(mdev = virMediatedDeviceNew(mdevsrc->uuidstr,
-                                          mdevsrc->model)))
-            continue;
-
-        /* Remove from the list only mdevs assigned to @drv_name/@dom_name */
-
-        tmp = virMediatedDeviceListFind(mgr->activeMediatedHostdevs, mdev);
-
-        /* skip inactive devices */
-        if (!tmp)
-            continue;
-
-        virMediatedDeviceGetUsedBy(tmp, &used_by_drvname, &used_by_domname);
-        if (STREQ_NULLABLE(drv_name, used_by_drvname) &&
-            STREQ_NULLABLE(dom_name, used_by_domname)) {
-            VIR_DEBUG("Removing %s dom=%s from activeMediatedHostdevs",
-                      mdevsrc->uuidstr, dom_name);
-            virMediatedDeviceListDel(mgr->activeMediatedHostdevs, tmp);
-        }
-    }
-    virObjectUnlock(mgr->activeMediatedHostdevs);
-}
-
-int
-virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr,
-                              virPCIDevicePtr pci)
-{
-    struct virHostdevIsPCINodeDeviceUsedData data = {mgr, NULL, NULL, false};
-    int ret = -1;
-
-    virObjectLock(mgr->activePCIHostdevs);
-    virObjectLock(mgr->inactivePCIHostdevs);
-
-    if (virHostdevIsPCINodeDeviceUsed(virPCIDeviceGetAddress(pci), &data))
-        goto cleanup;
-
-    if (virPCIDeviceDetach(pci, mgr->activePCIHostdevs,
-                           mgr->inactivePCIHostdevs) < 0)
-        goto cleanup;
-
-    ret = 0;
-
- cleanup:
-    virObjectUnlock(mgr->inactivePCIHostdevs);
-    virObjectUnlock(mgr->activePCIHostdevs);
-
-    return ret;
-}
-
-int
-virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr mgr,
-                                virPCIDevicePtr pci)
-{
-    struct virHostdevIsPCINodeDeviceUsedData data = {mgr, NULL, NULL, false};
-    int ret = -1;
-
-    virObjectLock(mgr->activePCIHostdevs);
-    virObjectLock(mgr->inactivePCIHostdevs);
-
-    if (virHostdevIsPCINodeDeviceUsed(virPCIDeviceGetAddress(pci), &data))
-        goto cleanup;
-
-    virPCIDeviceSetUnbindFromStub(pci, true);
-    virPCIDeviceSetRemoveSlot(pci, true);
-    virPCIDeviceSetReprobe(pci, true);
-
-    if (virPCIDeviceReattach(pci, mgr->activePCIHostdevs,
-                             mgr->inactivePCIHostdevs) < 0)
-        goto cleanup;
-
-    ret = 0;
-
- cleanup:
-    virObjectUnlock(mgr->inactivePCIHostdevs);
-    virObjectUnlock(mgr->activePCIHostdevs);
-
-    return ret;
-}
-
-int
-virHostdevPCINodeDeviceReset(virHostdevManagerPtr mgr,
-                             virPCIDevicePtr pci)
-{
-    int ret = -1;
-
-    virObjectLock(mgr->activePCIHostdevs);
-    virObjectLock(mgr->inactivePCIHostdevs);
-    if (virPCIDeviceReset(pci, mgr->activePCIHostdevs,
-                          mgr->inactivePCIHostdevs) < 0)
-        goto out;
-
-    ret = 0;
- out:
-    virObjectUnlock(mgr->inactivePCIHostdevs);
-    virObjectUnlock(mgr->activePCIHostdevs);
-    return ret;
-}
-
-int
-virHostdevPrepareDomainDevices(virHostdevManagerPtr mgr,
-                               const char *driver,
-                               virDomainDefPtr def,
-                               unsigned int flags)
-{
-    if (!def->nhostdevs)
-        return 0;
-
-    if (!mgr) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("no host device manager defined"));
-        return -1;
-    }
-
-    if (flags & VIR_HOSTDEV_SP_PCI) {
-        if (virHostdevPreparePCIDevices(mgr, driver,
-                                        def->name, def->uuid,
-                                        def->hostdevs,
-                                        def->nhostdevs,
-                                        flags) < 0)
-            return -1;
-    }
-
-    if (flags & VIR_HOSTDEV_SP_USB) {
-        if (virHostdevPrepareUSBDevices(mgr, driver, def->name,
-                                        def->hostdevs, def->nhostdevs,
-                                        flags) < 0)
-            return -1;
-    }
-
-    if (flags & VIR_HOSTDEV_SP_SCSI) {
-        if (virHostdevPrepareSCSIDevices(mgr, driver, def->name,
-                                         def->hostdevs, def->nhostdevs) < 0)
-        return -1;
-    }
-
-    return 0;
-}
-
-/* @oldStateDir
- * For upgrade purpose: see virHostdevReAttachPCIHostdevs
- */
-void
-virHostdevReAttachDomainDevices(virHostdevManagerPtr mgr,
-                                const char *driver,
-                                virDomainDefPtr def,
-                                unsigned int flags,
-                                const char *oldStateDir)
-{
-    if (!def->nhostdevs || !mgr)
-        return;
-
-    if (flags & VIR_HOSTDEV_SP_PCI) {
-        virHostdevReAttachPCIDevices(mgr, driver, def->name,
-                                     def->hostdevs, def->nhostdevs,
-                                     oldStateDir);
-    }
-
-    if (flags & VIR_HOSTDEV_SP_USB) {
-        virHostdevReAttachUSBDevices(mgr, driver, def->name,
-                                     def->hostdevs, def->nhostdevs);
-    }
-
-    if (flags & VIR_HOSTDEV_SP_SCSI) {
-        virHostdevReAttachSCSIDevices(mgr, driver, def->name,
-                                      def->hostdevs, def->nhostdevs);
-    }
-}
-
-int
-virHostdevUpdateActiveDomainDevices(virHostdevManagerPtr mgr,
-                                    const char *driver,
-                                    virDomainDefPtr def,
-                                    unsigned int flags)
-{
-    if (!def->nhostdevs)
-        return 0;
-
-    if (flags & VIR_HOSTDEV_SP_PCI) {
-        if (virHostdevUpdateActivePCIDevices(mgr,
-                                             def->hostdevs,
-                                             def->nhostdevs,
-                                             driver, def->name) < 0)
-            return -1;
-    }
-
-    if (flags & VIR_HOSTDEV_SP_USB) {
-        if (virHostdevUpdateActiveUSBDevices(mgr,
-                                             def->hostdevs,
-                                             def->nhostdevs,
-                                             driver, def->name) < 0)
-            return -1;
-    }
-
-    if (flags & VIR_HOSTDEV_SP_SCSI) {
-        if (virHostdevUpdateActiveSCSIDevices(mgr,
-                                              def->hostdevs,
-                                              def->nhostdevs,
-                                              driver, def->name) < 0)
-            return -1;
-    }
-
-    return 0;
-}
-
-
-static int
-virHostdevGetNVMeDeviceList(virNVMeDeviceListPtr nvmeDevices,
-                            virStorageSourcePtr src,
-                            const char *drv_name,
-                            const char *dom_name)
-{
-    virStorageSourcePtr n;
-
-    for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) {
-        g_autoptr(virNVMeDevice) dev = NULL;
-        const virStorageSourceNVMeDef *srcNVMe = n->nvme;
-
-        if (n->type != VIR_STORAGE_TYPE_NVME)
-            continue;
-
-        if (!(dev = virNVMeDeviceNew(&srcNVMe->pciAddr,
-                                     srcNVMe->namespace,
-                                     srcNVMe->managed)))
-            return -1;
-
-        virNVMeDeviceUsedBySet(dev, drv_name, dom_name);
-
-        if (virNVMeDeviceListAdd(nvmeDevices, dev) < 0)
-            return -1;
-    }
-
-    return 0;
-}
-
-
-int
-virHostdevPrepareOneNVMeDevice(virHostdevManagerPtr hostdev_mgr,
-                               const char *drv_name,
-                               const char *dom_name,
-                               virStorageSourcePtr src)
-{
-    g_autoptr(virNVMeDeviceList) nvmeDevices = NULL;
-    g_autoptr(virPCIDeviceList) pciDevices = NULL;
-    const unsigned int pciFlags = 0;
-    virNVMeDevicePtr temp = NULL;
-    size_t i;
-    ssize_t lastGoodNVMeIdx = -1;
-    int ret = -1;
-
-    if (!(nvmeDevices = virNVMeDeviceListNew()))
-        return -1;
-
-    if (virHostdevGetNVMeDeviceList(nvmeDevices, src, drv_name, dom_name) < 0)
-        return -1;
-
-    if (virNVMeDeviceListCount(nvmeDevices) == 0)
-        return 0;
-
-    virObjectLock(hostdev_mgr->activeNVMeHostdevs);
-
-    /* Firstly, let's check if all devices are free */
-    for (i = 0; i < virNVMeDeviceListCount(nvmeDevices); i++) {
-        const virNVMeDevice *dev = virNVMeDeviceListGet(nvmeDevices, i);
-        const virPCIDeviceAddress *addr = NULL;
-        g_autofree char *addrStr = NULL;
-        const char *actual_drvname = NULL;
-        const char *actual_domname = NULL;
-
-        temp = virNVMeDeviceListLookup(hostdev_mgr->activeNVMeHostdevs, dev);
-
-        /* Not on the list means not used */
-        if (!temp)
-            continue;
-
-        virNVMeDeviceUsedByGet(temp, &actual_drvname, &actual_domname);
-        addr = virNVMeDeviceAddressGet(dev);
-        addrStr = virPCIDeviceAddressAsString(addr);
-
-        virReportError(VIR_ERR_OPERATION_INVALID,
-                       _("NVMe device %s already in use by driver %s domain %s"),
-                       NULLSTR(addrStr), actual_drvname, actual_domname);
-        goto cleanup;
-    }
-
-    if (!(pciDevices = virNVMeDeviceListCreateDetachList(hostdev_mgr->activeNVMeHostdevs,
-                                                         nvmeDevices)))
-        goto cleanup;
-
-    /* Let's check if all PCI devices are NVMe disks. */
-    for (i = 0; i < virPCIDeviceListCount(pciDevices); i++) {
-        virPCIDevicePtr pci = virPCIDeviceListGet(pciDevices, i);
-        g_autofree char *drvPath = NULL;
-        g_autofree char *drvName = NULL;
-        int stub = VIR_PCI_STUB_DRIVER_NONE;
-
-        if (virPCIDeviceGetDriverPathAndName(pci, &drvPath, &drvName) < 0)
-            goto cleanup;
-
-        if (drvName)
-            stub = virPCIStubDriverTypeFromString(drvName);
-
-        if (stub == VIR_PCI_STUB_DRIVER_VFIO ||
-            STREQ_NULLABLE(drvName, "nvme"))
-            continue;
-
-        VIR_WARN("Suspicious NVMe disk assignment. PCI device "
-                 "%s is not an NVMe disk, it has %s driver",
-                 virPCIDeviceGetName(pci), NULLSTR(drvName));
-    }
-
-    /* This looks like a good opportunity to merge inactive NVMe devices onto
-     * the active list. This, however, means that if something goes wrong we
-     * have to perform a rollback before returning. */
-    for (i = 0; i < virNVMeDeviceListCount(nvmeDevices); i++) {
-        temp = virNVMeDeviceListGet(nvmeDevices, i);
-
-        if (virNVMeDeviceListAdd(hostdev_mgr->activeNVMeHostdevs, temp) < 0)
-            goto rollback;
-
-        lastGoodNVMeIdx = i;
-    }
-
-    if (virHostdevPreparePCIDevicesImpl(hostdev_mgr,
-                                        drv_name, dom_name, NULL,
-                                        pciDevices, NULL, 0, pciFlags) < 0)
-        goto rollback;
-
-    ret = 0;
- cleanup:
-    virObjectUnlock(hostdev_mgr->activeNVMeHostdevs);
-    return ret;
-
- rollback:
-    while (lastGoodNVMeIdx >= 0) {
-        temp = virNVMeDeviceListGet(nvmeDevices, lastGoodNVMeIdx);
-
-        virNVMeDeviceListDel(hostdev_mgr->activeNVMeHostdevs, temp);
-
-        lastGoodNVMeIdx--;
-    }
-    goto cleanup;
-}
-
-
-int
-virHostdevPrepareNVMeDevices(virHostdevManagerPtr hostdev_mgr,
-                             const char *drv_name,
-                             const char *dom_name,
-                             virDomainDiskDefPtr *disks,
-                             size_t ndisks)
-{
-    size_t i;
-    ssize_t lastGoodDiskIdx = -1;
-
-    for (i = 0; i < ndisks; i++) {
-        if (virHostdevPrepareOneNVMeDevice(hostdev_mgr, drv_name,
-                                           dom_name, disks[i]->src) < 0)
-            goto rollback;
-
-        lastGoodDiskIdx = i;
-    }
-
-    return 0;
-
- rollback:
-    while (lastGoodDiskIdx >= 0) {
-        if (virHostdevReAttachOneNVMeDevice(hostdev_mgr, drv_name, dom_name,
-                                            disks[lastGoodDiskIdx]->src) < 0) {
-            VIR_ERROR(_("Failed to reattach NVMe for disk target: %s"),
-                      disks[lastGoodDiskIdx]->dst);
-        }
-
-        lastGoodDiskIdx--;
-    }
-
-    return -1;
-}
-
-
-int
-virHostdevReAttachOneNVMeDevice(virHostdevManagerPtr hostdev_mgr,
-                                const char *drv_name,
-                                const char *dom_name,
-                                virStorageSourcePtr src)
-{
-    g_autoptr(virNVMeDeviceList) nvmeDevices = NULL;
-    g_autoptr(virPCIDeviceList) pciDevices = NULL;
-    size_t i;
-    int ret = -1;
-
-    if (!(nvmeDevices = virNVMeDeviceListNew()))
-        return -1;
-
-    if (virHostdevGetNVMeDeviceList(nvmeDevices, src, drv_name, dom_name) < 0)
-        return -1;
-
-    if (virNVMeDeviceListCount(nvmeDevices) == 0)
-        return 0;
-
-    virObjectLock(hostdev_mgr->activeNVMeHostdevs);
-
-    if (!(pciDevices = virNVMeDeviceListCreateReAttachList(hostdev_mgr->activeNVMeHostdevs,
-                                                           nvmeDevices)))
-        goto cleanup;
-
-    virHostdevReAttachPCIDevicesImpl(hostdev_mgr,
-                                     drv_name, dom_name, pciDevices,
-                                     NULL, 0, NULL);
-
-    for (i = 0; i < virNVMeDeviceListCount(nvmeDevices); i++) {
-        virNVMeDevicePtr temp = virNVMeDeviceListGet(nvmeDevices, i);
-
-        if (virNVMeDeviceListDel(hostdev_mgr->activeNVMeHostdevs, temp) < 0)
-            goto cleanup;
-    }
-
-    ret = 0;
- cleanup:
-    virObjectUnlock(hostdev_mgr->activeNVMeHostdevs);
-    return ret;
-}
-
-
-int
-virHostdevReAttachNVMeDevices(virHostdevManagerPtr hostdev_mgr,
-                              const char *drv_name,
-                              const char *dom_name,
-                              virDomainDiskDefPtr *disks,
-                              size_t ndisks)
-{
-    size_t i;
-    int ret = 0;
-
-    /* Contrary to virHostdevPrepareNVMeDevices, this is a best
-     * effort approach. Just iterate over all disks and try to
-     * reattach them. Don't stop at the first failure. */
-    for (i = 0; i < ndisks; i++) {
-        if (virHostdevReAttachOneNVMeDevice(hostdev_mgr, drv_name,
-                                            dom_name, disks[i]->src) < 0) {
-            VIR_ERROR(_("Failed to reattach NVMe for disk target: %s"),
-                      disks[i]->dst);
-            ret = -1;
-        }
-    }
-
-    return ret;
-}
-
-
-int
-virHostdevUpdateActiveNVMeDevices(virHostdevManagerPtr hostdev_mgr,
-                                  const char *drv_name,
-                                  const char *dom_name,
-                                  virDomainDiskDefPtr *disks,
-                                  size_t ndisks)
-{
-    g_autoptr(virNVMeDeviceList) nvmeDevices = NULL;
-    g_autoptr(virPCIDeviceList) pciDevices = NULL;
-    virNVMeDevicePtr temp = NULL;
-    size_t i;
-    ssize_t lastGoodNVMeIdx = -1;
-    ssize_t lastGoodPCIIdx = -1;
-    int ret = -1;
-
-    if (!(nvmeDevices = virNVMeDeviceListNew()))
-        return -1;
-
-    for (i = 0; i < ndisks; i++) {
-        if (virHostdevGetNVMeDeviceList(nvmeDevices, disks[i]->src, drv_name, dom_name) < 0)
-            return -1;
-    }
-
-    if (virNVMeDeviceListCount(nvmeDevices) == 0)
-        return 0;
-
-    virObjectLock(hostdev_mgr->activeNVMeHostdevs);
-    virObjectLock(hostdev_mgr->activePCIHostdevs);
-    virObjectLock(hostdev_mgr->inactivePCIHostdevs);
-
-    if (!(pciDevices = virNVMeDeviceListCreateDetachList(hostdev_mgr->activeNVMeHostdevs,
-                                                         nvmeDevices)))
-        goto cleanup;
-
-    for (i = 0; i < virNVMeDeviceListCount(nvmeDevices); i++) {
-        temp = virNVMeDeviceListGet(nvmeDevices, i);
-
-        if (virNVMeDeviceListAdd(hostdev_mgr->activeNVMeHostdevs, temp) < 0)
-            goto rollback;
-
-        lastGoodNVMeIdx = i;
-    }
-
-    for (i = 0; i < virPCIDeviceListCount(pciDevices); i++) {
-        virPCIDevicePtr actual = virPCIDeviceListGet(pciDevices, i);
-
-        /* We must restore some attributes that were lost on daemon restart. */
-        virPCIDeviceSetUnbindFromStub(actual, true);
-        if (virPCIDeviceSetUsedBy(actual, drv_name, dom_name) < 0)
-            goto rollback;
-
-        if (virPCIDeviceListAddCopy(hostdev_mgr->activePCIHostdevs, actual) < 0)
-            goto rollback;
-
-        lastGoodPCIIdx = i;
-    }
-
-    ret = 0;
- cleanup:
-    virObjectUnlock(hostdev_mgr->inactivePCIHostdevs);
-    virObjectUnlock(hostdev_mgr->activePCIHostdevs);
-    virObjectUnlock(hostdev_mgr->activeNVMeHostdevs);
-    return ret;
-
- rollback:
-    while (lastGoodNVMeIdx >= 0) {
-        temp = virNVMeDeviceListGet(nvmeDevices, lastGoodNVMeIdx);
-
-        virNVMeDeviceListDel(hostdev_mgr->activeNVMeHostdevs, temp);
-
-        lastGoodNVMeIdx--;
-    }
-    while (lastGoodPCIIdx >= 0) {
-        virPCIDevicePtr actual = virPCIDeviceListGet(pciDevices, i);
-
-        virPCIDeviceListDel(hostdev_mgr->activePCIHostdevs, actual);
-
-        lastGoodPCIIdx--;
-    }
-    goto cleanup;
-}
diff --git a/src/util/virhostdev.h b/src/util/virhostdev.h
deleted file mode 100644 (file)
index 811bda4..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/* virhostdev.h: hostdev management
- *
- * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
- *
- * This library is free software; you can redistribute it and/or
- * 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/>.
- */
-
-#pragma once
-
-#include "internal.h"
-
-#include "virpci.h"
-#include "virusb.h"
-#include "virscsi.h"
-#include "virscsivhost.h"
-#include "conf/domain_conf.h"
-#include "virmdev.h"
-#include "virnvme.h"
-
-typedef enum {
-    VIR_HOSTDEV_STRICT_ACS_CHECK     = (1 << 0), /* strict acs check */
-    VIR_HOSTDEV_COLD_BOOT            = (1 << 1), /* cold boot */
-
-    VIR_HOSTDEV_SP_PCI               = (1 << 8), /* support pci passthrough */
-    VIR_HOSTDEV_SP_USB               = (1 << 9), /* support usb passthrough */
-    VIR_HOSTDEV_SP_SCSI              = (1 << 10), /* support scsi passthrough */
-} virHostdevFlag;
-
-
-typedef struct _virHostdevManager virHostdevManager;
-typedef virHostdevManager *virHostdevManagerPtr;
-struct _virHostdevManager {
-    virObject parent;
-
-    char *stateDir;
-
-    virPCIDeviceListPtr activePCIHostdevs;
-    virPCIDeviceListPtr inactivePCIHostdevs;
-    virUSBDeviceListPtr activeUSBHostdevs;
-    virSCSIDeviceListPtr activeSCSIHostdevs;
-    virSCSIVHostDeviceListPtr activeSCSIVHostHostdevs;
-    virMediatedDeviceListPtr activeMediatedHostdevs;
-    /* NVMe devices are PCI devices really, but one NVMe disk can
-     * have multiple namespaces. */
-    virNVMeDeviceListPtr activeNVMeHostdevs;
-};
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(virHostdevManager, virObjectUnref);
-
-
-virHostdevManagerPtr virHostdevManagerGetDefault(void);
-int
-virHostdevPreparePCIDevices(virHostdevManagerPtr hostdev_mgr,
-                            const char *drv_name,
-                            const char *dom_name,
-                            const unsigned char *uuid,
-                            virDomainHostdevDefPtr *hostdevs,
-                            int nhostdevs,
-                            unsigned int flags)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
-    ATTRIBUTE_NONNULL(4);
-
-int
-virHostdevFindUSBDevice(virDomainHostdevDefPtr hostdev,
-                        bool mandatory,
-                        virUSBDevicePtr *usb)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
-int
-virHostdevPrepareUSBDevices(virHostdevManagerPtr hostdev_mgr,
-                            const char *drv_name,
-                            const char *dom_name,
-                            virDomainHostdevDefPtr *hostdevs,
-                            int nhostdevs,
-                            unsigned int flags)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-int
-virHostdevPrepareSCSIDevices(virHostdevManagerPtr hostdev_mgr,
-                             const char *drv_name,
-                             const char *dom_name,
-                             virDomainHostdevDefPtr *hostdevs,
-                             int nhostdevs)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-int
-virHostdevPrepareSCSIVHostDevices(virHostdevManagerPtr hostdev_mgr,
-                                  const char *drv_name,
-                                  const char *dom_name,
-                                  virDomainHostdevDefPtr *hostdevs,
-                                  int nhostdevs)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-int
-virHostdevPrepareMediatedDevices(virHostdevManagerPtr hostdev_mgr,
-                                 const char *drv_name,
-                                 const char *dom_name,
-                                 virDomainHostdevDefPtr *hostdevs,
-                                 int nhostdevs)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-void
-virHostdevReAttachPCIDevices(virHostdevManagerPtr hostdev_mgr,
-                             const char *drv_name,
-                             const char *dom_name,
-                             virDomainHostdevDefPtr *hostdevs,
-                             int nhostdevs,
-                             const char *oldStateDir)
-    ATTRIBUTE_NONNULL(1);
-void
-virHostdevReAttachUSBDevices(virHostdevManagerPtr hostdev_mgr,
-                              const char *drv_name,
-                              const char *dom_name,
-                              virDomainHostdevDefPtr *hostdevs,
-                              int nhostdevs)
-    ATTRIBUTE_NONNULL(1);
-void
-virHostdevReAttachSCSIDevices(virHostdevManagerPtr hostdev_mgr,
-                              const char *drv_name,
-                              const char *dom_name,
-                              virDomainHostdevDefPtr *hostdevs,
-                              int nhostdevs)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-void
-virHostdevReAttachSCSIVHostDevices(virHostdevManagerPtr hostdev_mgr,
-                                   const char *drv_name,
-                                   const char *dom_name,
-                                   virDomainHostdevDefPtr *hostdevs,
-                                   int nhostdevs)
-    ATTRIBUTE_NONNULL(1);
-void
-virHostdevReAttachMediatedDevices(virHostdevManagerPtr hostdev_mgr,
-                                  const char *drv_name,
-                                  const char *dom_name,
-                                  virDomainHostdevDefPtr *hostdevs,
-                                  int nhostdevs)
-    ATTRIBUTE_NONNULL(1);
-int
-virHostdevUpdateActivePCIDevices(virHostdevManagerPtr mgr,
-                                 virDomainHostdevDefPtr *hostdevs,
-                                 int nhostdevs,
-                                 const char *drv_name,
-                                 const char *dom_name)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
-int
-virHostdevUpdateActiveUSBDevices(virHostdevManagerPtr mgr,
-                                 virDomainHostdevDefPtr *hostdevs,
-                                 int nhostdevs,
-                                 const char *drv_name,
-                                 const char *dom_name)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
-int
-virHostdevUpdateActiveSCSIDevices(virHostdevManagerPtr mgr,
-                                  virDomainHostdevDefPtr *hostdevs,
-                                  int nhostdevs,
-                                  const char *drv_name,
-                                  const char *dom_name)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
-int
-virHostdevUpdateActiveMediatedDevices(virHostdevManagerPtr mgr,
-                                      virDomainHostdevDefPtr *hostdevs,
-                                      int nhostdevs,
-                                      const char *drv_name,
-                                      const char *dom_name)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
-int
-virHostdevUpdateActiveDomainDevices(virHostdevManagerPtr mgr,
-                                    const char *driver,
-                                    virDomainDefPtr def,
-                                    unsigned int flags)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-int
-virHostdevPrepareDomainDevices(virHostdevManagerPtr mgr,
-                               const char *driver,
-                               virDomainDefPtr def,
-                               unsigned int flags)
-    ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-void
-virHostdevReAttachDomainDevices(virHostdevManagerPtr mgr,
-                                const char *driver,
-                                virDomainDefPtr def,
-                                unsigned int flags,
-                                const char *oldStateDir)
-    ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
-
-/* functions used by NodeDevDetach/Reattach/Reset */
-int virHostdevPCINodeDeviceDetach(virHostdevManagerPtr mgr,
-                                  virPCIDevicePtr pci)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-int virHostdevPCINodeDeviceReAttach(virHostdevManagerPtr mgr,
-                                    virPCIDevicePtr pci)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-int virHostdevPCINodeDeviceReset(virHostdevManagerPtr mgr,
-                                 virPCIDevicePtr pci)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-
-int
-virHostdevPrepareOneNVMeDevice(virHostdevManagerPtr hostdev_mgr,
-                               const char *drv_name,
-                               const char *dom_name,
-                               virStorageSourcePtr src);
-
-int
-virHostdevPrepareNVMeDevices(virHostdevManagerPtr hostdev_mgr,
-                             const char *drv_name,
-                             const char *dom_name,
-                             virDomainDiskDefPtr *disks,
-                             size_t ndisks);
-
-int
-virHostdevReAttachOneNVMeDevice(virHostdevManagerPtr hostdev_mgr,
-                                const char *drv_name,
-                                const char *dom_name,
-                                virStorageSourcePtr src);
-
-int
-virHostdevReAttachNVMeDevices(virHostdevManagerPtr hostdev_mgr,
-                              const char *drv_name,
-                              const char *dom_name,
-                              virDomainDiskDefPtr *disks,
-                              size_t ndisks);
-
-int
-virHostdevUpdateActiveNVMeDevices(virHostdevManagerPtr hostdev_mgr,
-                                  const char *drv_name,
-                                  const char *dom_name,
-                                  virDomainDiskDefPtr *disks,
-                                  size_t ndisks);
index ed5255b62dd2f872728a3c01ee790d6477d66cf6..bfb8e343780f2911d9597d5ce86d2b0c08d52d44 100644 (file)
@@ -22,6 +22,7 @@ AM_CPPFLAGS = \
        -I$(top_builddir)/src -I$(top_srcdir)/src \
        -I$(top_srcdir)/src/util \
        -I$(top_srcdir)/src/conf \
+       -I$(top_srcdir)/src/hypervisor \
        -I$(top_builddir)/src/rpc \
        $(NULL)