rpms/libvirt/devel libvirt-add-pci-hostdev-hotplug-support.patch, NONE, 1.1 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-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.4-svirt-sound.patch, 1.2, 1.3 libvirt.spec, 1.170, 1.171

Mark McLoughlin markmc at fedoraproject.org
Wed Aug 19 16:26:28 UTC 2009


Author: markmc

Update of /cvs/pkgs/rpms/libvirt/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv29802

Modified Files:
	libvirt-0.6.4-svirt-sound.patch libvirt.spec 
Added Files:
	libvirt-add-pci-hostdev-hotplug-support.patch 
	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-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.7.0-5
- Add PCI host device hotplug support
- 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)
- Fix list corruption after disk hot-unplug
- Fix minor 'virsh nodedev-list --tree' annoyance


libvirt-add-pci-hostdev-hotplug-support.patch:
 domain_conf.c        |   33 +++++-
 domain_conf.h        |   13 ++
 libvirt_private.syms |    2 
 qemu_driver.c        |  267 ++++++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 300 insertions(+), 15 deletions(-)

--- NEW FILE libvirt-add-pci-hostdev-hotplug-support.patch ---
>From 332979bb680d833529ab9cecac6828c6ce54d731 Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc at redhat.com>
Date: Fri, 14 Aug 2009 08:31:10 +0100
Subject: [PATCH] Add host PCI device hotplug support

Attaching a host PCI device to a qemu guest is done with a
straightforward 'pci_add pci_addr auto host host=XX:XX.X' command.

Like with NIC and disk hotplug, we need to retain the guest PCI address
assigned by qemu so that we can use it for hot-unplug.

Identifying a device for detach is done using the host PCI address.

Managed mode is handled by detaching/resetting the device before
attaching it to the guest and re-attaching it after detaching it from
the guest.

(cherry picked from commit 7636ef4630fc15c3d559eceb5b5c4fb1524b7c5a)
(cherry picked from commit 0c5b7b93a3cdb197c55d79c2605e9e19e3af43f5)
(cherry picked from commit 60ff07585ca8f7e639fed477e2e2cf79ce1c5c21)
(cherry picked from commit 4e12af5623e4a962a6bb911af06fa29aa85befba)
(cherry picked from commit 4dbecff9fbd5b5d1154bc7a41a5d4dd00533b359)
(cherry picked from commit 12edef9a6aca5bd9a2ea18b73ca862f615684d84)
(cherry picked from commit 457e05062863a35c7efb35470886b9b83a49d04d)
(cherry picked from commit e8ad33931296c67de0538e78d12e21706a826d37)

Fedora-patch: libvirt-add-pci-hostdev-hotplug-support.patch
---
 src/domain_conf.c        |   33 +++++-
 src/domain_conf.h        |   13 +++
 src/libvirt_private.syms |    2 +
 src/qemu_driver.c        |  266 ++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 300 insertions(+), 14 deletions(-)

diff --git a/src/domain_conf.c b/src/domain_conf.c
index 2301a96..bad53f7 100644
--- a/src/domain_conf.c
+++ b/src/domain_conf.c
@@ -1977,7 +1977,8 @@ out:
 static int
 virDomainHostdevSubsysPciDefParseXML(virConnectPtr conn,
                                      const xmlNodePtr node,
-                                     virDomainHostdevDefPtr def) {
+                                     virDomainHostdevDefPtr def,
+                                     int flags) {
 
     int ret = -1;
     xmlNodePtr cur;
@@ -2049,6 +2050,20 @@ virDomainHostdevSubsysPciDefParseXML(virConnectPtr conn,
                                          _("pci address needs function id"));
                     goto out;
                 }
+            } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
+                       xmlStrEqual(cur->name, BAD_CAST "state")) {
+                char *devaddr = virXMLPropString(cur, "devaddr");
+                if (devaddr &&
+                    sscanf(devaddr, "%x:%x:%x",
+                           &def->source.subsys.u.pci.guest_addr.domain,
+                           &def->source.subsys.u.pci.guest_addr.bus,
+                           &def->source.subsys.u.pci.guest_addr.slot) < 3) {
+                    virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                         _("Unable to parse devaddr parameter '%s'"),
+                                         devaddr);
+                    VIR_FREE(devaddr);
+                    goto out;
+                }
             } else {
                 virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                      _("unknown pci source type '%s'"),
@@ -2123,7 +2138,7 @@ virDomainHostdevDefParseXML(virConnectPtr conn,
                 }
                 if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
                     def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
-                        if (virDomainHostdevSubsysPciDefParseXML(conn, cur, def) < 0)
+                        if (virDomainHostdevSubsysPciDefParseXML(conn, cur, def, flags) < 0)
                             goto error;
                 }
             } else {
@@ -3937,7 +3952,8 @@ virDomainGraphicsDefFormat(virConnectPtr conn,
 static int
 virDomainHostdevDefFormat(virConnectPtr conn,
                           virBufferPtr buf,
-                          virDomainHostdevDefPtr def)
+                          virDomainHostdevDefPtr def,
+                          int flags)
 {
     const char *mode = virDomainHostdevModeTypeToString(def->mode);
     const char *type;
@@ -3978,6 +3994,15 @@ virDomainHostdevDefFormat(virConnectPtr conn,
                           def->source.subsys.u.pci.bus,
                           def->source.subsys.u.pci.slot,
                           def->source.subsys.u.pci.function);
+        if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS) {
+            virBufferAddLit(buf, "      <state");
+            if (virHostdevHasValidGuestAddr(def))
+                virBufferVSprintf(buf, " devaddr='%.4x:%.2x:%.2x'",
+                                  def->source.subsys.u.pci.guest_addr.domain,
+                                  def->source.subsys.u.pci.guest_addr.bus,
+                                  def->source.subsys.u.pci.guest_addr.slot);
+            virBufferAddLit(buf, "/>\n");
+        }
     }
 
     virBufferAddLit(buf, "      </source>\n");
@@ -4192,7 +4217,7 @@ char *virDomainDefFormat(virConnectPtr conn,
             goto cleanup;
 
     for (n = 0 ; n < def->nhostdevs ; n++)
-        if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n]) < 0)
+        if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n], flags) < 0)
             goto cleanup;
 
     virBufferAddLit(&buf, "  </devices>\n");
diff --git a/src/domain_conf.h b/src/domain_conf.h
index 63fca76..44302be 100644
--- a/src/domain_conf.h
+++ b/src/domain_conf.h
@@ -391,6 +391,11 @@ struct _virDomainHostdevDef {
                      unsigned bus;
                      unsigned slot;
                      unsigned function;
+                    struct {
+                        unsigned domain;
+                        unsigned bus;
+                        unsigned slot;
+                    } guest_addr;
                 } pci;
             } u;
         } subsys;
@@ -404,6 +409,14 @@ struct _virDomainHostdevDef {
     char* target;
 };
 
+static inline int
+virHostdevHasValidGuestAddr(virDomainHostdevDefPtr def)
+{
+    return def->source.subsys.u.pci.guest_addr.domain ||
+           def->source.subsys.u.pci.guest_addr.bus ||
+           def->source.subsys.u.pci.guest_addr.slot;
+}
+
 /* Flags for the 'type' field in next struct */
 enum virDomainDeviceType {
     VIR_DOMAIN_DEVICE_DISK,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 4f1b01f..22131c4 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -88,6 +88,8 @@ virDomainGetRootFilesystem;
 virDomainGraphicsTypeFromString;
 virDomainGraphicsDefFree;
 virDomainHostdevDefFree;
+virDomainHostdevModeTypeToString;
+virDomainHostdevSubsysTypeToString;
 virDomainInputDefFree;
 virDomainLifecycleTypeFromString;
 virDomainLifecycleTypeToString;
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index cbc27c4..99dac52 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -5258,9 +5258,91 @@ cleanup:
     return -1;
 }
 
-static int qemudDomainAttachHostDevice(virConnectPtr conn,
-                                       virDomainObjPtr vm,
-                                       virDomainDeviceDefPtr dev)
+static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
+                                          struct qemud_driver *driver,
+                                          virDomainObjPtr vm,
+                                          virDomainDeviceDefPtr dev)
+{
+    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+    char *cmd, *reply;
+    unsigned domain, bus, slot;
+    pciDevice *pci;
+
+    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    pci = 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)
+        return -1;
+
+    if ((hostdev->managed && pciDettachDevice(conn, pci) < 0) ||
+        pciResetDevice(conn, pci, driver->activePciHostdevs) < 0) {
+        pciFreeDevice(conn, pci);
+        return -1;
+    }
+
+    if (pciDeviceListAdd(conn, driver->activePciHostdevs, pci) < 0) {
+        pciFreeDevice(conn, pci);
+        return -1;
+    }
+
+    cmd = reply = NULL;
+
+    if (virAsprintf(&cmd, "pci_add pci_addr=auto host host=%.2x:%.2x.%.1x",
+                    hostdev->source.subsys.u.pci.bus,
+                    hostdev->source.subsys.u.pci.slot,
+                    hostdev->source.subsys.u.pci.function) < 0) {
+        virReportOOMError(conn);
+        goto error;
+    }
+
+    if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
+        qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                         "%s", _("cannot attach host pci device"));
+        goto error;
+    }
+
+    if (strstr(reply, "invalid type: host")) {
+        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s",
+                         _("PCI device assignment is not supported by this version of qemu"));
+        goto error;
+    }
+
+    if (qemudParsePciAddReply(vm, reply, &domain, &bus, &slot) < 0) {
+        qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                         _("parsing pci_add reply failed: %s"), reply);
+        goto error;
+    }
+
+    hostdev->source.subsys.u.pci.guest_addr.domain = domain;
+    hostdev->source.subsys.u.pci.guest_addr.bus    = bus;
+    hostdev->source.subsys.u.pci.guest_addr.slot   = slot;
+
+    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
+
+    VIR_FREE(reply);
+    VIR_FREE(cmd);
+
+    return 0;
+
+error:
+    pciDeviceListDel(conn, driver->activePciHostdevs, pci);
+
+    VIR_FREE(reply);
+    VIR_FREE(cmd);
+
+    return -1;
+}
+
+static int qemudDomainAttachHostUsbDevice(virConnectPtr conn,
+                                          virDomainObjPtr vm,
+                                          virDomainDeviceDefPtr dev)
 {
     int ret;
     char *cmd, *reply;
@@ -5310,6 +5392,36 @@ static int qemudDomainAttachHostDevice(virConnectPtr conn,
     return 0;
 }
 
+static int qemudDomainAttachHostDevice(virConnectPtr conn,
+                                       struct qemud_driver *driver,
+                                       virDomainObjPtr vm,
+                                       virDomainDeviceDefPtr dev)
+{
+    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+
+    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
+        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+                         _("hostdev mode '%s' not supported"),
+                         virDomainHostdevModeTypeToString(hostdev->mode));
+        return -1;
+    }
+
+    if (qemuDomainSetDeviceOwnership(conn, driver, dev, 0) < 0)
+        return -1;
+
+    switch (hostdev->source.subsys.type) {
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
+        return qemudDomainAttachHostPciDevice(conn, driver, vm, dev);
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
+        return qemudDomainAttachHostUsbDevice(conn, vm, dev);
+    default:
+        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+                         _("hostdev subsys type '%s' not supported"),
+                         virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
+        return -1;
+    }
+}
+
 static int qemudDomainAttachDevice(virDomainPtr dom,
                                    const char *xml) {
     struct qemud_driver *driver = dom->conn->privateData;
@@ -5411,13 +5523,8 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
         }
     } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
         ret = qemudDomainAttachNetDevice(dom->conn, driver, vm, dev, qemuCmdFlags);
-    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
-               dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
-               dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
-        if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 0) < 0)
-            goto cleanup;
-
-        ret = qemudDomainAttachHostDevice(dom->conn, vm, dev);
+    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
+        ret = qemudDomainAttachHostDevice(dom->conn, driver, vm, dev);
     } else {
         qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                          _("device type '%s' cannot be attached"),
@@ -5630,6 +5737,143 @@ cleanup:
     return ret;
 }
 
+static int qemudDomainDetachHostPciDevice(virConnectPtr conn,
+                                          struct qemud_driver *driver,
+                                          virDomainObjPtr vm,
+                                          virDomainDeviceDefPtr dev)
+{
+    virDomainHostdevDefPtr detach;
+    char *cmd, *reply;
+    int i, ret;
+    pciDevice *pci;
+
+    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
+        unsigned domain   = vm->def->hostdevs[i]->source.subsys.u.pci.domain;
+        unsigned bus      = vm->def->hostdevs[i]->source.subsys.u.pci.bus;
+        unsigned slot     = vm->def->hostdevs[i]->source.subsys.u.pci.slot;
+        unsigned function = vm->def->hostdevs[i]->source.subsys.u.pci.function;
+
+        if (dev->data.hostdev->source.subsys.u.pci.domain   == domain &&
+            dev->data.hostdev->source.subsys.u.pci.bus      == bus &&
+            dev->data.hostdev->source.subsys.u.pci.slot     == slot &&
+            dev->data.hostdev->source.subsys.u.pci.function == function) {
+            detach = vm->def->hostdevs[i];
+            break;
+        }
+    }
+
+    if (!detach) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                         _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
+                         dev->data.hostdev->source.subsys.u.pci.domain,
+                         dev->data.hostdev->source.subsys.u.pci.bus,
+                         dev->data.hostdev->source.subsys.u.pci.slot,
+                         dev->data.hostdev->source.subsys.u.pci.function);
+        return -1;
+    }
+
+    if (!virHostdevHasValidGuestAddr(detach)) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                         "%s", _("hostdev cannot be detached - device state missing"));
+        return -1;
+    }
+
+    if (virAsprintf(&cmd, "pci_del pci_addr=%.4x:%.2x:%.2x",
+                    detach->source.subsys.u.pci.guest_addr.domain,
+                    detach->source.subsys.u.pci.guest_addr.bus,
+                    detach->source.subsys.u.pci.guest_addr.slot) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
+        qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                         "%s", _("cannot detach host pci device"));
+        VIR_FREE(cmd);
+        return -1;
+    }
+
+    DEBUG("%s: pci_del reply: %s", vm->def->name,  reply);
+
+    /* If the command fails due to a wrong PCI address qemu prints
+     * 'invalid pci address'; nothing is printed on success */
+    if (strstr(reply, "Invalid pci address")) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+                         _("failed to detach host pci device: invalid PCI address %.4x:%.2x:%.2x: %s"),
+                         detach->source.subsys.u.pci.guest_addr.domain,
+                         detach->source.subsys.u.pci.guest_addr.bus,
+                         detach->source.subsys.u.pci.guest_addr.slot,
+                         reply);
+        VIR_FREE(reply);
+        VIR_FREE(cmd);
+        return -1;
+    }
+
+    VIR_FREE(reply);
+    VIR_FREE(cmd);
+
+    ret = 0;
+
+    pci = pciGetDevice(conn,
+                       detach->source.subsys.u.pci.domain,
+                       detach->source.subsys.u.pci.bus,
+                       detach->source.subsys.u.pci.slot,
+                       detach->source.subsys.u.pci.function);
+    if (!pci)
+        ret = -1;
+    else {
+        pciDeviceListDel(conn, driver->activePciHostdevs, pci);
+        if (pciResetDevice(conn, pci, driver->activePciHostdevs) < 0)
+            ret = -1;
+        if (detach->managed && pciReAttachDevice(conn, pci) < 0)
+            ret = -1;
+        pciFreeDevice(conn, pci);
+    }
+
+    if (i != --vm->def->nhostdevs)
+        memmove(&vm->def->hostdevs[i],
+                &vm->def->hostdevs[i+1],
+                sizeof(*vm->def->hostdevs) * (vm->def->nhostdevs-i));
+    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs) < 0) {
+        virReportOOMError(conn);
+        ret = -1;
+    }
+
+    return ret;
+}
+
+static int qemudDomainDetachHostDevice(virConnectPtr conn,
+                                       struct qemud_driver *driver,
+                                       virDomainObjPtr vm,
+                                       virDomainDeviceDefPtr dev)
+{
+    virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+    int ret;
+
+    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
+        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+                         _("hostdev mode '%s' not supported"),
+                         virDomainHostdevModeTypeToString(hostdev->mode));
+        return -1;
+    }
+
+    switch (hostdev->source.subsys.type) {
+    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
+        ret = qemudDomainDetachHostPciDevice(conn, driver, vm, dev);
+        break;
+    default:
+        qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
+                         _("hostdev subsys type '%s' not supported"),
+                         virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
+        return -1;
+    }
+
+    if (qemuDomainSetDeviceOwnership(conn, driver, dev, 1) < 0)
+        VIR_WARN0("Fail to restore disk device ownership");
+
+    return ret;
+}
+
 static int qemudDomainDetachDevice(virDomainPtr dom,
                                    const char *xml) {
     struct qemud_driver *driver = dom->conn->privateData;
@@ -5670,6 +5914,8 @@ static int qemudDomainDetachDevice(virDomainPtr dom,
             VIR_WARN0("Fail to restore disk device ownership");
     } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
         ret = qemudDomainDetachNetDevice(dom->conn, vm, dev);
+    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
+        ret = qemudDomainDetachHostDevice(dom->conn, driver, vm, dev);
     } else
         qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
                          "%s", _("only SCSI or virtio disk device can be detached dynamically"));
-- 
1.6.2.5


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

--- NEW FILE libvirt-add-space-to-nodedev-list-tree.patch ---
>From 100eb35a80932cd9a162c38ecd2ab8b01894fb61 Mon Sep 17 00:00:00 2001
From: Mark McLoughlin <markmc at redhat.com>
Date: Mon, 17 Aug 2009 15:05:22 +0100
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 097c818bf00b3777778ffc32fea3a6ed1e741e2b)

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

diff --git a/src/virsh.c b/src/virsh.c
index 94c3c4e..2d0cf81 100644
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -5370,6 +5370,8 @@ cmdNodeListDevicesPrint(vshControl *ctl,
     if (depth && depth < MAX_DEPTH) {
         indentBuf[indentIdx] = '+';
         indentBuf[indentIdx+1] = '-';
+        indentBuf[indentIdx+2] = ' ';
+        indentBuf[indentIdx+3] = '\0';
     }
 
     /* Print this device */
@@ -5398,7 +5400,7 @@ cmdNodeListDevicesPrint(vshControl *ctl,
     /* If there is a child device, then print another blank line */
     if (nextlastdev != -1) {
         vshPrint(ctl, "%s", indentBuf);
-        vshPrint(ctl, "  |\n");
+        vshPrint(ctl, " |\n");
     }
 
     /* Finally print all children */
-- 
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 89eefbd116ae74c3a5cfcfc74a31a40b83c726c3 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 bd63692..4f1b01f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -278,7 +278,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 74f7ef0..96e5d6d 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -63,6 +63,7 @@ struct _pciDevice {
     unsigned      pci_pm_cap_pos;
     unsigned      has_flr : 1;
     unsigned      has_pm_reset : 1;
+    unsigned      managed : 1;
 };
 
 /* For virReportOOMError()  and virReportSystemError() */
@@ -225,7 +226,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.
@@ -236,7 +237,8 @@ static int
 pciIterDevices(virConnectPtr conn,
                pciIterPredicate predicate,
                pciDevice *dev,
-               pciDevice **matched)
+               pciDevice **matched,
+               void *data)
 {
     DIR *dir;
     struct dirent *entry;
@@ -254,7 +256,7 @@ pciIterDevices(virConnectPtr conn,
 
     while ((entry = readdir(dir))) {
         unsigned domain, bus, slot, function;
-        pciDevice *try;
+        pciDevice *check;
 
         /* Ignore '.' and '..' */
         if (entry->d_name[0] == '.')
@@ -266,18 +268,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;
@@ -379,63 +381,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;
 }
 
@@ -443,9 +452,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;
@@ -455,10 +466,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;
     }
 
@@ -572,10 +583,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;
 
@@ -594,7 +613,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();
@@ -890,8 +909,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 517626a..ab9d5e1 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -35,6 +35,7 @@
 #include "threads.h"
 #include "security.h"
 #include "cgroup.h"
+#include "pci.h"
 
 #define qemudDebug(fmt, ...) do {} while(0)
 
@@ -107,6 +108,8 @@ struct qemud_driver {
 
     char *securityDriverName;
     virSecurityDriverPtr securityDriver;
+
+    pciDeviceList *activePciHostdevs;
 };
 
 
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index fd39fc2..cbc27c4 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -128,6 +128,9 @@ static int qemudDomainSetMemoryBalloon(virConnectPtr conn,
 static int qemudDetectVcpuPIDs(virConnectPtr conn,
                                virDomainObjPtr vm);
 
+static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
+                                       virDomainDefPtr def);
+
 static struct qemud_driver *qemu_driver = NULL;
 
 static int qemuCgroupControllerActive(struct qemud_driver *driver,
@@ -320,6 +323,10 @@ qemuReconnectDomain(struct qemud_driver *driver,
         goto error;
     }
 
+    if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
+        goto error;
+    }
+
     if (obj->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
         driver->securityDriver &&
         driver->securityDriver->domainReserveSecurityLabel &&
@@ -524,6 +531,9 @@ qemudStartup(int privileged) {
     if ((qemu_driver->caps = qemudCapsInit(NULL)) == NULL)
         goto out_of_memory;
 
+    if ((qemu_driver->activePciHostdevs = pciDeviceListNew(NULL)) == NULL)
+        goto error;
+
     if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
         goto error;
     }
@@ -648,6 +658,7 @@ qemudShutdown(void) {
         return -1;
 
     qemuDriverLock(qemu_driver);
+    pciDeviceListFree(NULL, qemu_driver->activePciHostdevs);
     virCapabilitiesFree(qemu_driver->caps);
 
     virDomainObjListFree(&qemu_driver->domains);
@@ -1329,48 +1340,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;
@@ -1385,95 +1364,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 const char *const defaultDeviceACL[] = {
@@ -2001,7 +2036,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
     if (qemuSetupCgroup(conn, driver, vm) < 0)
         goto cleanup;
 
-    if (qemuPrepareHostDevices(conn, vm->def) < 0)
+    if (qemuPrepareHostDevices(conn, driver, vm->def) < 0)
         goto cleanup;
 
     if (VIR_ALLOC(vm->monitor_chr) < 0) {
@@ -2183,7 +2218,7 @@ static void qemudShutdownVMDaemon(virConnectPtr conn,
         VIR_WARN("Failed to restore all device ownership for %s",
                  vm->def->name);
 
-    qemuDomainReAttachHostDevices(conn, vm->def);
+    qemuDomainReAttachHostDevices(conn, driver, vm->def);
 
 retry:
     if ((ret = qemuRemoveCgroup(conn, driver, vm)) < 0) {
@@ -6791,6 +6826,7 @@ out:
 static int
 qemudNodeDeviceReset (virNodeDevicePtr dev)
 {
+    struct qemud_driver *driver = dev->conn->privateData;
     pciDevice *pci;
     unsigned domain, bus, slot, function;
     int ret = -1;
@@ -6802,11 +6838,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 f2ffc25..dfa9ca5 100644
--- a/src/xen_unified.c
+++ b/src/xen_unified.c
@@ -1641,7 +1641,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 5aad00b08cadc4d9da8bffd3d255ffaac98d36dd 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 2dc2e1c..11b3e8b 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -402,29 +402,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)
@@ -529,7 +506,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;
@@ -537,16 +514,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);
@@ -604,14 +571,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-fix-device-list-update-after-detach.patch:
 qemu_driver.c |   39 ++++++++++++++++++---------------------
 1 file changed, 18 insertions(+), 21 deletions(-)

--- NEW FILE libvirt-fix-device-list-update-after-detach.patch ---
>From 165fb333c9d954fec636dc0f1917ba50417478c0 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/network 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 qemudDomainDetachNetDevice() and
  qemudDomainDetachPciDiskDevice()

(cherry picked from commit 4e12af5623e4a962a6bb911af06fa29aa85befba)

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

diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index bd58435..2c4fd6f 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -5404,18 +5404,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:
@@ -5503,16 +5502,15 @@ qemudDomainDetachNetDevice(virConnectPtr conn,
 
     DEBUG("%s: host_net_remove reply: %s", vm->def->name,  reply);
 
-    if (vm->def->nnets > 1) {
-        vm->def->nets[i] = vm->def->nets[--vm->def->nnets];
-        if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets) < 0) {
-            virReportOOMError(conn);
-            goto cleanup;
-        }
-    } else {
-        VIR_FREE(vm->def->nets[0]);
-        vm->def->nnets = 0;
+    if (i != --vm->def->nnets)
+        memmove(&vm->def->nets[i],
+                &vm->def->nets[i+1],
+                sizeof(*vm->def->nets) * (vm->def->nnets-i));
+    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets) < 0) {
+        virReportOOMError(conn);
+        goto cleanup;
     }
+
     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 c8a9dbe131713de83bdc67c563c4ab149e32c489 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 11b3e8b..74f7ef0 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -456,15 +456,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;
     }
 
@@ -475,7 +478,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;
     }
 
@@ -492,9 +497,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);
@@ -516,7 +524,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;
     }
 
@@ -533,8 +543,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;
 }
@@ -582,10 +596,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 4ce7a54..fd39fc2 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -1465,9 +1465,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 8f26acc66ca90eea67fd5e84be5a76e3b8aa7fbf 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 2c4fd6f..4ce7a54 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -1402,6 +1402,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 const char *const defaultDeviceACL[] = {
     "/dev/null", "/dev/full", "/dev/zero",
     "/dev/random", "/dev/urandom",
@@ -2109,6 +2183,8 @@ static void qemudShutdownVMDaemon(virConnectPtr conn,
         VIR_WARN("Failed to restore all device ownership for %s",
                  vm->def->name);
 
+    qemuDomainReAttachHostDevices(conn, vm->def);
+
 retry:
     if ((ret = qemuRemoveCgroup(conn, driver, vm)) < 0) {
         if (ret == -EBUSY && (retries++ < 5)) {
-- 
1.6.2.5


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

Index: libvirt-0.6.4-svirt-sound.patch
===================================================================
RCS file: /cvs/pkgs/rpms/libvirt/devel/libvirt-0.6.4-svirt-sound.patch,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -p -r1.2 -r1.3
--- libvirt-0.6.4-svirt-sound.patch	17 Aug 2009 08:08:46 -0000	1.2
+++ libvirt-0.6.4-svirt-sound.patch	19 Aug 2009 16:26:27 -0000	1.3
@@ -1,4 +1,4 @@
-From f9355301cf4dda452308b616e8c00e59be5aec0a Mon Sep 17 00:00:00 2001
+From 1e99b2edee0eb3ca1c600e5bd5c55741cb95a29a Mon Sep 17 00:00:00 2001
 From: Daniel P. Berrange <berrange at redhat.com>
 Date: Mon, 17 Aug 2009 08:32:08 +0100
 Subject: [PATCH] Disable sound cards when running sVirt


Index: libvirt.spec
===================================================================
RCS file: /cvs/pkgs/rpms/libvirt/devel/libvirt.spec,v
retrieving revision 1.170
retrieving revision 1.171
diff -u -p -r1.170 -r1.171
--- libvirt.spec	17 Aug 2009 08:08:46 -0000	1.170
+++ libvirt.spec	19 Aug 2009 16:26:27 -0000	1.171
@@ -96,6 +96,27 @@ Patch03: libvirt-0.7.0-policy-kit-rewrit
 # Log and ignore NUMA topology problems (rhbz #506590)
 Patch04: libvirt-0.7.0-numa-ignore-fail.patch
 
+# Minor 'virsh nodedev-list --tree' annoyance, fix from upstream
+Patch05: libvirt-add-space-to-nodedev-list-tree.patch
+
+# Fixes list corruption after disk hot-unplug
+Patch06: libvirt-fix-device-list-update-after-detach.patch
+
+# Re-attach PCI host devices after guest shuts down (bug #499561)
+Patch07: libvirt-reattach-pci-hostdevs-after-guest-shutdown.patch
+
+# Allow PM reset on multi-function PCI devices (bug #515689)
+Patch08: libvirt-allow-pm-reset-on-multi-function-pci-devices.patch
+
+# Fix stupid PCI reset error message (#499678)
+Patch09: libvirt-improve-pci-hostdev-reset-error-message.patch
+
+# Allow PCI bus reset to reset other devices (#499678)
+Patch10: libvirt-allow-pci-hostdev-reset-to-reset-other-devices.patch
+
+# Add PCI host device hotplug support
+Patch11: libvirt-add-pci-hostdev-hotplug-support.patch
+
 # Temporary hack till PulseAudio autostart problems are sorted
 # out when SELinux enforcing (bz 486112)
 Patch200: libvirt-0.6.4-svirt-sound.patch
@@ -281,6 +302,13 @@ of recent versions of Linux (and other O
 %patch02 -p1
 %patch03 -p1
 %patch04 -p1
+%patch05 -p1
+%patch06 -p1
+%patch07 -p1
+%patch08 -p1
+%patch09 -p1
+%patch10 -p1
+%patch11 -p1
 
 %patch200 -p1
 
@@ -649,6 +677,15 @@ fi
 %endif
 
 %changelog
+* Wed Aug 19 2009 Mark McLoughlin <markmc at redhat.com> - 0.7.0-5
+- Add PCI host device hotplug support
+- 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)
+- Fix 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.7.0-4
 - Rewrite policykit support (rhbz #499970)
 - Log and ignore NUMA topology problems (rhbz #506590)




More information about the fedora-extras-commits mailing list