rpms/libvirt/F-11 libvirt-add-space-to-nodedev-list-tree.patch, NONE, 1.1 libvirt-allow-pci-hostdev-reset-to-reset-other-devices.patch, NONE, 1.1 libvirt-allow-pm-reset-on-multi-function-pci-devices.patch, NONE, 1.1 libvirt-do-not-overwrite-error-in-wait-for-monitor.patch, NONE, 1.1 libvirt-fix-device-list-update-after-detach.patch, NONE, 1.1 libvirt-improve-pci-hostdev-reset-error-message.patch, NONE, 1.1 libvirt-reattach-pci-hostdevs-after-guest-shutdown.patch, NONE, 1.1 libvirt-0.6.2-svirt-sound.patch, 1.2, 1.3 libvirt.spec, 1.138, 1.139

Mark McLoughlin markmc at fedoraproject.org
Wed Aug 19 16:15:46 UTC 2009


Author: markmc

Update of /cvs/pkgs/rpms/libvirt/F-11
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv27568

Modified Files:
	libvirt-0.6.2-svirt-sound.patch libvirt.spec 
Added Files:
	libvirt-add-space-to-nodedev-list-tree.patch 
	libvirt-allow-pci-hostdev-reset-to-reset-other-devices.patch 
	libvirt-allow-pm-reset-on-multi-function-pci-devices.patch 
	libvirt-do-not-overwrite-error-in-wait-for-monitor.patch 
	libvirt-fix-device-list-update-after-detach.patch 
	libvirt-improve-pci-hostdev-reset-error-message.patch 
	libvirt-reattach-pci-hostdevs-after-guest-shutdown.patch 
Log Message:
* Wed Aug 19 2009 Mark McLoughlin <markmc at redhat.com> - 0.6.2-16.fc11
- Allow PCI bus reset to reset other devices (#499678)
- Fix stupid PCI reset error message (bug #499678)
- Allow PM reset on multi-function PCI devices (bug #515689)
- Re-attach PCI host devices after guest shuts down (bug #499561)
- Fixes list corruption after disk hot-unplug
- Fix minor 'virsh nodedev-list --tree' annoyance


libvirt-add-space-to-nodedev-list-tree.patch:
 virsh.c |   11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

--- NEW FILE libvirt-add-space-to-nodedev-list-tree.patch ---
>From b77d11b221862343d304e11ed878e2f176101f24 Mon Sep 17 00:00:00 2001
From: Daniel P. Berrange <berrange at redhat.com>
Date: Tue, 28 Apr 2009 10:55:45 +0000
Subject: [PATCH] Cosmetic change to 'virsh nodedev-list --tree' output

Maybe it's just me, but I try to select an item from the tree using
double-click and get annoyed when "+-" gets included in the selection.

* src/virsh.c: add a space between "+-" and the node device name
  in 'virsh nodedev-list --tree'

(cherry picked from commit cb4a6614fae48d05f09b7b15328ea6ef4071ccb3)
(cherry picked from commit 097c818bf00b3777778ffc32fea3a6ed1e741e2b)

Fedora-patch: libvirt-add-space-to-nodedev-list-tree.patch
---
 src/virsh.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/src/virsh.c b/src/virsh.c
index 26764a7..c92bb8f 100644
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -4460,10 +4460,12 @@ cmdNodeListDevicesPrint(vshControl *ctl,
     if (depth && depth < MAX_DEPTH) {
         indentBuf[indentIdx] = '+';
         indentBuf[indentIdx+1] = '-';
+        indentBuf[indentIdx+2] = ' ';
+        indentBuf[indentIdx+3] = '\0';
     }
 
     /* Print this device */
-    vshPrint(ctl, indentBuf);
+    vshPrint(ctl, "%s", indentBuf);
     vshPrint(ctl, "%s\n", devices[devid]);
 
 
@@ -4487,8 +4489,8 @@ cmdNodeListDevicesPrint(vshControl *ctl,
 
     /* If there is a child device, then print another blank line */
     if (nextlastdev != -1) {
-        vshPrint(ctl, indentBuf);
-        vshPrint(ctl, "  |\n");
+        vshPrint(ctl, "%s", indentBuf);
+        vshPrint(ctl, " |\n");
     }
 
     /* Finally print all children */
@@ -4511,7 +4513,7 @@ cmdNodeListDevicesPrint(vshControl *ctl,
     /* If there was no child device, and we're the last in
      * a list of devices, then print another blank line */
     if (nextlastdev == -1 && devid == lastdev) {
-        vshPrint(ctl, indentBuf);
+        vshPrint(ctl, "%s", indentBuf);
         vshPrint(ctl, "\n");
     }
 }
-- 
1.6.2.5


libvirt-allow-pci-hostdev-reset-to-reset-other-devices.patch:
 libvirt_private.syms |    7 +
 pci.c                |  211 ++++++++++++++++++++++++++++++++++++---------
 pci.h                |   23 ++++
 qemu_conf.h          |    3 
 qemu_driver.c        |  237 +++++++++++++++++++++++++++++----------------------
 xen_unified.c        |    3 
 6 files changed, 339 insertions(+), 145 deletions(-)

--- NEW FILE libvirt-allow-pci-hostdev-reset-to-reset-other-devices.patch ---
>From 6878a049e27f2eaea7bd3d5c266a2d2b39e444f1 Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc at redhat.com>
Date: Mon, 17 Aug 2009 15:05:23 +0100
Subject: [PATCH] Maintain a list of active PCI hostdevs and use it in pciResetDevice()

https://bugzilla.redhat.com/499678

First we add a pciDeviceList type and add a qemuGetPciHostDeviceList()
function to build a list from a domain definition. Use this in
prepare/re-attach to simplify things and eliminate the multiple
pciGetDevice() calls.

Then, as we start/shutdown guests we can add or delete devices as
appropriate from a list of active devices.

Finally, in pciReset(), we can use this to determine whether its safe to
reset a device as a side effect of resetting another device.

(cherry picked from commit 78675b228b76a83f83d64856bfb63b9e14c103a0)
(cherry picked from commit e8ad33931296c67de0538e78d12e21706a826d37)

Fedora-patch: libvirt-allow-pci-hostdev-reset-to-reset-other-devices.patch
---
 src/libvirt_private.syms |    7 +-
 src/pci.c                |  211 +++++++++++++++++++++++++++++++++--------
 src/pci.h                |   23 +++++-
 src/qemu_conf.h          |    3 +
 src/qemu_driver.c        |  237 +++++++++++++++++++++++++++-------------------
 src/xen_unified.c        |    2 +-
 6 files changed, 339 insertions(+), 144 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 9249a1a..75ddda8 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -240,7 +240,12 @@ pciFreeDevice;
 pciDettachDevice;
 pciReAttachDevice;
 pciResetDevice;
-
+pciDeviceSetManaged;
+pciDeviceGetManaged;
+pciDeviceListNew;
+pciDeviceListFree;
+pciDeviceListAdd;
+pciDeviceListDel;
 
 # qparams.h
 qparam_get_query;
diff --git a/src/pci.c b/src/pci.c
index 1dddb08..1e68261 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -58,6 +58,7 @@ struct _pciDevice {
     unsigned      pci_pm_cap_pos;
     unsigned      has_flr : 1;
     unsigned      has_pm_reset : 1;
+    unsigned      managed : 1;
 };
 
 /* For virReportOOMError()  and virReportSystemError() */
@@ -220,7 +221,7 @@ pciWrite32(pciDevice *dev, unsigned pos, uint32_t val)
     pciWrite(dev, pos, &buf[0], sizeof(buf));
 }
 
-typedef int (*pciIterPredicate)(pciDevice *, pciDevice *);
+typedef int (*pciIterPredicate)(pciDevice *, pciDevice *, void *);
 
 /* Iterate over available PCI devices calling @predicate
  * to compare each one to @dev.
@@ -231,7 +232,8 @@ static int
 pciIterDevices(virConnectPtr conn,
                pciIterPredicate predicate,
                pciDevice *dev,
-               pciDevice **matched)
+               pciDevice **matched,
+               void *data)
 {
     DIR *dir;
     struct dirent *entry;
@@ -249,7 +251,7 @@ pciIterDevices(virConnectPtr conn,
 
     while ((entry = readdir(dir))) {
         unsigned domain, bus, slot, function;
-        pciDevice *try;
+        pciDevice *check;
 
         /* Ignore '.' and '..' */
         if (entry->d_name[0] == '.')
@@ -261,18 +263,18 @@ pciIterDevices(virConnectPtr conn,
             continue;
         }
 
-        try = pciGetDevice(conn, domain, bus, slot, function);
-        if (!try) {
+        check = pciGetDevice(conn, domain, bus, slot, function);
+        if (!check) {
             ret = -1;
             break;
         }
 
-        if (predicate(try, dev)) {
-            VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, try->name);
-            *matched = try;
+        if (predicate(dev, check, data)) {
+            VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check->name);
+            *matched = check;
             break;
         }
-        pciFreeDevice(conn, try);
+        pciFreeDevice(conn, check);
     }
     closedir(dir);
     return ret;
@@ -374,63 +376,70 @@ pciDetectPowerManagementReset(pciDevice *dev)
     return 0;
 }
 
-/* Any devices other than the one supplied on the same domain/bus ? */
+/* Any active devices other than the one supplied on the same domain/bus ? */
 static int
-pciSharesBus(pciDevice *a, pciDevice *b)
+pciSharesBusWithActive(pciDevice *dev, pciDevice *check, void *data)
 {
-    return
-        a->domain == b->domain &&
-        a->bus == b->bus &&
-        (a->slot != b->slot ||
-         a->function != b->function);
-}
+    pciDeviceList *activeDevs = data;
 
-static int
-pciBusContainsOtherDevices(virConnectPtr conn, pciDevice *dev)
-{
-    pciDevice *matched = NULL;
-    if (pciIterDevices(conn, pciSharesBus, dev, &matched) < 0)
-        return 1;
-    if (!matched)
+    if (dev->domain != check->domain ||
+        dev->bus != check->bus ||
+        (check->slot == check->slot &&
+         check->function == check->function))
+        return 0;
+
+    if (activeDevs && !pciDeviceListFind(activeDevs, check))
         return 0;
-    pciFreeDevice(conn, matched);
+
     return 1;
 }
 
-/* Is @a the parent of @b ? */
+static pciDevice *
+pciBusContainsActiveDevices(virConnectPtr conn,
+                            pciDevice *dev,
+                            pciDeviceList *activeDevs)
+{
+    pciDevice *active = NULL;
+    if (pciIterDevices(conn, pciSharesBusWithActive,
+                       dev, &active, activeDevs) < 0)
+        return NULL;
+    return active;
+}
+
+/* Is @check the parent of @dev ? */
 static int
-pciIsParent(pciDevice *a, pciDevice *b)
+pciIsParent(pciDevice *dev, pciDevice *check, void *data ATTRIBUTE_UNUSED)
 {
     uint16_t device_class;
     uint8_t header_type, secondary, subordinate;
 
-    if (a->domain != b->domain)
+    if (dev->domain != check->domain)
         return 0;
 
     /* Is it a bridge? */
-    device_class = pciRead16(a, PCI_CLASS_DEVICE);
+    device_class = pciRead16(check, PCI_CLASS_DEVICE);
     if (device_class != PCI_CLASS_BRIDGE_PCI)
         return 0;
 
     /* Is it a plane? */
-    header_type = pciRead8(a, PCI_HEADER_TYPE);
+    header_type = pciRead8(check, PCI_HEADER_TYPE);
     if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
         return 0;
 
-    secondary   = pciRead8(a, PCI_SECONDARY_BUS);
-    subordinate = pciRead8(a, PCI_SUBORDINATE_BUS);
+    secondary   = pciRead8(check, PCI_SECONDARY_BUS);
+    subordinate = pciRead8(check, PCI_SUBORDINATE_BUS);
 
-    VIR_DEBUG("%s %s: found parent device %s\n", b->id, b->name, a->name);
+    VIR_DEBUG("%s %s: found parent device %s\n", dev->id, dev->name, check->name);
 
     /* No, it's superman! */
-    return (b->bus >= secondary && b->bus <= subordinate);
+    return (dev->bus >= secondary && dev->bus <= subordinate);
 }
 
 static pciDevice *
 pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
 {
     pciDevice *parent = NULL;
-    pciIterDevices(conn, pciIsParent, dev, &parent);
+    pciIterDevices(conn, pciIsParent, dev, &parent, NULL);
     return parent;
 }
 
@@ -438,9 +447,11 @@ pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
  * devices behind a bus.
  */
 static int
-pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
+pciTrySecondaryBusReset(virConnectPtr conn,
+                        pciDevice *dev,
+                        pciDeviceList *activeDevs)
 {
-    pciDevice *parent;
+    pciDevice *parent, *conflict;
     uint8_t config_space[PCI_CONF_LEN];
     uint16_t ctl;
     int ret = -1;
@@ -450,10 +461,10 @@ pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
      * In future, we could allow it so long as those devices
      * are not in use by the host or other guests.
      */
-    if (pciBusContainsOtherDevices(conn, dev)) {
+    if ((conflict = pciBusContainsActiveDevices(conn, dev, activeDevs))) {
         pciReportError(conn, VIR_ERR_NO_SUPPORT,
-                       _("Other devices on bus with %s, not doing bus reset"),
-                       dev->name);
+                       _("Active %s devices on bus with %s, not doing bus reset"),
+                       conflict->name, dev->name);
         return -1;
     }
 
@@ -567,10 +578,18 @@ pciInitDevice(virConnectPtr conn, pciDevice *dev)
 }
 
 int
-pciResetDevice(virConnectPtr conn, pciDevice *dev)
+pciResetDevice(virConnectPtr conn,
+               pciDevice *dev,
+               pciDeviceList *activeDevs)
 {
     int ret = -1;
 
+    if (activeDevs && pciDeviceListFind(activeDevs, dev)) {
+        pciReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                       _("Not resetting active device %s"), dev->name);
+        return -1;
+    }
+
     if (!dev->initted && pciInitDevice(conn, dev) < 0)
         return -1;
 
@@ -589,7 +608,7 @@ pciResetDevice(virConnectPtr conn, pciDevice *dev)
 
     /* Bus reset is not an option with the root bus */
     if (ret < 0 && dev->bus != 0)
-        ret = pciTrySecondaryBusReset(conn, dev);
+        ret = pciTrySecondaryBusReset(conn, dev, activeDevs);
 
     if (ret < 0) {
         virErrorPtr err = virGetLastError();
@@ -885,8 +904,116 @@ pciGetDevice(virConnectPtr conn,
 void
 pciFreeDevice(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
 {
+    if (!dev)
+        return;
     VIR_DEBUG("%s %s: freeing", dev->id, dev->name);
     if (dev->fd >= 0)
         close(dev->fd);
     VIR_FREE(dev);
 }
+
+void pciDeviceSetManaged(pciDevice *dev, unsigned managed)
+{
+    dev->managed = !!managed;
+}
+
+unsigned pciDeviceGetManaged(pciDevice *dev)
+{
+    return dev->managed;
+}
+
+pciDeviceList *
+pciDeviceListNew(virConnectPtr conn)
+{
+    pciDeviceList *list;
+
+    if (VIR_ALLOC(list) < 0) {
+        virReportOOMError(conn);
+        return NULL;
+    }
+
+    return list;
+}
+
+void
+pciDeviceListFree(virConnectPtr conn,
+                  pciDeviceList *list)
+{
+    int i;
+
+    if (!list)
+        return;
+
+    for (i = 0; i < list->count; i++) {
+        pciFreeDevice(conn, list->devs[i]);
+        list->devs[i] = NULL;
+    }
+
+    list->count = 0;
+    VIR_FREE(list->devs);
+    VIR_FREE(list);
+}
+
+int
+pciDeviceListAdd(virConnectPtr conn,
+                 pciDeviceList *list,
+                 pciDevice *dev)
+{
+    if (pciDeviceListFind(list, dev)) {
+        pciReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                       _("Device %s is already in use"), dev->name);
+        return -1;
+    }
+
+    if (VIR_REALLOC_N(list->devs, list->count+1) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    list->devs[list->count++] = dev;
+
+    return 0;
+}
+
+void
+pciDeviceListDel(virConnectPtr conn ATTRIBUTE_UNUSED,
+                 pciDeviceList *list,
+                 pciDevice *dev)
+{
+    int i;
+
+    for (i = 0; i < list->count; i++) {
+        if (list->devs[i]->domain   != dev->domain ||
+            list->devs[i]->bus      != dev->bus    ||
+            list->devs[i]->slot     != dev->slot   ||
+            list->devs[i]->function != dev->function)
+            continue;
+
+        pciFreeDevice(conn, list->devs[i]);
+
+        if (i != --list->count)
+            memmove(&list->devs[i],
+                    &list->devs[i+1],
+                    sizeof(*list->devs) * (list->count-i));
+
+        if (VIR_REALLOC_N(list->devs, list->count) < 0) {
+            ; /* not fatal */
+        }
+
+        break;
+    }
+}
+
+pciDevice *
+pciDeviceListFind(pciDeviceList *list, pciDevice *dev)
+{
+    int i;
+
+    for (i = 0; i < list->count; i++)
+        if (list->devs[i]->domain   == dev->domain &&
+            list->devs[i]->bus      == dev->bus    &&
+            list->devs[i]->slot     == dev->slot   &&
+            list->devs[i]->function == dev->function)
+            return list->devs[i];
+    return NULL;
+}
diff --git a/src/pci.h b/src/pci.h
index 47882ef..685b0af 100644
--- a/src/pci.h
+++ b/src/pci.h
@@ -27,6 +27,11 @@
 
 typedef struct _pciDevice pciDevice;
 
+typedef struct {
+    unsigned count;
+    pciDevice **devs;
+} pciDeviceList;
+
 pciDevice *pciGetDevice      (virConnectPtr  conn,
                               unsigned       domain,
                               unsigned       bus,
@@ -39,6 +44,22 @@ int        pciDettachDevice  (virConnectPtr  conn,
 int        pciReAttachDevice (virConnectPtr  conn,
                               pciDevice     *dev);
 int        pciResetDevice    (virConnectPtr  conn,
-                              pciDevice     *dev);
+                              pciDevice     *dev,
+                              pciDeviceList *activeDevs);
+void      pciDeviceSetManaged(pciDevice     *dev,
+                              unsigned       managed);
+unsigned  pciDeviceGetManaged(pciDevice     *dev);
+
+pciDeviceList *pciDeviceListNew  (virConnectPtr conn);
+void           pciDeviceListFree (virConnectPtr conn,
+                                  pciDeviceList *list);
+int            pciDeviceListAdd  (virConnectPtr conn,
+                                  pciDeviceList *list,
+                                  pciDevice *dev);
+void           pciDeviceListDel  (virConnectPtr conn,
+                                  pciDeviceList *list,
+                                  pciDevice *dev);
+pciDevice *    pciDeviceListFind (pciDeviceList *list,
+                                  pciDevice *dev);
 
 #endif /* __VIR_PCI_H__ */
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index 70fe9c8..cde326d 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -34,6 +34,7 @@
 #include "domain_event.h"
 #include "threads.h"
 #include "security.h"
+#include "pci.h"
 
 #define qemudDebug(fmt, ...) do {} while(0)
 
@@ -90,6 +91,8 @@ struct qemud_driver {
 
     char *securityDriverName;
     virSecurityDriverPtr securityDriver;
+
+    pciDeviceList *activePciHostdevs;
 };
 
 /* Status needed to reconenct to running VMs */
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index 9f87d2a..7dbf4a2 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -126,6 +126,9 @@ static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
                                        virDomainObjPtr vm,
                                        unsigned long newmem);
 
+static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
+                                       virDomainDefPtr def);
+
 static struct qemud_driver *qemu_driver = NULL;
 
 
@@ -334,6 +337,10 @@ qemudReconnectVMs(struct qemud_driver *driver)
         if ((vm->logfile = qemudLogFD(NULL, driver->logDir, vm->def->name)) < 0)
             goto next_error;
 
+        if (qemuUpdateActivePciHostdevs(driver, vm->def) < 0) {
+            goto next_error;
+        }
+
         if (vm->def->id >= driver->nextvmid)
             driver->nextvmid = vm->def->id + 1;
 
@@ -515,6 +522,9 @@ qemudStartup(void) {
     if ((qemu_driver->caps = qemudCapsInit()) == NULL)
         goto out_of_memory;
 
+    if ((qemu_driver->activePciHostdevs = pciDeviceListNew(NULL)) == NULL)
+        goto error;
+
     if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
         goto error;
     }
@@ -627,6 +637,7 @@ qemudShutdown(void) {
         return -1;
 
     qemuDriverLock(qemu_driver);
+    pciDeviceListFree(NULL, qemu_driver->activePciHostdevs);
     virCapabilitiesFree(qemu_driver->caps);
 
     virDomainObjListFree(&qemu_driver->domains);
@@ -1209,48 +1220,16 @@ static int qemudNextFreeVNCPort(struct qemud_driver *driver ATTRIBUTE_UNUSED) {
     return -1;
 }
 
-static int qemuPrepareHostDevices(virConnectPtr conn,
-                                  virDomainDefPtr def) {
+static pciDeviceList *
+qemuGetPciHostDeviceList(virConnectPtr conn,
+                         virDomainDefPtr def)
+{
+    pciDeviceList *list;
     int i;
 
-    /* We have to use 2 loops here. *All* devices must
-     * be detached before we reset any of them, because
-     * in some cases you have to reset the whole PCI,
-     * which impacts all devices on it
-     */
-
-    for (i = 0 ; i < def->nhostdevs ; i++) {
-        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
-
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
-            continue;
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
-            continue;
-
-        if (hostdev->managed) {
-            pciDevice *dev = pciGetDevice(conn,
-                                          hostdev->source.subsys.u.pci.domain,
-                                          hostdev->source.subsys.u.pci.bus,
-                                          hostdev->source.subsys.u.pci.slot,
-                                          hostdev->source.subsys.u.pci.function);
-            if (!dev)
-                goto error;
-
-            if (pciDettachDevice(conn, dev) < 0) {
-                pciFreeDevice(conn, dev);
-                goto error;
-            }
-
-            pciFreeDevice(conn, dev);
-        } /* else {
-             XXX validate that non-managed device isn't in use, eg
-             by checking that device is either un-bound, or bound
-             to pci-stub.ko
-        } */
-    }
+    if (!(list = pciDeviceListNew(conn)))
+        return NULL;
 
-    /* Now that all the PCI hostdevs have be dettached, we can safely
-     * reset them */
     for (i = 0 ; i < def->nhostdevs ; i++) {
         virDomainHostdevDefPtr hostdev = def->hostdevs[i];
         pciDevice *dev;
@@ -1265,95 +1244,151 @@ static int qemuPrepareHostDevices(virConnectPtr conn,
                            hostdev->source.subsys.u.pci.bus,
                            hostdev->source.subsys.u.pci.slot,
                            hostdev->source.subsys.u.pci.function);
-        if (!dev)
-            goto error;
+        if (!dev) {
+            pciDeviceListFree(conn, list);
+            return NULL;
+        }
 
-        if (pciResetDevice(conn, dev) < 0) {
+        if (pciDeviceListAdd(conn, list, dev) < 0) {
             pciFreeDevice(conn, dev);
-            goto error;
+            pciDeviceListFree(conn, list);
+            return NULL;
         }
 
-        pciFreeDevice(conn, dev);
+        pciDeviceSetManaged(dev, hostdev->managed);
     }
 
-    return 0;
+    return list;
+}
 
-error:
-    return -1;
+static int
+qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
+                            virDomainDefPtr def)
+{
+    pciDeviceList *pcidevs;
+    int i, ret;
+
+    if (!def->nhostdevs)
+        return 0;
+
+    if (!(pcidevs = qemuGetPciHostDeviceList(NULL, def)))
+        return -1;
+
+    ret = 0;
+
+    for (i = 0; i < pcidevs->count; i++) {
+        if (pciDeviceListAdd(NULL,
+                             driver->activePciHostdevs,
+                             pcidevs->devs[i]) < 0) {
+            ret = -1;
+            break;
+        }
+        pcidevs->devs[i] = NULL;
+    }
+
+    pciDeviceListFree(NULL, pcidevs);
+    return ret;
 }
 
-static void
-qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainDefPtr def)
+static int
+qemuPrepareHostDevices(virConnectPtr conn,
+                       struct qemud_driver *driver,
+                       virDomainDefPtr def)
 {
+    pciDeviceList *pcidevs;
     int i;
 
-    /* Again 2 loops; reset all the devices before re-attach */
+    if (!def->nhostdevs)
+        return 0;
 
-    for (i = 0 ; i < def->nhostdevs ; i++) {
-        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
-        pciDevice *dev;
+    if (!(pcidevs = qemuGetPciHostDeviceList(conn, def)))
+        return -1;
 
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
-            continue;
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
-            continue;
+    /* We have to use 3 loops here. *All* devices must
+     * be detached before we reset any of them, because
+     * in some cases you have to reset the whole PCI,
+     * which impacts all devices on it. Also, all devices
+     * must be reset before being marked as active.
+     */
 
-        dev = pciGetDevice(conn,
-                           hostdev->source.subsys.u.pci.domain,
-                           hostdev->source.subsys.u.pci.bus,
-                           hostdev->source.subsys.u.pci.slot,
-                           hostdev->source.subsys.u.pci.function);
-        if (!dev) {
-            virErrorPtr err = virGetLastError();
-            VIR_ERROR(_("Failed to allocate pciDevice: %s\n"),
-                      err ? err->message : "");
-            virResetError(err);
-            continue;
-        }
+    /* XXX validate that non-managed device isn't in use, eg
+     * by checking that device is either un-bound, or bound
+     * to pci-stub.ko
+     */
 
-        if (pciResetDevice(conn, dev) < 0) {
-            virErrorPtr err = virGetLastError();
-            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
-                      err ? err->message : "");
-            virResetError(err);
-        }
+    for (i = 0; i < pcidevs->count; i++)
+        if (pciDeviceGetManaged(pcidevs->devs[i]) &&
+            pciDettachDevice(conn, pcidevs->devs[i]) < 0)
+            goto error;
+
+    /* Now that all the PCI hostdevs have be dettached, we can safely
+     * reset them */
+    for (i = 0; i < pcidevs->count; i++)
+        if (pciResetDevice(conn, pcidevs->devs[i],
+                           driver->activePciHostdevs) < 0)
+            goto error;
 
-        pciFreeDevice(conn, dev);
+    /* Now mark all the devices as active */
+    for (i = 0; i < pcidevs->count; i++) {
+        if (pciDeviceListAdd(conn,
+                             driver->activePciHostdevs,
+                             pcidevs->devs[i]) < 0)
+            goto error;
+        pcidevs->devs[i] = NULL;
     }
 
-    for (i = 0 ; i < def->nhostdevs ; i++) {
-        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
-        pciDevice *dev;
+    pciDeviceListFree(conn, pcidevs);
+    return 0;
 
-        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
-            continue;
-        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
-            continue;
-        if (!hostdev->managed)
-            continue;
+error:
+    pciDeviceListFree(conn, pcidevs);
+    return -1;
+}
 
-        dev = pciGetDevice(conn,
-                           hostdev->source.subsys.u.pci.domain,
-                           hostdev->source.subsys.u.pci.bus,
-                           hostdev->source.subsys.u.pci.slot,
-                           hostdev->source.subsys.u.pci.function);
-        if (!dev) {
+static void
+qemuDomainReAttachHostDevices(virConnectPtr conn,
+                              struct qemud_driver *driver,
+                              virDomainDefPtr def)
+{
+    pciDeviceList *pcidevs;
+    int i;
+
+    if (!def->nhostdevs)
+        return;
+
+    if (!(pcidevs = qemuGetPciHostDeviceList(conn, def))) {
+        virErrorPtr err = virGetLastError();
+        VIR_ERROR(_("Failed to allocate pciDeviceList: %s\n"),
+                  err ? err->message : "");
+        virResetError(err);
+        return;
+    }
+
+    /* Again 3 loops; mark all devices as inactive before reset
+     * them and reset all the devices before re-attach */
+
+    for (i = 0; i < pcidevs->count; i++)
+        pciDeviceListDel(conn, driver->activePciHostdevs, pcidevs->devs[i]);
+
+    for (i = 0; i < pcidevs->count; i++)
+        if (pciResetDevice(conn, pcidevs->devs[i],
+                           driver->activePciHostdevs) < 0) {
             virErrorPtr err = virGetLastError();
-            VIR_ERROR(_("Failed to allocate pciDevice: %s\n"),
+            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
                       err ? err->message : "");
             virResetError(err);
-            continue;
         }
 
-        if (pciReAttachDevice(conn, dev) < 0) {
+    for (i = 0; i < pcidevs->count; i++)
+        if (pciDeviceGetManaged(pcidevs->devs[i]) &&
+            pciReAttachDevice(conn, pcidevs->devs[i]) < 0) {
             virErrorPtr err = virGetLastError();
             VIR_ERROR(_("Failed to re-attach PCI device: %s\n"),
                       err ? err->message : "");
             virResetError(err);
         }
 
-        pciFreeDevice(conn, dev);
-    }
+    pciDeviceListFree(conn, pcidevs);
 }
 
 static int qemudDomainSetSecurityLabel(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm)
@@ -1468,7 +1503,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
                                 &qemuCmdFlags) < 0)
         goto cleanup;
 
-    if (qemuPrepareHostDevices(conn, vm->def) < 0)
+    if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
         goto cleanup;
 
     vm->def->id = driver->nextvmid++;
@@ -1634,7 +1669,7 @@ static void qemudShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
         VIR_FREE(vm->def->seclabel.imagelabel);
     }
 
-    qemuDomainReAttachHostDevices(conn, vm->def);
+    qemuDomainReAttachHostDevices(conn, driver, vm->def);
 
     if (qemudRemoveDomainStatus(conn, driver, vm) < 0) {
         VIR_WARN(_("Failed to remove domain status for %s"),
@@ -5247,6 +5282,7 @@ out:
 static int
 qemudNodeDeviceReset (virNodeDevicePtr dev)
 {
+    struct qemud_driver *driver = dev->conn->privateData;
     pciDevice *pci;
     unsigned domain, bus, slot, function;
     int ret = -1;
@@ -5258,11 +5294,14 @@ qemudNodeDeviceReset (virNodeDevicePtr dev)
     if (!pci)
         return -1;
 
-    if (pciResetDevice(dev->conn, pci) < 0)
+    qemuDriverLock(driver);
+
+    if (pciResetDevice(dev->conn, pci, driver->activePciHostdevs) < 0)
         goto out;
 
     ret = 0;
 out:
+    qemuDriverUnlock(driver);
     pciFreeDevice(dev->conn, pci);
     return ret;
 }
diff --git a/src/xen_unified.c b/src/xen_unified.c
index e708980..ba8c769 100644
--- a/src/xen_unified.c
+++ b/src/xen_unified.c
@@ -1529,7 +1529,7 @@ xenUnifiedNodeDeviceReset (virNodeDevicePtr dev)
     if (!pci)
         return -1;
 
-    if (pciResetDevice(dev->conn, pci) < 0)
+    if (pciResetDevice(dev->conn, pci, NULL) < 0)
         goto out;
 
     ret = 0;
-- 
1.6.2.5


libvirt-allow-pm-reset-on-multi-function-pci-devices.patch:
 pci.c |   49 +++++++++----------------------------------------
 1 file changed, 9 insertions(+), 40 deletions(-)

--- NEW FILE libvirt-allow-pm-reset-on-multi-function-pci-devices.patch ---
>From d79f35fbd4eaf610972621b042993d00f3247d5c Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc at redhat.com>
Date: Fri, 14 Aug 2009 08:31:11 +0100
Subject: [PATCH] Allow PM reset on multi-function PCI devices

https://bugzilla.redhat.com/515689

It turns out that a PCI Power Management reset only affects individual
functions, and not the whole device.

The PCI Power Management spec talks about resetting the 'device' rather
than the 'function', but Intel's Dexuan Cui informs me that it is
actually a per-function reset.

Also, Yu Zhao has added pci_pm_reset() to the kernel, and it doesn't
reject multi-function devices, so it must be true! :-)

(A side issue is that we could defer the PM reset to the kernel if we
could detect that the kernel has PM reset support, but barring version
number checks we don't have a way to detect that support)

* src/pci.c: remove the pciDeviceContainsOtherFunctions() check from
  pciTryPowerManagementReset() and prefer PM reset over bus reset
  where both are available

Cc: Cui, Dexuan <dexuan.cui at intel.com>
Cc: Yu Zhao <yu.zhao at intel.com>

(cherry picked from commit 64a6682b93a2a8aa38067a43979c9eaf993d2b41)

Fedora-patch: libvirt-allow-pm-reset-on-multi-function-pci-devices.patch
---
 src/pci.c |   48 +++++++++---------------------------------------
 1 files changed, 9 insertions(+), 39 deletions(-)

diff --git a/src/pci.c b/src/pci.c
index 68a380d..f78ab9f 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -397,29 +397,6 @@ pciBusContainsOtherDevices(virConnectPtr conn, pciDevice *dev)
     return 1;
 }
 
-/* Any other functions on this device ? */
-static int
-pciSharesDevice(pciDevice *a, pciDevice *b)
-{
-    return
-        a->domain == b->domain &&
-        a->bus == b->bus &&
-        a->slot == b->slot &&
-        a->function != b->function;
-}
-
-static int
-pciDeviceContainsOtherFunctions(virConnectPtr conn, pciDevice *dev)
-{
-    pciDevice *matched = NULL;
-    if (pciIterDevices(conn, pciSharesDevice, dev, &matched) < 0)
-        return 1;
-    if (!matched)
-        return 0;
-    pciFreeDevice(conn, matched);
-    return 1;
-}
-
 /* Is @a the parent of @b ? */
 static int
 pciIsParent(pciDevice *a, pciDevice *b)
@@ -524,7 +501,7 @@ out:
  * above we require the device supports a full internal reset.
  */
 static int
-pciTryPowerManagementReset(virConnectPtr conn, pciDevice *dev)
+pciTryPowerManagementReset(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
 {
     uint8_t config_space[PCI_CONF_LEN];
     uint32_t ctl;
@@ -532,16 +509,6 @@ pciTryPowerManagementReset(virConnectPtr conn, pciDevice *dev)
     if (!dev->pci_pm_cap_pos)
         return -1;
 
-    /* For now, we just refuse to do a power management reset
-     * if there are other functions on this device.
-     * In future, we could allow it so long as those functions
-     * are not in use by the host or other guests.
-     */
-    if (pciDeviceContainsOtherFunctions(conn, dev)) {
-        VIR_WARN("%s contains other functions, not resetting", dev->name);
-        return -1;
-    }
-
     /* Save and restore the device's config space. */
     if (pciRead(dev, 0, &config_space[0], PCI_CONF_LEN) < 0) {
         VIR_WARN("Failed to save PCI config space for %s", dev->name);
@@ -599,14 +566,17 @@ pciResetDevice(virConnectPtr conn, pciDevice *dev)
     if (dev->has_flr)
         return 0;
 
+    /* If the device supports PCI power management reset,
+     * that's the next best thing because it only resets
+     * the function, not the whole device.
+     */
+    if (dev->has_pm_reset)
+        ret = pciTryPowerManagementReset(conn, dev);
+
     /* Bus reset is not an option with the root bus */
-    if (dev->bus != 0)
+    if (ret < 0 && dev->bus != 0)
         ret = pciTrySecondaryBusReset(conn, dev);
 
-    /* Next best option is a PCI power management reset */
-    if (ret < 0 && dev->has_pm_reset)
-        ret = pciTryPowerManagementReset(conn, dev);
-
     if (ret < 0)
         pciReportError(conn, VIR_ERR_NO_SUPPORT,
                        _("No PCI reset capability available for %s"),
-- 
1.6.2.5


libvirt-do-not-overwrite-error-in-wait-for-monitor.patch:
 qemu_driver.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

--- NEW FILE libvirt-do-not-overwrite-error-in-wait-for-monitor.patch ---
>From 1319852c443c432d44a2e73508f3be742027f780 Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc at redhat.com>
Date: Wed, 19 Aug 2009 11:28:02 +0100
Subject: [PATCH] Don't overwrite error in qemudWaitForMonitor()

May help diagnose https://bugzilla.redhat.com/515054

Fedora-patch: libvirt-do-not-overwrite-error-in-wait-for-monitor.patch
---
 src/qemu_driver.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index dfd19c5..74e106a 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -985,8 +985,9 @@ static int qemudWaitForMonitor(virConnectPtr conn,
         return 0;
 
     /* Unexpected end of file - inform user of QEMU log data */
-    qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
-                     _("unable to start guest: %s"), buf);
+    if (!virGetLastError())
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("unable to start guest: %s"), buf);
     return -1;
 }
 
-- 
1.6.2.5


libvirt-fix-device-list-update-after-detach.patch:
 qemu_driver.c |   22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

--- NEW FILE libvirt-fix-device-list-update-after-detach.patch ---
>From 2754da03d65f216271c81ece791b96a19272c812 Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc at redhat.com>
Date: Sat, 15 Aug 2009 19:38:15 +0100
Subject: [PATCH] Fix list updating after disk hot-unplug

The current code makes a poor effort at updating the device arrays after
hot-unplug. Fix that and combine the two code paths into one.

* src/qemu_driver.c: fix list updating in qemudDomainDetachPciDiskDevice()

(cherry picked from commit 4e12af5623e4a962a6bb911af06fa29aa85befba)

Fedora-patch: libvirt-fix-device-list-update-after-detach.patch
---
 src/qemu_driver.c |   21 ++++++++++-----------
 1 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index dfd19c5..ce04beb 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -4123,18 +4123,17 @@ try_command:
         goto cleanup;
     }
 
-    if (vm->def->ndisks > 1) {
-        vm->def->disks[i] = vm->def->disks[--vm->def->ndisks];
-        if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks) < 0) {
-            virReportOOMError(conn);
-            goto cleanup;
-        }
-        qsort(vm->def->disks, vm->def->ndisks, sizeof(*vm->def->disks),
-              virDomainDiskQSort);
-    } else {
-        VIR_FREE(vm->def->disks[0]);
-        vm->def->ndisks = 0;
+    if (i != --vm->def->ndisks)
+        memmove(&vm->def->disks[i],
+                &vm->def->disks[i+1],
+                sizeof(*vm->def->disks) * (vm->def->ndisks-i));
+    if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks) < 0) {
+        virReportOOMError(conn);
+        goto cleanup;
     }
+    qsort(vm->def->disks, vm->def->ndisks, sizeof(*vm->def->disks),
+          virDomainDiskQSort);
+
     ret = 0;
 
 cleanup:
-- 
1.6.2.5


libvirt-improve-pci-hostdev-reset-error-message.patch:
 pci.c         |   44 +++++++++++++++++++++++++++++++-------------
 qemu_driver.c |    5 ++---
 2 files changed, 33 insertions(+), 16 deletions(-)

--- NEW FILE libvirt-improve-pci-hostdev-reset-error-message.patch ---
>From 9f80bab3829b97ac2802c15b9f3e4a6bbbb24627 Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc at redhat.com>
Date: Fri, 14 Aug 2009 08:31:11 +0100
Subject: [PATCH] Improve PCI host device reset error message

https://bugzilla.redhat.com/499678

Currently, if we are unable to reset a PCI device we return a fairly
generic 'No PCI reset capability available' error message.

Fix that by returning an error from the individual reset messages and
using that error to construct the higher level error mesage.

* src/pci.c: set errors in pciTryPowerManagementReset() and
  pciTrySecondaryBusReset() on failure; use those error messages
  in pciResetDevice(), or explain that no reset support is available

(cherry picked from commit ebea34185612c3b96d7d3bbd8b7c2ce6c9f4fe6f)

Fedora-patch: libvirt-improve-pci-hostdev-reset-error-message.patch
---
 src/pci.c         |   44 +++++++++++++++++++++++++++++++-------------
 src/qemu_driver.c |    4 ++--
 2 files changed, 33 insertions(+), 15 deletions(-)

diff --git a/src/pci.c b/src/pci.c
index f78ab9f..1dddb08 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -451,15 +451,18 @@ pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
      * are not in use by the host or other guests.
      */
     if (pciBusContainsOtherDevices(conn, dev)) {
-        VIR_WARN("Other devices on bus with %s, not doing bus reset",
-                 dev->name);
+        pciReportError(conn, VIR_ERR_NO_SUPPORT,
+                       _("Other devices on bus with %s, not doing bus reset"),
+                       dev->name);
         return -1;
     }
 
     /* Find the parent bus */
     parent = pciGetParentDevice(conn, dev);
     if (!parent) {
-        VIR_WARN("Failed to find parent device for %s", dev->name);
+        pciReportError(conn, VIR_ERR_NO_SUPPORT,
+                       _("Failed to find parent device for %s"),
+                       dev->name);
         return -1;
     }
 
@@ -470,7 +473,9 @@ pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
      * are multiple devices/functions
      */
     if (pciRead(dev, 0, config_space, PCI_CONF_LEN) < 0) {
-        VIR_WARN("Failed to save PCI config space for %s", dev->name);
+        pciReportError(conn, VIR_ERR_NO_SUPPORT,
+                       _("Failed to save PCI config space for %s"),
+                       dev->name);
         goto out;
     }
 
@@ -487,9 +492,12 @@ pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
 
     usleep(200 * 1000); /* sleep 200ms */
 
-    if (pciWrite(dev, 0, config_space, PCI_CONF_LEN) < 0)
-        VIR_WARN("Failed to restore PCI config space for %s", dev->name);
-
+    if (pciWrite(dev, 0, config_space, PCI_CONF_LEN) < 0) {
+        pciReportError(conn, VIR_ERR_NO_SUPPORT,
+                       _("Failed to restore PCI config space for %s"),
+                       dev->name);
+        goto out;
+    }
     ret = 0;
 out:
     pciFreeDevice(conn, parent);
@@ -511,7 +519,9 @@ pciTryPowerManagementReset(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
 
     /* Save and restore the device's config space. */
     if (pciRead(dev, 0, &config_space[0], PCI_CONF_LEN) < 0) {
-        VIR_WARN("Failed to save PCI config space for %s", dev->name);
+        pciReportError(conn, VIR_ERR_NO_SUPPORT,
+                       _("Failed to save PCI config space for %s"),
+                       dev->name);
         return -1;
     }
 
@@ -528,8 +538,12 @@ pciTryPowerManagementReset(virConnectPtr conn ATTRIBUTE_UNUSED, pciDevice *dev)
 
     usleep(10 * 1000); /* sleep 10ms */
 
-    if (pciWrite(dev, 0, &config_space[0], PCI_CONF_LEN) < 0)
-        VIR_WARN("Failed to restore PCI config space for %s", dev->name);
+    if (pciWrite(dev, 0, &config_space[0], PCI_CONF_LEN) < 0) {
+        pciReportError(conn, VIR_ERR_NO_SUPPORT,
+                       _("Failed to restore PCI config space for %s"),
+                       dev->name);
+        return -1;
+    }
 
     return 0;
 }
@@ -577,10 +591,14 @@ pciResetDevice(virConnectPtr conn, pciDevice *dev)
     if (ret < 0 && dev->bus != 0)
         ret = pciTrySecondaryBusReset(conn, dev);
 
-    if (ret < 0)
+    if (ret < 0) {
+        virErrorPtr err = virGetLastError();
         pciReportError(conn, VIR_ERR_NO_SUPPORT,
-                       _("No PCI reset capability available for %s"),
-                       dev->name);
+                       _("Unable to reset PCI device %s: %s"),
+                       dev->name,
+                       err ? err->message : _("no FLR, PM reset or bus reset available"));
+    }
+
     return ret;
 }
 
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index ddd3693..9f87d2a 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -1345,9 +1345,9 @@ qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainDefPtr def)
             continue;
         }
 
-        if (pciDettachDevice(conn, dev) < 0) {
+        if (pciReAttachDevice(conn, dev) < 0) {
             virErrorPtr err = virGetLastError();
-            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
+            VIR_ERROR(_("Failed to re-attach PCI device: %s\n"),
                       err ? err->message : "");
             virResetError(err);
         }
-- 
1.6.2.5


libvirt-reattach-pci-hostdevs-after-guest-shutdown.patch:
 qemu_driver.c |   77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 76 insertions(+), 1 deletion(-)

--- NEW FILE libvirt-reattach-pci-hostdevs-after-guest-shutdown.patch ---
>From 1e44604c0d4c2d4c1347c2a1027f1ea02a6499f9 Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc at redhat.com>
Date: Fri, 14 Aug 2009 08:31:11 +0100
Subject: [PATCH] Reset and re-attach PCI host devices on guest shutdown

https://bugzilla.redhat.com/499561

When the guest shuts down, we should attempt to restore all PCI host
devices to a sane state.

In the case of managed hostdevs, we should reset and re-attach the
devices. In the case of unmanaged hostdevs, we should just reset them.

Note, KVM will already reset assigned devices when the guest shuts
down using whatever means it can, so we are only doing it to cover the
cases the kernel can't handle.

* src/qemu_driver.c: add qemuDomainReAttachHostDevices() and call
  it from qemudShutdownVMDaemon()

(cherry picked from commit 4035152a8767e72fd4e26a91cb4d5afa75b72e61)

Fedora-patch: libvirt-reattach-pci-hostdevs-after-guest-shutdown.patch
---
 src/qemu_driver.c |   76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 76 insertions(+), 0 deletions(-)

diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index ce04beb..ddd3693 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -1282,6 +1282,80 @@ error:
     return -1;
 }
 
+static void
+qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainDefPtr def)
+{
+    int i;
+
+    /* Again 2 loops; reset all the devices before re-attach */
+
+    for (i = 0 ; i < def->nhostdevs ; i++) {
+        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
+        pciDevice *dev;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+            continue;
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+            continue;
+
+        dev = pciGetDevice(conn,
+                           hostdev->source.subsys.u.pci.domain,
+                           hostdev->source.subsys.u.pci.bus,
+                           hostdev->source.subsys.u.pci.slot,
+                           hostdev->source.subsys.u.pci.function);
+        if (!dev) {
+            virErrorPtr err = virGetLastError();
+            VIR_ERROR(_("Failed to allocate pciDevice: %s\n"),
+                      err ? err->message : "");
+            virResetError(err);
+            continue;
+        }
+
+        if (pciResetDevice(conn, dev) < 0) {
+            virErrorPtr err = virGetLastError();
+            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
+                      err ? err->message : "");
+            virResetError(err);
+        }
+
+        pciFreeDevice(conn, dev);
+    }
+
+    for (i = 0 ; i < def->nhostdevs ; i++) {
+        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
+        pciDevice *dev;
+
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
+            continue;
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+            continue;
+        if (!hostdev->managed)
+            continue;
+
+        dev = pciGetDevice(conn,
+                           hostdev->source.subsys.u.pci.domain,
+                           hostdev->source.subsys.u.pci.bus,
+                           hostdev->source.subsys.u.pci.slot,
+                           hostdev->source.subsys.u.pci.function);
+        if (!dev) {
+            virErrorPtr err = virGetLastError();
+            VIR_ERROR(_("Failed to allocate pciDevice: %s\n"),
+                      err ? err->message : "");
+            virResetError(err);
+            continue;
+        }
+
+        if (pciDettachDevice(conn, dev) < 0) {
+            virErrorPtr err = virGetLastError();
+            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
+                      err ? err->message : "");
+            virResetError(err);
+        }
+
+        pciFreeDevice(conn, dev);
+    }
+}
+
 static int qemudDomainSetSecurityLabel(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm)
 {
     if (vm->def->seclabel.label != NULL)
@@ -1560,6 +1634,8 @@ static void qemudShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
         VIR_FREE(vm->def->seclabel.imagelabel);
     }
 
+    qemuDomainReAttachHostDevices(conn, vm->def);
+
     if (qemudRemoveDomainStatus(conn, driver, vm) < 0) {
         VIR_WARN(_("Failed to remove domain status for %s"),
                  vm->def->name);
-- 
1.6.2.5


libvirt-0.6.2-svirt-sound.patch:
 qemu_conf.c |   18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

Index: libvirt-0.6.2-svirt-sound.patch
===================================================================
RCS file: /cvs/pkgs/rpms/libvirt/F-11/libvirt-0.6.2-svirt-sound.patch,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -p -r1.2 -r1.3
--- libvirt-0.6.2-svirt-sound.patch	17 Aug 2009 08:08:57 -0000	1.2
+++ libvirt-0.6.2-svirt-sound.patch	19 Aug 2009 16:15:46 -0000	1.3
@@ -1,4 +1,4 @@
-From 02f85e2c6b3b53f89d8b4b3e5cb70b1700719516 Mon Sep 17 00:00:00 2001
+From e76837af35d692cb947db3a47058bcfbbf77b46a Mon Sep 17 00:00:00 2001
 From: Daniel P. Berrange <berrange at redhat.com>
 Date: Mon, 17 Aug 2009 08:52:30 +0100
 Subject: [PATCH] Disable sound cards when running sVirt


Index: libvirt.spec
===================================================================
RCS file: /cvs/pkgs/rpms/libvirt/F-11/libvirt.spec,v
retrieving revision 1.138
retrieving revision 1.139
diff -u -p -r1.138 -r1.139
--- libvirt.spec	17 Aug 2009 08:08:57 -0000	1.138
+++ libvirt.spec	19 Aug 2009 16:15:46 -0000	1.139
@@ -66,7 +66,7 @@
 Summary: Library providing a simple API virtualization
 Name: libvirt
 Version: 0.6.2
-Release: 15%{?dist}%{?extra_release}
+Release: 16%{?dist}%{?extra_release}
 License: LGPLv2+
 Group: Development/Libraries
 Source: libvirt-%{version}.tar.gz
@@ -118,6 +118,18 @@ Patch21: libvirt-0.6.2-qemu-name-uniquen
 Patch22: libvirt-0.6.2-buf-locale-escape.patch
 # rhbz #506590
 Patch23: libvirt-0.6.2-numa-ignore-fail.patch
+# Minor 'virsh nodedev-list --tree' annoyance, fix from upstream
+Patch24: libvirt-add-space-to-nodedev-list-tree.patch
+# Fixes list corruption after disk hot-unplug
+Patch25: libvirt-fix-device-list-update-after-detach.patch
+# Re-attach PCI host devices after guest shuts down (bug #499561)
+Patch26: libvirt-reattach-pci-hostdevs-after-guest-shutdown.patch
+# Allow PM reset on multi-function PCI devices (bug #515689)
+Patch27: libvirt-allow-pm-reset-on-multi-function-pci-devices.patch
+# Fix stupid PCI reset error message (#499678)
+Patch28: libvirt-improve-pci-hostdev-reset-error-message.patch
+# Allow PCI bus reset to reset other devices (#499678)
+Patch29: libvirt-allow-pci-hostdev-reset-to-reset-other-devices.patch
 
 # Not for upstream. Temporary hack till PulseAudio autostart
 # problems are sorted out when SELinux enforcing
@@ -293,6 +305,12 @@ of recent versions of Linux (and other O
 %patch21 -p1
 %patch22 -p1
 %patch23 -p1
+%patch24 -p1
+%patch25 -p1
+%patch26 -p1
+%patch27 -p1
+%patch28 -p1
+%patch29 -p1
 
 %patch200 -p1
 
@@ -616,6 +634,14 @@ fi
 %endif
 
 %changelog
+* Wed Aug 19 2009 Mark McLoughlin <markmc at redhat.com> - 0.6.2-16.fc11
+- Allow PCI bus reset to reset other devices (#499678)
+- Fix stupid PCI reset error message (bug #499678)
+- Allow PM reset on multi-function PCI devices (bug #515689)
+- Re-attach PCI host devices after guest shuts down (bug #499561)
+- Fixes list corruption after disk hot-unplug
+- Fix minor 'virsh nodedev-list --tree' annoyance
+
 * Thu Aug 13 2009 Daniel P. Berrange <berrange at redhat.com> - 0.6.2-15.fc11
 - Log and ignore NUMA topology problems (rhbz #506590)
 




More information about the fedora-extras-commits mailing list