|
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 |
|