Mark McLoughlin c034c1
From 8f26acc66ca90eea67fd5e84be5a76e3b8aa7fbf Mon Sep 17 00:00:00 2001
Mark McLoughlin c034c1
From: Mark McLoughlin <markmc@redhat.com>
Mark McLoughlin c034c1
Date: Fri, 14 Aug 2009 08:31:11 +0100
Mark McLoughlin c034c1
Subject: [PATCH] Reset and re-attach PCI host devices on guest shutdown
Mark McLoughlin c034c1
Mark McLoughlin c034c1
https://bugzilla.redhat.com/499561
Mark McLoughlin c034c1
Mark McLoughlin c034c1
When the guest shuts down, we should attempt to restore all PCI host
Mark McLoughlin c034c1
devices to a sane state.
Mark McLoughlin c034c1
Mark McLoughlin c034c1
In the case of managed hostdevs, we should reset and re-attach the
Mark McLoughlin c034c1
devices. In the case of unmanaged hostdevs, we should just reset them.
Mark McLoughlin c034c1
Mark McLoughlin c034c1
Note, KVM will already reset assigned devices when the guest shuts
Mark McLoughlin c034c1
down using whatever means it can, so we are only doing it to cover the
Mark McLoughlin c034c1
cases the kernel can't handle.
Mark McLoughlin c034c1
Mark McLoughlin c034c1
* src/qemu_driver.c: add qemuDomainReAttachHostDevices() and call
Mark McLoughlin c034c1
  it from qemudShutdownVMDaemon()
Mark McLoughlin c034c1
Mark McLoughlin c034c1
(cherry picked from commit 4035152a8767e72fd4e26a91cb4d5afa75b72e61)
Mark McLoughlin c034c1
Mark McLoughlin c034c1
Fedora-patch: libvirt-reattach-pci-hostdevs-after-guest-shutdown.patch
Mark McLoughlin c034c1
---
Mark McLoughlin c034c1
 src/qemu_driver.c |   76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
Mark McLoughlin c034c1
 1 files changed, 76 insertions(+), 0 deletions(-)
Mark McLoughlin c034c1
Mark McLoughlin c034c1
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
Mark McLoughlin c034c1
index 2c4fd6f..4ce7a54 100644
Mark McLoughlin c034c1
--- a/src/qemu_driver.c
Mark McLoughlin c034c1
+++ b/src/qemu_driver.c
Mark McLoughlin c034c1
@@ -1402,6 +1402,80 @@ error:
Mark McLoughlin c034c1
     return -1;
Mark McLoughlin c034c1
 }
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
+static void
Mark McLoughlin c034c1
+qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainDefPtr def)
Mark McLoughlin c034c1
+{
Mark McLoughlin c034c1
+    int i;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    /* Again 2 loops; reset all the devices before re-attach */
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    for (i = 0 ; i < def->nhostdevs ; i++) {
Mark McLoughlin c034c1
+        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
Mark McLoughlin c034c1
+        pciDevice *dev;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
Mark McLoughlin c034c1
+            continue;
Mark McLoughlin c034c1
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
Mark McLoughlin c034c1
+            continue;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        dev = pciGetDevice(conn,
Mark McLoughlin c034c1
+                           hostdev->source.subsys.u.pci.domain,
Mark McLoughlin c034c1
+                           hostdev->source.subsys.u.pci.bus,
Mark McLoughlin c034c1
+                           hostdev->source.subsys.u.pci.slot,
Mark McLoughlin c034c1
+                           hostdev->source.subsys.u.pci.function);
Mark McLoughlin c034c1
+        if (!dev) {
Mark McLoughlin c034c1
+            virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
+            VIR_ERROR(_("Failed to allocate pciDevice: %s\n"),
Mark McLoughlin c034c1
+                      err ? err->message : "");
Mark McLoughlin c034c1
+            virResetError(err);
Mark McLoughlin c034c1
+            continue;
Mark McLoughlin c034c1
+        }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        if (pciResetDevice(conn, dev) < 0) {
Mark McLoughlin c034c1
+            virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
+            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
Mark McLoughlin c034c1
+                      err ? err->message : "");
Mark McLoughlin c034c1
+            virResetError(err);
Mark McLoughlin c034c1
+        }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        pciFreeDevice(conn, dev);
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+    for (i = 0 ; i < def->nhostdevs ; i++) {
Mark McLoughlin c034c1
+        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
Mark McLoughlin c034c1
+        pciDevice *dev;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
Mark McLoughlin c034c1
+            continue;
Mark McLoughlin c034c1
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
Mark McLoughlin c034c1
+            continue;
Mark McLoughlin c034c1
+        if (!hostdev->managed)
Mark McLoughlin c034c1
+            continue;
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        dev = pciGetDevice(conn,
Mark McLoughlin c034c1
+                           hostdev->source.subsys.u.pci.domain,
Mark McLoughlin c034c1
+                           hostdev->source.subsys.u.pci.bus,
Mark McLoughlin c034c1
+                           hostdev->source.subsys.u.pci.slot,
Mark McLoughlin c034c1
+                           hostdev->source.subsys.u.pci.function);
Mark McLoughlin c034c1
+        if (!dev) {
Mark McLoughlin c034c1
+            virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
+            VIR_ERROR(_("Failed to allocate pciDevice: %s\n"),
Mark McLoughlin c034c1
+                      err ? err->message : "");
Mark McLoughlin c034c1
+            virResetError(err);
Mark McLoughlin c034c1
+            continue;
Mark McLoughlin c034c1
+        }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        if (pciDettachDevice(conn, dev) < 0) {
Mark McLoughlin c034c1
+            virErrorPtr err = virGetLastError();
Mark McLoughlin c034c1
+            VIR_ERROR(_("Failed to reset PCI device: %s\n"),
Mark McLoughlin c034c1
+                      err ? err->message : "");
Mark McLoughlin c034c1
+            virResetError(err);
Mark McLoughlin c034c1
+        }
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
+        pciFreeDevice(conn, dev);
Mark McLoughlin c034c1
+    }
Mark McLoughlin c034c1
+}
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
 static const char *const defaultDeviceACL[] = {
Mark McLoughlin c034c1
     "/dev/null", "/dev/full", "/dev/zero",
Mark McLoughlin c034c1
     "/dev/random", "/dev/urandom",
Mark McLoughlin c034c1
@@ -2109,6 +2183,8 @@ static void qemudShutdownVMDaemon(virConnectPtr conn,
Mark McLoughlin c034c1
         VIR_WARN("Failed to restore all device ownership for %s",
Mark McLoughlin c034c1
                  vm->def->name);
Mark McLoughlin c034c1
 
Mark McLoughlin c034c1
+    qemuDomainReAttachHostDevices(conn, vm->def);
Mark McLoughlin c034c1
+
Mark McLoughlin c034c1
 retry:
Mark McLoughlin c034c1
     if ((ret = qemuRemoveCgroup(conn, driver, vm)) < 0) {
Mark McLoughlin c034c1
         if (ret == -EBUSY && (retries++ < 5)) {
Mark McLoughlin c034c1
-- 
Mark McLoughlin c034c1
1.6.2.5
Mark McLoughlin c034c1