[libvirt] [PATCHv4 2/3] qemu: hostdev: Add checks if PCI passthrough is availabe in the host
Laine Stump
laine at laine.org
Wed Oct 9 12:58:18 UTC 2013
On 10/08/2013 06:46 PM, Peter Krempa wrote:
> Add code to check availability of PCI passhthrough using VFIO and the
> legacy KVM passthrough and use it when starting VMs and hotplugging
> devices to live machine.
> ---
>
> Notes:
> Version 4:
> - moved this function so that it can be called from qemuPrepareHostdevPCIDevices()
> - now caching the support for passthrough types right away
>
> src/qemu/qemu_hostdev.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 125 insertions(+)
>
> diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
> index 4127abd..7f3170d 100644
> --- a/src/qemu/qemu_hostdev.c
> +++ b/src/qemu/qemu_hostdev.c
> @@ -23,6 +23,11 @@
>
> #include <config.h>
>
> +#include <dirent.h>
> +#include <fcntl.h>
> +#include <sys/ioctl.h>
> +#include <errno.h>
> +
> #include "qemu_hostdev.h"
> #include "virlog.h"
> #include "virerror.h"
> @@ -31,6 +36,7 @@
> #include "virusb.h"
> #include "virscsi.h"
> #include "virnetdev.h"
> +#include "virfile.h"
>
> #define VIR_FROM_THIS VIR_FROM_QEMU
>
> @@ -486,6 +492,122 @@ qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
> }
>
>
> +static bool
> +qemuHostdevHostSupportsPassthroughVFIO(void)
> +{
> + DIR *iommuDir = NULL;
> + struct dirent *iommuGroup = NULL;
> + bool ret = false;
> +
> + /* condition 1 - /sys/kernel/iommu_groups/ contains entries */
> + if (!(iommuDir = opendir("/sys/kernel/iommu_groups/")))
> + goto cleanup;
> +
> + while ((iommuGroup = readdir(iommuDir))) {
> + /* skip ./ ../ */
> + if (STRPREFIX(iommuGroup->d_name, "."))
> + continue;
> +
> + /* assume we found a group */
> + break;
> + }
> +
> + if (!iommuGroup)
> + goto cleanup;
> + /* okay, iommu is on and recognizes groups */
> +
> + /* condition 2 - /dev/vfio/vfio exists */
> + if (!virFileExists("/dev/vfio/vfio"))
> + goto cleanup;
> +
> + ret = true;
> +
> +cleanup:
> + if (iommuDir)
> + closedir(iommuDir);
> +
> + return ret;
> +}
> +
> +
> +#if HAVE_LINUX_KVM_H
> +# include <linux/kvm.h>
> +static bool
> +qemuHostdevHostSupportsPassthroughLegacy(void)
> +{
> + int kvmfd = -1;
> + bool ret = false;
> +
> + if ((kvmfd = open("/dev/kvm", O_RDONLY)) < 0)
> + goto cleanup;
> +
> +# ifdef KVM_CAP_IOMMU
> + if ((ioctl(kvmfd, KVM_CHECK_EXTENSION, KVM_CAP_IOMMU)) <= 0)
> + goto cleanup;
> +
> + ret = true;
> +# endif
> +
> +cleanup:
> + VIR_FORCE_CLOSE(kvmfd);
> +
> + return ret;
> +}
> +#else
> +static bool
> +qemuHostdevHostSupportsPassthroughLegacy(void)
> +{
> + return false;
> +}
> +#endif
> +
> +
> +static bool
> +qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
> + size_t nhostdevs)
> +{
> + bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy();
> + bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
I just double checked, and these two calls won't ever be done
unnecessarily, because qemuPrepareHostdevPCIDevices() is never called
unless there will be at least one hostdev added.
> + size_t i;
> +
> + /* assign defaults for hostdev passthrough */
> + for (i = 0; i < nhostdevs; i++) {
> + virDomainHostdevDefPtr hostdev = hostdevs[i];
> + int *backend = &hostdev->source.subsys.u.pci.backend;
> +
> + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
> + continue;
> + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
> + continue;
> +
> + switch ((virDomainHostdevSubsysPciBackendType) *backend) {
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
> + if (!supportsPassthroughVFIO) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("host doesn't support VFIO PCI passthrough"));
> + return false;
> + }
> + break;
> +
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
> + if (!supportsPassthroughKVM) {
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> + _("host doesn't support legacy PCI passthrough"));
> + return false;
> + }
> +
> + break;
> +
> + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
> + break;
> + }
> + }
> +
> + return true;
> +}
> +
> +
> int
> qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
> const char *name,
> @@ -499,6 +621,9 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
> int ret = -1;
> virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
>
> + if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs))
> + goto cleanup;
> +
> virObjectLock(driver->activePciHostdevs);
> virObjectLock(driver->inactivePciHostdevs);
>
ACK.
More information about the libvir-list
mailing list