Mark McLoughlin c034c1
From 89eefbd116ae74c3a5cfcfc74a31a40b83c726c3 Mon Sep 17 00:00:00 2001
Mark McLoughlin c034c1
From: Mark McLoughlin <markmc@redhat.com>
Mark McLoughlin c034c1
Date: Mon, 17 Aug 2009 15:05:23 +0100
Mark McLoughlin c034c1
Subject: [PATCH] Maintain a list of active PCI hostdevs and use it in pciResetDevice()
Mark McLoughlin c034c1
Mark McLoughlin c034c1
https://bugzilla.redhat.com/499678
Mark McLoughlin c034c1
Mark McLoughlin c034c1
First we add a pciDeviceList type and add a qemuGetPciHostDeviceList()
Mark McLoughlin c034c1
function to build a list from a domain definition. Use this in
Mark McLoughlin c034c1
prepare/re-attach to simplify things and eliminate the multiple
Mark McLoughlin c034c1
pciGetDevice() calls.
Mark McLoughlin c034c1
Mark McLoughlin c034c1
Then, as we start/shutdown guests we can add or delete devices as
Mark McLoughlin c034c1
appropriate from a list of active devices.
Mark McLoughlin c034c1
Mark McLoughlin c034c1
Finally, in pciReset(), we can use this to determine whether its safe to
Mark McLoughlin c034c1
reset a device as a side effect of resetting another device.
Mark McLoughlin c034c1
Mark McLoughlin c034c1
(cherry picked from commit 78675b228b76a83f83d64856bfb63b9e14c103a0)
Mark McLoughlin c034c1
(cherry picked from commit e8ad33931296c67de0538e78d12e21706a826d37)
Mark McLoughlin c034c1
Mark McLoughlin c034c1
Fedora-patch: libvirt-allow-pci-hostdev-reset-to-reset-other-devices.patch
Mark McLoughlin c034c1
---
Mark McLoughlin c034c1
 src/libvirt_private.syms |    7 +-
Mark McLoughlin c034c1
 src/pci.c                |  211 +++++++++++++++++++++++++++++++++--------
Mark McLoughlin c034c1
 src/pci.h                |   23 +++++-
Mark McLoughlin c034c1
 src/qemu_conf.h          |    3 +
Mark McLoughlin c034c1
 src/qemu_driver.c        |  237 +++++++++++++++++++++++++++-------------------
Mark McLoughlin c034c1
 src/xen_unified.c        |    2 +-
Mark McLoughlin c034c1
 6 files changed, 339 insertions(+), 144 deletions(-)
Mark McLoughlin c034c1
Mark McLoughlin c034c1
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
Mark McLoughlin c034c1
index bd63692..4f1b01f 100644
Mark McLoughlin c034c1
--- a/src/libvirt_private.syms
Mark McLoughlin c034c1
+++ b/src/libvirt_private.syms
Mark McLoughlin c034c1
@@ -278,7 +278,12 @@ pciFreeDevice;
Mark McLoughlin c034c1
 pciDettachDevice;
Mark McLoughlin c034c1
 pciReAttachDevice;
Mark McLoughlin c034c1
 pciResetDevice;
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
+pciDeviceSetManaged;
Mark McLoughlin c034c1
+pciDeviceGetManaged;
Mark McLoughlin c034c1
+pciDeviceListNew;
Mark McLoughlin c034c1
+pciDeviceListFree;
Mark McLoughlin c034c1
+pciDeviceListAdd;
Mark McLoughlin c034c1
+pciDeviceListDel;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 # qparams.h
Mark McLoughlin c034c1
 qparam_get_query;
Mark McLoughlin c034c1
diff --git a/src/pci.c b/src/pci.c
Mark McLoughlin c034c1
index 74f7ef0..96e5d6d 100644
Mark McLoughlin c034c1
--- a/src/pci.c
Mark McLoughlin c034c1
+++ b/src/pci.c
Mark McLoughlin c034c1
@@ -63,6 +63,7 @@ struct _pciDevice {
Mark McLoughlin c034c1
     unsigned      pci_pm_cap_pos;
Mark McLoughlin c034c1
     unsigned      has_flr : 1;
Mark McLoughlin c034c1
     unsigned      has_pm_reset : 1;
Mark McLoughlin c034c1
+    unsigned      managed : 1;
Mark McLoughlin c034c1
 };
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 /* For virReportOOMError()  and virReportSystemError() */
Mark McLoughlin c034c1
@@ -225,7 +226,7 @@ pciWrite32(pciDevice *dev, unsigned pos, uint32_t val)
Mark McLoughlin c034c1
     pciWrite(dev, pos, &buf[0], sizeof(buf));
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-typedef int (*pciIterPredicate)(pciDevice *, pciDevice *);
Mark McLoughlin c034c1
+typedef int (*pciIterPredicate)(pciDevice *, pciDevice *, void *);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 /* Iterate over available PCI devices calling @predicate
Mark McLoughlin c034c1
  * to compare each one to @dev.
Mark McLoughlin c034c1
@@ -236,7 +237,8 @@ static int
Mark McLoughlin c034c1
 pciIterDevices(virConnectPtr conn,
Mark McLoughlin c034c1
                pciIterPredicate predicate,
Mark McLoughlin c034c1
                pciDevice *dev,
Mark McLoughlin c034c1
-               pciDevice **matched)
Mark McLoughlin c034c1
+               pciDevice **matched,
Mark McLoughlin c034c1
+               void *data)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
     DIR *dir;
Mark McLoughlin c034c1
     struct dirent *entry;
Mark McLoughlin c034c1
@@ -254,7 +256,7 @@ pciIterDevices(virConnectPtr conn,
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     while ((entry = readdir(dir))) {
Mark McLoughlin c034c1
         unsigned domain, bus, slot, function;
Mark McLoughlin c034c1
-        pciDevice *try;
Mark McLoughlin c034c1
+        pciDevice *check;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
         /* Ignore '.' and '..' */
Mark McLoughlin c034c1
         if (entry->d_name[0] == '.')
Mark McLoughlin c034c1
@@ -266,18 +268,18 @@ pciIterDevices(virConnectPtr conn,
Mark McLoughlin c034c1
             continue;
Mark McLoughlin c034c1
         }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        try = pciGetDevice(conn, domain, bus, slot, function);
Mark McLoughlin c034c1
-        if (!try) {
Mark McLoughlin c034c1
+        check = pciGetDevice(conn, domain, bus, slot, function);
Mark McLoughlin c034c1
+        if (!check) {
Mark McLoughlin c034c1
             ret = -1;
Mark McLoughlin c034c1
             break;
Mark McLoughlin c034c1
         }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        if (predicate(try, dev)) {
Mark McLoughlin c034c1
-            VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, try->name);
Mark McLoughlin c034c1
-            *matched = try;
Mark McLoughlin c034c1
+        if (predicate(dev, check, data)) {
Mark McLoughlin c034c1
+            VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check->name);
Mark McLoughlin c034c1
+            *matched = check;
Mark McLoughlin c034c1
             break;
Mark McLoughlin c034c1
         }
Mark McLoughlin c034c1
-        pciFreeDevice(conn, try);
Mark McLoughlin c034c1
+        pciFreeDevice(conn, check);
Mark McLoughlin c034c1
     }
Mark McLoughlin c034c1
     closedir(dir);
Mark McLoughlin c034c1
     return ret;
Mark McLoughlin c034c1
@@ -379,63 +381,70 @@ pciDetectPowerManagementReset(pciDevice *dev)
Mark McLoughlin c034c1
     return 0;
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-/* Any devices other than the one supplied on the same domain/bus ? */
Mark McLoughlin c034c1
+/* Any active devices other than the one supplied on the same domain/bus ? */
Mark McLoughlin c034c1
 static int
Mark McLoughlin c034c1
-pciSharesBus(pciDevice *a, pciDevice *b)
Mark McLoughlin c034c1
+pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void *data)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
-    return
Mark McLoughlin c034c1
-        a->domain == b->domain &&
Mark McLoughlin c034c1
-        a->bus == b->bus &&
Mark McLoughlin c034c1
-        (a->slot != b->slot ||
Mark McLoughlin c034c1
-         a->function != b->function);
Mark McLoughlin c034c1
-}
Mark McLoughlin c034c1
+    pciDeviceList *activeDevs = data;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-static int
Mark McLoughlin c034c1
-pciBusContainsOtherDevices(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
-{
Mark McLoughlin c034c1
-    pciDevice *matched = NULL;
Mark McLoughlin c034c1
-    if (pciIterDevices(conn, pciSharesBus, dev, &matched) < 0)
Mark McLoughlin c034c1
-        return 1;
Mark McLoughlin c034c1
-    if (!matched)
Mark McLoughlin c034c1
+    if (dev->domain != check->domain ||
Mark McLoughlin c034c1
+        dev->bus != check->bus ||
Mark McLoughlin c034c1
+        (check->slot == check->slot &&
Mark McLoughlin c034c1
+         check->function == check->function))
Mark McLoughlin c034c1
+        return 0;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    if (activeDevs && !pciDeviceListFind(activeDevs, check))
Mark McLoughlin c034c1
         return 0;
Mark McLoughlin c034c1
-    pciFreeDevice(conn, matched);
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
     return 1;
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-/* Is @a the parent of @b ? */
Mark McLoughlin c034c1
+static pciDevice *
Mark McLoughlin c034c1
+pciBusContainsActiveDevices(virConnectPtr conn,
Mark McLoughlin c034c1
+                            pciDevice *dev,
Mark McLoughlin c034c1
+                            pciDeviceList *activeDevs)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    pciDevice *active = NULL;
Mark McLoughlin c034c1
+    if (pciIterDevices(conn, pciSharesBusWithActive,
Mark McLoughlin c034c1
+                       dev, &active, activeDevs) < 0)
Mark McLoughlin c034c1
+        return NULL;
Mark McLoughlin c034c1
+    return active;
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+/* Is @check the parent of @dev ? */
Mark McLoughlin c034c1
 static int
Mark McLoughlin c034c1
-pciIsParent(pciDevice *a, pciDevice *b)
Mark McLoughlin c034c1
+pciIsParent(pciDevice *dev, pciDevice *check, void *data ATTRIBUTE_UNUSED)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
     uint16_t device_class;
Mark McLoughlin c034c1
     uint8_t header_type, secondary, subordinate;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    if (a->domain != b->domain)
Mark McLoughlin c034c1
+    if (dev->domain != check->domain)
Mark McLoughlin c034c1
         return 0;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     /* Is it a bridge? */
Mark McLoughlin c034c1
-    device_class = pciRead16(a, PCI_CLASS_DEVICE);
Mark McLoughlin c034c1
+    device_class = pciRead16(check, PCI_CLASS_DEVICE);
Mark McLoughlin c034c1
     if (device_class != PCI_CLASS_BRIDGE_PCI)
Mark McLoughlin c034c1
         return 0;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     /* Is it a plane? */
Mark McLoughlin c034c1
-    header_type = pciRead8(a, PCI_HEADER_TYPE);
Mark McLoughlin c034c1
+    header_type = pciRead8(check, PCI_HEADER_TYPE);
Mark McLoughlin c034c1
     if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
Mark McLoughlin c034c1
         return 0;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    secondary   = pciRead8(a, PCI_SECONDARY_BUS);
Mark McLoughlin c034c1
-    subordinate = pciRead8(a, PCI_SUBORDINATE_BUS);
Mark McLoughlin c034c1
+    secondary   = pciRead8(check, PCI_SECONDARY_BUS);
Mark McLoughlin c034c1
+    subordinate = pciRead8(check, PCI_SUBORDINATE_BUS);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    VIR_DEBUG("%s %s: found parent device %s\n", b->id, b->name, a->name);
Mark McLoughlin c034c1
+    VIR_DEBUG("%s %s: found parent device %s\n", dev->id, dev->name, check->name);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     /* No, it's superman! */
Mark McLoughlin c034c1
-    return (b->bus >= secondary && b->bus <= subordinate);
Mark McLoughlin c034c1
+    return (dev->bus >= secondary && dev->bus <= subordinate);
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 static pciDevice *
Mark McLoughlin c034c1
 pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
     pciDevice *parent = NULL;
Mark McLoughlin c034c1
-    pciIterDevices(conn, pciIsParent, dev, &parent);
Mark McLoughlin c034c1
+    pciIterDevices(conn, pciIsParent, dev, &parent, NULL);
Mark McLoughlin c034c1
     return parent;
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
@@ -443,9 +452,11 @@ pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
  * devices behind a bus.
Mark McLoughlin c034c1
  */
Mark McLoughlin c034c1
 static int
Mark McLoughlin c034c1
-pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
+pciTrySecondaryBusReset(virConnectPtr conn,
Mark McLoughlin c034c1
+                        pciDevice *dev,
Mark McLoughlin c034c1
+                        pciDeviceList *activeDevs)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
-    pciDevice *parent;
Mark McLoughlin c034c1
+    pciDevice *parent, *conflict;
Mark McLoughlin c034c1
     uint8_t config_space[PCI_CONF_LEN];
Mark McLoughlin c034c1
     uint16_t ctl;
Mark McLoughlin c034c1
     int ret = -1;
Mark McLoughlin c034c1
@@ -455,10 +466,10 @@ pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
      * In future, we could allow it so long as those devices
Mark McLoughlin c034c1
      * are not in use by the host or other guests.
Mark McLoughlin c034c1
      */
Mark McLoughlin c034c1
-    if (pciBusContainsOtherDevices(conn, dev)) {
Mark McLoughlin c034c1
+    if ((conflict = pciBusContainsActiveDevices(conn, dev, activeDevs))) {
Mark McLoughlin c034c1
         pciReportError(conn, VIR_ERR_NO_SUPPORT,
Mark McLoughlin c034c1
-                       _("Other devices on bus with %s, not doing bus reset"),
Mark McLoughlin c034c1
-                       dev->name);
Mark McLoughlin c034c1
+                       _("Active %s devices on bus with %s, not doing bus reset"),
Mark McLoughlin c034c1
+                       conflict->name, dev->name);
Mark McLoughlin c034c1
         return -1;
Mark McLoughlin c034c1
     }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
@@ -572,10 +583,18 @@ pciInitDevice(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 int
Mark McLoughlin c034c1
-pciResetDevice(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
+pciResetDevice(virConnectPtr conn,
Mark McLoughlin c034c1
+               pciDevice *dev,
Mark McLoughlin c034c1
+               pciDeviceList *activeDevs)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
     int ret = -1;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
+    if (activeDevs && pciDeviceListFind(activeDevs, dev)) {
Mark McLoughlin c034c1
+        pciReportError(conn, VIR_ERR_INTERNAL_ERROR,
Mark McLoughlin c034c1
+                       _("Not resetting active device %s"), dev->name);
Mark McLoughlin c034c1
+        return -1;
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
     if (!dev->initted && pciInitDevice(conn, dev) < 0)
Mark McLoughlin c034c1
         return -1;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
@@ -594,7 +613,7 @@ pciResetDevice(virConnectPtr conn, pciDevice *dev)
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     /* Bus reset is not an option with the root bus */
Mark McLoughlin c034c1
     if (ret < 0 && dev->bus != 0)
Mark McLoughlin c034c1
-        ret = pciTrySecondaryBusReset(conn, dev);
Mark McLoughlin c034c1
+        ret = pciTrySecondaryBusReset(conn, dev, activeDevs);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     if (ret < 0) {
Mark McLoughlin c034c1
         virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
@@ -890,8 +909,116 @@ pciGetDevice(virConnectPtr conn,
Mark McLoughlin c034c1
 void
Mark McLoughlin c034c1
 pciFreeDevice(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
+    if (!dev)
Mark McLoughlin c034c1
+        return;
Mark McLoughlin c034c1
     VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
Mark McLoughlin c034c1
     if (dev->fd >= 0)
Mark McLoughlin c034c1
         close(dev->fd);
Mark McLoughlin c034c1
     VIR_FREE(dev);
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+void pciDeviceSetManaged(pciDevice *dev, unsigned managed)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    dev->managed = !!managed;
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+unsigned pciDeviceGetManaged(pciDevice *dev)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    return dev->managed;
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+pciDeviceList *
Mark McLoughlin c034c1
+pciDeviceListNew(virConnectPtr conn)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    pciDeviceList *list;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    if (VIR_ALLOC(list) < 0) {
Mark McLoughlin c034c1
+        virReportOOMError(conn);
Mark McLoughlin c034c1
+        return NULL;
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    return list;
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+void
Mark McLoughlin c034c1
+pciDeviceListFree(virConnectPtr conn,
Mark McLoughlin c034c1
+                  pciDeviceList *list)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    int i;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    if (!list)
Mark McLoughlin c034c1
+        return;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    for (i = 0; i < list->count; i++) {
Mark McLoughlin c034c1
+        pciFreeDevice(conn, list->devs[i]);
Mark McLoughlin c034c1
+        list->devs[i] = NULL;
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    list->count = 0;
Mark McLoughlin c034c1
+    VIR_FREE(list->devs);
Mark McLoughlin c034c1
+    VIR_FREE(list);
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+int
Mark McLoughlin c034c1
+pciDeviceListAdd(virConnectPtr conn,
Mark McLoughlin c034c1
+                 pciDeviceList *list,
Mark McLoughlin c034c1
+                 pciDevice *dev)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    if (pciDeviceListFind(list, dev)) {
Mark McLoughlin c034c1
+        pciReportError(conn, VIR_ERR_INTERNAL_ERROR,
Mark McLoughlin c034c1
+                       _("Device %s is already in use"), dev->name);
Mark McLoughlin c034c1
+        return -1;
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    if (VIR_REALLOC_N(list->devs, list->count+1) < 0) {
Mark McLoughlin c034c1
+        virReportOOMError(conn);
Mark McLoughlin c034c1
+        return -1;
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    list->devs[list->count++] = dev;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    return 0;
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+void
Mark McLoughlin c034c1
+pciDeviceListDel(virConnectPtr conn ATTRIBUTE_UNUSED,
Mark McLoughlin c034c1
+                 pciDeviceList *list,
Mark McLoughlin c034c1
+                 pciDevice *dev)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    int i;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    for (i = 0; i < list->count; i++) {
Mark McLoughlin c034c1
+        if (list->devs[i]->domain   != dev->domain ||
Mark McLoughlin c034c1
+            list->devs[i]->bus      != dev->bus    ||
Mark McLoughlin c034c1
+            list->devs[i]->slot     != dev->slot   ||
Mark McLoughlin c034c1
+            list->devs[i]->function != dev->function)
Mark McLoughlin c034c1
+            continue;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        pciFreeDevice(conn, list->devs[i]);
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        if (i != --list->count)
Mark McLoughlin c034c1
+            memmove(&list->devs[i],
Mark McLoughlin c034c1
+                    &list->devs[i+1],
Mark McLoughlin c034c1
+                    sizeof(*list->devs) * (list->count-i));
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        if (VIR_REALLOC_N(list->devs, list->count) < 0) {
Mark McLoughlin c034c1
+            ; /* not fatal */
Mark McLoughlin c034c1
+        }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        break;
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+pciDevice *
Mark McLoughlin c034c1
+pciDeviceListFind(pciDeviceList *list, pciDevice *dev)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    int i;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    for (i = 0; i < list->count; i++)
Mark McLoughlin c034c1
+        if (list->devs[i]->domain   == dev->domain &&
Mark McLoughlin c034c1
+            list->devs[i]->bus      == dev->bus    &&
Mark McLoughlin c034c1
+            list->devs[i]->slot     == dev->slot   &&
Mark McLoughlin c034c1
+            list->devs[i]->function == dev->function)
Mark McLoughlin c034c1
+            return list->devs[i];
Mark McLoughlin c034c1
+    return NULL;
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
diff --git a/src/pci.h b/src/pci.h
Mark McLoughlin c034c1
index 47882ef..685b0af 100644
Mark McLoughlin c034c1
--- a/src/pci.h
Mark McLoughlin c034c1
+++ b/src/pci.h
Mark McLoughlin c034c1
@@ -27,6 +27,11 @@
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 typedef struct _pciDevice pciDevice;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
+typedef struct {
Mark McLoughlin c034c1
+    unsigned count;
Mark McLoughlin c034c1
+    pciDevice **devs;
Mark McLoughlin c034c1
+} pciDeviceList;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
 pciDevice *pciGetDevice      (virConnectPtr  conn,
Mark McLoughlin c034c1
                               unsigned       domain,
Mark McLoughlin c034c1
                               unsigned       bus,
Mark McLoughlin c034c1
@@ -39,6 +44,22 @@ int        pciDettachDevice  (virConnectPtr  conn,
Mark McLoughlin c034c1
 int        pciReAttachDevice (virConnectPtr  conn,
Mark McLoughlin c034c1
                               pciDevice     *dev);
Mark McLoughlin c034c1
 int        pciResetDevice    (virConnectPtr  conn,
Mark McLoughlin c034c1
-                              pciDevice     *dev);
Mark McLoughlin c034c1
+                              pciDevice     *dev,
Mark McLoughlin c034c1
+                              pciDeviceList *activeDevs);
Mark McLoughlin c034c1
+void      pciDeviceSetManaged(pciDevice     *dev,
Mark McLoughlin c034c1
+                              unsigned       managed);
Mark McLoughlin c034c1
+unsigned  pciDeviceGetManaged(pciDevice     *dev);
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+pciDeviceList *pciDeviceListNew  (virConnectPtr conn);
Mark McLoughlin c034c1
+void           pciDeviceListFree (virConnectPtr conn,
Mark McLoughlin c034c1
+                                  pciDeviceList *list);
Mark McLoughlin c034c1
+int            pciDeviceListAdd  (virConnectPtr conn,
Mark McLoughlin c034c1
+                                  pciDeviceList *list,
Mark McLoughlin c034c1
+                                  pciDevice *dev);
Mark McLoughlin c034c1
+void           pciDeviceListDel  (virConnectPtr conn,
Mark McLoughlin c034c1
+                                  pciDeviceList *list,
Mark McLoughlin c034c1
+                                  pciDevice *dev);
Mark McLoughlin c034c1
+pciDevice *    pciDeviceListFind (pciDeviceList *list,
Mark McLoughlin c034c1
+                                  pciDevice *dev);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 #endif /* __VIR_PCI_H__ */
Mark McLoughlin c034c1
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
Mark McLoughlin c034c1
index 517626a..ab9d5e1 100644
Mark McLoughlin c034c1
--- a/src/qemu_conf.h
Mark McLoughlin c034c1
+++ b/src/qemu_conf.h
Mark McLoughlin c034c1
@@ -35,6 +35,7 @@
Mark McLoughlin c034c1
 #include "threads.h"
Mark McLoughlin c034c1
 #include "security.h"
Mark McLoughlin c034c1
 #include "cgroup.h"
Mark McLoughlin c034c1
+#include "pci.h"
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 #define qemudDebug(fmt, ...) do {} while(0)
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
@@ -107,6 +108,8 @@ struct qemud_driver {
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     char *securityDriverName;
Mark McLoughlin c034c1
     virSecurityDriverPtr securityDriver;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    pciDeviceList *activePciHostdevs;
Mark McLoughlin c034c1
 };
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
Mark McLoughlin c034c1
index fd39fc2..cbc27c4 100644
Mark McLoughlin c034c1
--- a/src/qemu_driver.c
Mark McLoughlin c034c1
+++ b/src/qemu_driver.c
Mark McLoughlin c034c1
@@ -128,6 +128,9 @@ static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
Mark McLoughlin c034c1
 static int qemudDetectVcpuPIDs(virConnectPtr conn,
Mark McLoughlin c034c1
                                virDomainObjPtr vm);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
+static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
Mark McLoughlin c034c1
+                                       virDomainDefPtr def);
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
 static struct qemud_driver *qemu_driver = NULL;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 static int qemuCgroupControllerActive(struct qemud_driver *driver,
Mark McLoughlin c034c1
@@ -320,6 +323,10 @@ qemuReconnectDomain(struct qemud_driver *driver,
Mark McLoughlin c034c1
         goto error;
Mark McLoughlin c034c1
     }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
+    if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
Mark McLoughlin c034c1
+        goto error;
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
     if (obj->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
Mark McLoughlin c034c1
         driver->securityDriver &&
Mark McLoughlin c034c1
         driver->securityDriver->domainReserveSecurityLabel &&
Mark McLoughlin c034c1
@@ -524,6 +531,9 @@ qemudStartup(int privileged) {
Mark McLoughlin c034c1
     if ((qemu_driver->caps = qemudCapsInit(NULL)) == NULL)
Mark McLoughlin c034c1
         goto out_of_memory;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
+    if ((qemu_driver->activePciHostdevs = pciDeviceListNew(NULL)) == NULL)
Mark McLoughlin c034c1
+        goto error;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
     if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
Mark McLoughlin c034c1
         goto error;
Mark McLoughlin c034c1
     }
Mark McLoughlin c034c1
@@ -648,6 +658,7 @@ qemudShutdown(void) {
Mark McLoughlin c034c1
         return -1;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     qemuDriverLock(qemu_driver);
Mark McLoughlin c034c1
+    pciDeviceListFree(NULL, qemu_driver->activePciHostdevs);
Mark McLoughlin c034c1
     virCapabilitiesFree(qemu_driver->caps);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     virDomainObjListFree(&qemu_driver->domains);
Mark McLoughlin c034c1
@@ -1329,48 +1340,16 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
Mark McLoughlin c034c1
     return -1;
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-static int qemuPrepareHostDevices(virConnectPtr conn,
Mark McLoughlin c034c1
-                                  virDomainDefPtr def) {
Mark McLoughlin c034c1
+static pciDeviceList *
Mark McLoughlin c034c1
+qemuGetPciHostDeviceList(virConnectPtr conn,
Mark McLoughlin c034c1
+                         virDomainDefPtr def)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    pciDeviceList *list;
Mark McLoughlin c034c1
     int i;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    /* We have to use 2 loops here. *All* devices must
Mark McLoughlin c034c1
-     * be detached before we reset any of them, because
Mark McLoughlin c034c1
-     * in some cases you have to reset the whole PCI,
Mark McLoughlin c034c1
-     * which impacts all devices on it
Mark McLoughlin c034c1
-     */
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
-    for (i = 0 ; i < def->nhostdevs ; i++) {
Mark McLoughlin c034c1
-        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
Mark McLoughlin c034c1
-            continue;
Mark McLoughlin c034c1
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
Mark McLoughlin c034c1
-            continue;
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
-        if (hostdev->managed) {
Mark McLoughlin c034c1
-            pciDevice *dev = pciGetDevice(conn,
Mark McLoughlin c034c1
-                                          hostdev->source.subsys.u.pci.domain,
Mark McLoughlin c034c1
-                                          hostdev->source.subsys.u.pci.bus,
Mark McLoughlin c034c1
-                                          hostdev->source.subsys.u.pci.slot,
Mark McLoughlin c034c1
-                                          hostdev->source.subsys.u.pci.function);
Mark McLoughlin c034c1
-            if (!dev)
Mark McLoughlin c034c1
-                goto error;
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
-            if (pciDettachDevice(conn, dev) < 0) {
Mark McLoughlin c034c1
-                pciFreeDevice(conn, dev);
Mark McLoughlin c034c1
-                goto error;
Mark McLoughlin c034c1
-            }
Mark McLoughlin c034c1
-
Mark McLoughlin c034c1
-            pciFreeDevice(conn, dev);
Mark McLoughlin c034c1
-        } /* else {
Mark McLoughlin c034c1
-             XXX validate that non-managed device isn't in use, eg
Mark McLoughlin c034c1
-             by checking that device is either un-bound, or bound
Mark McLoughlin c034c1
-             to pci-stub.ko
Mark McLoughlin c034c1
-        } */
Mark McLoughlin c034c1
-    }
Mark McLoughlin c034c1
+    if (!(list = pciDeviceListNew(conn)))
Mark McLoughlin c034c1
+        return NULL;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    /* Now that all the PCI hostdevs have be dettached, we can safely
Mark McLoughlin c034c1
-     * reset them */
Mark McLoughlin c034c1
     for (i = 0 ; i < def->nhostdevs ; i++) {
Mark McLoughlin c034c1
         virDomainHostdevDefPtr hostdev = def->hostdevs[i];
Mark McLoughlin c034c1
         pciDevice *dev;
Mark McLoughlin c034c1
@@ -1385,95 +1364,151 @@ static int qemuPrepareHostDevices(virConnectPtr conn,
Mark McLoughlin c034c1
                            hostdev->source.subsys.u.pci.bus,
Mark McLoughlin c034c1
                            hostdev->source.subsys.u.pci.slot,
Mark McLoughlin c034c1
                            hostdev->source.subsys.u.pci.function);
Mark McLoughlin c034c1
-        if (!dev)
Mark McLoughlin c034c1
-            goto error;
Mark McLoughlin c034c1
+        if (!dev) {
Mark McLoughlin c034c1
+            pciDeviceListFree(conn, list);
Mark McLoughlin c034c1
+            return NULL;
Mark McLoughlin c034c1
+        }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        if (pciResetDevice(conn, dev) < 0) {
Mark McLoughlin c034c1
+        if (pciDeviceListAdd(conn, list, dev) < 0) {
Mark McLoughlin c034c1
             pciFreeDevice(conn, dev);
Mark McLoughlin c034c1
-            goto error;
Mark McLoughlin c034c1
+            pciDeviceListFree(conn, list);
Mark McLoughlin c034c1
+            return NULL;
Mark McLoughlin c034c1
         }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        pciFreeDevice(conn, dev);
Mark McLoughlin c034c1
+        pciDeviceSetManaged(dev, hostdev->managed);
Mark McLoughlin c034c1
     }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    return 0;
Mark McLoughlin c034c1
+    return list;
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-error:
Mark McLoughlin c034c1
-    return -1;
Mark McLoughlin c034c1
+static int
Mark McLoughlin c034c1
+qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
Mark McLoughlin c034c1
+                            virDomainDefPtr def)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    pciDeviceList *pcidevs;
Mark McLoughlin c034c1
+    int i, ret;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    if (!def->nhostdevs)
Mark McLoughlin c034c1
+        return 0;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    if (!(pcidevs = qemuGetPciHostDeviceList(NULL, def)))
Mark McLoughlin c034c1
+        return -1;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    ret = 0;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    for (i = 0; i < pcidevs->count; i++) {
Mark McLoughlin c034c1
+        if (pciDeviceListAdd(NULL,
Mark McLoughlin c034c1
+                             driver->activePciHostdevs,
Mark McLoughlin c034c1
+                             pcidevs->devs[i]) < 0) {
Mark McLoughlin c034c1
+            ret = -1;
Mark McLoughlin c034c1
+            break;
Mark McLoughlin c034c1
+        }
Mark McLoughlin c034c1
+        pcidevs->devs[i] = NULL;
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    pciDeviceListFree(NULL, pcidevs);
Mark McLoughlin c034c1
+    return ret;
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-static void
Mark McLoughlin c034c1
-qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainDefPtr def)
Mark McLoughlin c034c1
+static int
Mark McLoughlin c034c1
+qemuPrepareHostDevices(virConnectPtr conn,
Mark McLoughlin c034c1
+                       struct qemud_driver *driver,
Mark McLoughlin c034c1
+                       virDomainDefPtr def)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
+    pciDeviceList *pcidevs;
Mark McLoughlin c034c1
     int i;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    /* Again 2 loops; reset all the devices before re-attach */
Mark McLoughlin c034c1
+    if (!def->nhostdevs)
Mark McLoughlin c034c1
+        return 0;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    for (i = 0 ; i < def->nhostdevs ; i++) {
Mark McLoughlin c034c1
-        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
Mark McLoughlin c034c1
-        pciDevice *dev;
Mark McLoughlin c034c1
+    if (!(pcidevs = qemuGetPciHostDeviceList(conn, def)))
Mark McLoughlin c034c1
+        return -1;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
Mark McLoughlin c034c1
-            continue;
Mark McLoughlin c034c1
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
Mark McLoughlin c034c1
-            continue;
Mark McLoughlin c034c1
+    /* We have to use 3 loops here. *All* devices must
Mark McLoughlin c034c1
+     * be detached before we reset any of them, because
Mark McLoughlin c034c1
+     * in some cases you have to reset the whole PCI,
Mark McLoughlin c034c1
+     * which impacts all devices on it. Also, all devices
Mark McLoughlin c034c1
+     * must be reset before being marked as active.
Mark McLoughlin c034c1
+     */
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        dev = pciGetDevice(conn,
Mark McLoughlin c034c1
-                           hostdev->source.subsys.u.pci.domain,
Mark McLoughlin c034c1
-                           hostdev->source.subsys.u.pci.bus,
Mark McLoughlin c034c1
-                           hostdev->source.subsys.u.pci.slot,
Mark McLoughlin c034c1
-                           hostdev->source.subsys.u.pci.function);
Mark McLoughlin c034c1
-        if (!dev) {
Mark McLoughlin c034c1
-            virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
-            VIR_ERROR(_("Failed to allocate pciDevice: %s\n"),
Mark McLoughlin c034c1
-                      err ? err->message : "");
Mark McLoughlin c034c1
-            virResetError(err);
Mark McLoughlin c034c1
-            continue;
Mark McLoughlin c034c1
-        }
Mark McLoughlin c034c1
+    /* XXX validate that non-managed device isn't in use, eg
Mark McLoughlin c034c1
+     * by checking that device is either un-bound, or bound
Mark McLoughlin c034c1
+     * to pci-stub.ko
Mark McLoughlin c034c1
+     */
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        if (pciResetDevice(conn, dev) < 0) {
Mark McLoughlin c034c1
-            virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
-            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
Mark McLoughlin c034c1
-                      err ? err->message : "");
Mark McLoughlin c034c1
-            virResetError(err);
Mark McLoughlin c034c1
-        }
Mark McLoughlin c034c1
+    for (i = 0; i < pcidevs->count; i++)
Mark McLoughlin c034c1
+        if (pciDeviceGetManaged(pcidevs->devs[i]) &&
Mark McLoughlin c034c1
+            pciDettachDevice(conn, pcidevs->devs[i]) < 0)
Mark McLoughlin c034c1
+            goto error;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    /* Now that all the PCI hostdevs have be dettached, we can safely
Mark McLoughlin c034c1
+     * reset them */
Mark McLoughlin c034c1
+    for (i = 0; i < pcidevs->count; i++)
Mark McLoughlin c034c1
+        if (pciResetDevice(conn, pcidevs->devs[i],
Mark McLoughlin c034c1
+                           driver->activePciHostdevs) < 0)
Mark McLoughlin c034c1
+            goto error;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        pciFreeDevice(conn, dev);
Mark McLoughlin c034c1
+    /* Now mark all the devices as active */
Mark McLoughlin c034c1
+    for (i = 0; i < pcidevs->count; i++) {
Mark McLoughlin c034c1
+        if (pciDeviceListAdd(conn,
Mark McLoughlin c034c1
+                             driver->activePciHostdevs,
Mark McLoughlin c034c1
+                             pcidevs->devs[i]) < 0)
Mark McLoughlin c034c1
+            goto error;
Mark McLoughlin c034c1
+        pcidevs->devs[i] = NULL;
Mark McLoughlin c034c1
     }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    for (i = 0 ; i < def->nhostdevs ; i++) {
Mark McLoughlin c034c1
-        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
Mark McLoughlin c034c1
-        pciDevice *dev;
Mark McLoughlin c034c1
+    pciDeviceListFree(conn, pcidevs);
Mark McLoughlin c034c1
+    return 0;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
Mark McLoughlin c034c1
-            continue;
Mark McLoughlin c034c1
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
Mark McLoughlin c034c1
-            continue;
Mark McLoughlin c034c1
-        if (!hostdev->managed)
Mark McLoughlin c034c1
-            continue;
Mark McLoughlin c034c1
+error:
Mark McLoughlin c034c1
+    pciDeviceListFree(conn, pcidevs);
Mark McLoughlin c034c1
+    return -1;
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        dev = pciGetDevice(conn,
Mark McLoughlin c034c1
-                           hostdev->source.subsys.u.pci.domain,
Mark McLoughlin c034c1
-                           hostdev->source.subsys.u.pci.bus,
Mark McLoughlin c034c1
-                           hostdev->source.subsys.u.pci.slot,
Mark McLoughlin c034c1
-                           hostdev->source.subsys.u.pci.function);
Mark McLoughlin c034c1
-        if (!dev) {
Mark McLoughlin c034c1
+static void
Mark McLoughlin c034c1
+qemuDomainReAttachHostDevices(virConnectPtr conn,
Mark McLoughlin c034c1
+                              struct qemud_driver *driver,
Mark McLoughlin c034c1
+                              virDomainDefPtr def)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    pciDeviceList *pcidevs;
Mark McLoughlin c034c1
+    int i;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    if (!def->nhostdevs)
Mark McLoughlin c034c1
+        return;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    if (!(pcidevs = qemuGetPciHostDeviceList(conn, def))) {
Mark McLoughlin c034c1
+        virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
+        VIR_ERROR(_("Failed to allocate pciDeviceList: %s\n"),
Mark McLoughlin c034c1
+                  err ? err->message : "");
Mark McLoughlin c034c1
+        virResetError(err);
Mark McLoughlin c034c1
+        return;
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    /* Again 3 loops; mark all devices as inactive before reset
Mark McLoughlin c034c1
+     * them and reset all the devices before re-attach */
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    for (i = 0; i < pcidevs->count; i++)
Mark McLoughlin c034c1
+        pciDeviceListDel(conn, driver->activePciHostdevs, pcidevs->devs[i]);
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    for (i = 0; i < pcidevs->count; i++)
Mark McLoughlin c034c1
+        if (pciResetDevice(conn, pcidevs->devs[i],
Mark McLoughlin c034c1
+                           driver->activePciHostdevs) < 0) {
Mark McLoughlin c034c1
             virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
-            VIR_ERROR(_("Failed to allocate pciDevice: %s\n"),
Mark McLoughlin c034c1
+            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
Mark McLoughlin c034c1
                       err ? err->message : "");
Mark McLoughlin c034c1
             virResetError(err);
Mark McLoughlin c034c1
-            continue;
Mark McLoughlin c034c1
         }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        if (pciReAttachDevice(conn, dev) < 0) {
Mark McLoughlin c034c1
+    for (i = 0; i < pcidevs->count; i++)
Mark McLoughlin c034c1
+        if (pciDeviceGetManaged(pcidevs->devs[i]) &&
Mark McLoughlin c034c1
+            pciReAttachDevice(conn, pcidevs->devs[i]) < 0) {
Mark McLoughlin c034c1
             virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
             VIR_ERROR(_("Failed to re-attach PCI device: %s\n"),
Mark McLoughlin c034c1
                       err ? err->message : "");
Mark McLoughlin c034c1
             virResetError(err);
Mark McLoughlin c034c1
         }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-        pciFreeDevice(conn, dev);
Mark McLoughlin c034c1
-    }
Mark McLoughlin c034c1
+    pciDeviceListFree(conn, pcidevs);
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 static const char *const defaultDeviceACL[] = {
Mark McLoughlin c034c1
@@ -2001,7 +2036,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
Mark McLoughlin c034c1
     if (qemuSetupCgroup(conn, driver, vm) < 0)
Mark McLoughlin c034c1
         goto cleanup;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    if (qemuPrepareHostDevices(conn, vm->def) < 0)
Mark McLoughlin c034c1
+    if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
Mark McLoughlin c034c1
         goto cleanup;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     if (VIR_ALLOC(vm->monitor_chr) < 0) {
Mark McLoughlin c034c1
@@ -2183,7 +2218,7 @@ static void qemudShutdownVMDaemon(virConnectPtr conn,
Mark McLoughlin c034c1
         VIR_WARN("Failed to restore all device ownership for %s",
Mark McLoughlin c034c1
                  vm->def->name);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    qemuDomainReAttachHostDevices(conn, vm->def);
Mark McLoughlin c034c1
+    qemuDomainReAttachHostDevices(conn, driver, vm->def);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
 retry:
Mark McLoughlin c034c1
     if ((ret = qemuRemoveCgroup(conn, driver, vm)) < 0) {
Mark McLoughlin c034c1
@@ -6791,6 +6826,7 @@ out:
Mark McLoughlin c034c1
 static int
Mark McLoughlin c034c1
 qemudNodeDeviceReset (virNodeDevicePtr dev)
Mark McLoughlin c034c1
 {
Mark McLoughlin c034c1
+    struct qemud_driver *driver = dev->conn->privateData;
Mark McLoughlin c034c1
     pciDevice *pci;
Mark McLoughlin c034c1
     unsigned domain, bus, slot, function;
Mark McLoughlin c034c1
     int ret = -1;
Mark McLoughlin c034c1
@@ -6802,11 +6838,14 @@ qemudNodeDeviceReset (virNodeDevicePtr dev)
Mark McLoughlin c034c1
     if (!pci)
Mark McLoughlin c034c1
         return -1;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    if (pciResetDevice(dev->conn, pci) < 0)
Mark McLoughlin c034c1
+    qemuDriverLock(driver);
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    if (pciResetDevice(dev->conn, pci, driver->activePciHostdevs) < 0)
Mark McLoughlin c034c1
         goto out;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     ret = 0;
Mark McLoughlin c034c1
 out:
Mark McLoughlin c034c1
+    qemuDriverUnlock(driver);
Mark McLoughlin c034c1
     pciFreeDevice(dev->conn, pci);
Mark McLoughlin c034c1
     return ret;
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
diff --git a/src/xen_unified.c b/src/xen_unified.c
Mark McLoughlin c034c1
index f2ffc25..dfa9ca5 100644
Mark McLoughlin c034c1
--- a/src/xen_unified.c
Mark McLoughlin c034c1
+++ b/src/xen_unified.c
Mark McLoughlin c034c1
@@ -1641,7 +1641,7 @@ xenUnifiedNodeDeviceReset (virNodeDevicePtr dev)
Mark McLoughlin c034c1
     if (!pci)
Mark McLoughlin c034c1
         return -1;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
-    if (pciResetDevice(dev->conn, pci) < 0)
Mark McLoughlin c034c1
+    if (pciResetDevice(dev->conn, pci, NULL) < 0)
Mark McLoughlin c034c1
         goto out;
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
     ret = 0;
Mark McLoughlin c034c1
-- 
Mark McLoughlin c034c1
1.6.2.5
Mark McLoughlin c034c1