render / rpms / libvirt

Forked from rpms/libvirt 10 months ago
Clone
43fe83
From 676f5e9952f7cbc09ad54d77e09d864f61874a6d Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <676f5e9952f7cbc09ad54d77e09d864f61874a6d.1382534060.git.jdenemar@redhat.com>
43fe83
From: Peter Krempa <pkrempa@redhat.com>
43fe83
Date: Thu, 10 Oct 2013 13:56:36 +0200
43fe83
Subject: [PATCH] qemu: hostdev: Add checks if PCI passthrough is available in
43fe83
 the host
43fe83
43fe83
https://bugzilla.redhat.com/show_bug.cgi?id=1001738
43fe83
43fe83
Add code to check availability of PCI passhthrough using VFIO and the
43fe83
legacy KVM passthrough and use it when starting VMs and hotplugging
43fe83
devices to live machine.
43fe83
43fe83
(cherry picked from commit 467b561ac2ca7cb968d7a1d781e715cdd7bf3d14)
43fe83
43fe83
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
43fe83
---
43fe83
 src/qemu/qemu_hostdev.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++
43fe83
 1 file changed, 125 insertions(+)
43fe83
43fe83
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
43fe83
index 4127abd..7f3170d 100644
43fe83
--- a/src/qemu/qemu_hostdev.c
43fe83
+++ b/src/qemu/qemu_hostdev.c
43fe83
@@ -23,6 +23,11 @@
43fe83
 
43fe83
 #include <config.h>
43fe83
 
43fe83
+#include <dirent.h>
43fe83
+#include <fcntl.h>
43fe83
+#include <sys/ioctl.h>
43fe83
+#include <errno.h>
43fe83
+
43fe83
 #include "qemu_hostdev.h"
43fe83
 #include "virlog.h"
43fe83
 #include "virerror.h"
43fe83
@@ -31,6 +36,7 @@
43fe83
 #include "virusb.h"
43fe83
 #include "virscsi.h"
43fe83
 #include "virnetdev.h"
43fe83
+#include "virfile.h"
43fe83
 
43fe83
 #define VIR_FROM_THIS VIR_FROM_QEMU
43fe83
 
43fe83
@@ -486,6 +492,122 @@ qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
43fe83
 }
43fe83
 
43fe83
 
43fe83
+static bool
43fe83
+qemuHostdevHostSupportsPassthroughVFIO(void)
43fe83
+{
43fe83
+    DIR *iommuDir = NULL;
43fe83
+    struct dirent *iommuGroup = NULL;
43fe83
+    bool ret = false;
43fe83
+
43fe83
+    /* condition 1 - /sys/kernel/iommu_groups/ contains entries */
43fe83
+    if (!(iommuDir = opendir("/sys/kernel/iommu_groups/")))
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    while ((iommuGroup = readdir(iommuDir))) {
43fe83
+        /* skip ./ ../ */
43fe83
+        if (STRPREFIX(iommuGroup->d_name, "."))
43fe83
+            continue;
43fe83
+
43fe83
+        /* assume we found a group */
43fe83
+        break;
43fe83
+    }
43fe83
+
43fe83
+    if (!iommuGroup)
43fe83
+        goto cleanup;
43fe83
+    /* okay, iommu is on and recognizes groups */
43fe83
+
43fe83
+    /* condition 2 - /dev/vfio/vfio exists */
43fe83
+    if (!virFileExists("/dev/vfio/vfio"))
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    ret = true;
43fe83
+
43fe83
+cleanup:
43fe83
+    if (iommuDir)
43fe83
+        closedir(iommuDir);
43fe83
+
43fe83
+    return ret;
43fe83
+}
43fe83
+
43fe83
+
43fe83
+#if HAVE_LINUX_KVM_H
43fe83
+# include <linux/kvm.h>
43fe83
+static bool
43fe83
+qemuHostdevHostSupportsPassthroughLegacy(void)
43fe83
+{
43fe83
+    int kvmfd = -1;
43fe83
+    bool ret = false;
43fe83
+
43fe83
+    if ((kvmfd = open("/dev/kvm", O_RDONLY)) < 0)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+# ifdef KVM_CAP_IOMMU
43fe83
+    if ((ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_IOMMU)) <= 0)
43fe83
+        goto cleanup;
43fe83
+
43fe83
+    ret = true;
43fe83
+# endif
43fe83
+
43fe83
+cleanup:
43fe83
+    VIR_FORCE_CLOSE(kvmfd);
43fe83
+
43fe83
+    return ret;
43fe83
+}
43fe83
+#else
43fe83
+static bool
43fe83
+qemuHostdevHostSupportsPassthroughLegacy(void)
43fe83
+{
43fe83
+    return false;
43fe83
+}
43fe83
+#endif
43fe83
+
43fe83
+
43fe83
+static bool
43fe83
+qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
43fe83
+                                  size_t nhostdevs)
43fe83
+{
43fe83
+    bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy();
43fe83
+    bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
43fe83
+    size_t i;
43fe83
+
43fe83
+    /* assign defaults for hostdev passthrough */
43fe83
+    for (i = 0; i < nhostdevs; i++) {
43fe83
+        virDomainHostdevDefPtr hostdev = hostdevs[i];
43fe83
+        int *backend = &hostdev->source.subsys.u.pci.backend;
43fe83
+
43fe83
+        if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
43fe83
+            continue;
43fe83
+        if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
43fe83
+            continue;
43fe83
+
43fe83
+        switch ((virDomainHostdevSubsysPciBackendType) *backend) {
43fe83
+        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
43fe83
+            if (!supportsPassthroughVFIO) {
43fe83
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
43fe83
+                               _("host doesn't support VFIO PCI passthrough"));
43fe83
+                return false;
43fe83
+            }
43fe83
+            break;
43fe83
+
43fe83
+        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
43fe83
+        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
43fe83
+            if (!supportsPassthroughKVM) {
43fe83
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
43fe83
+                               _("host doesn't support legacy PCI passthrough"));
43fe83
+                return false;
43fe83
+            }
43fe83
+
43fe83
+            break;
43fe83
+
43fe83
+        case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
43fe83
+            break;
43fe83
+        }
43fe83
+    }
43fe83
+
43fe83
+    return true;
43fe83
+}
43fe83
+
43fe83
+
43fe83
 int
43fe83
 qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
43fe83
                              const char *name,
43fe83
@@ -499,6 +621,9 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
43fe83
     int ret = -1;
43fe83
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
43fe83
 
43fe83
+    if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs))
43fe83
+        goto cleanup;
43fe83
+
43fe83
     virObjectLock(driver->activePciHostdevs);
43fe83
     virObjectLock(driver->inactivePciHostdevs);
43fe83
 
43fe83
-- 
43fe83
1.8.4
43fe83