diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 8f744871d2..8c998db176 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -2757,11 +2757,10 @@
backend, which is compatible with UEFI SecureBoot) or "kvm"
(for the legacy device assignment handled directly by the KVM
kernel module)Since 1.0.5 (QEMU and KVM
- only, requires kernel 3.6 or newer). Currently, "kvm"
- is the default used by libvirt when not explicitly provided,
- but since the two are functionally equivalent, this default
- could be changed in the future with no impact to domains that
- don't specify anything.
+ only, requires kernel 3.6 or newer). The default, when
+ the driver name is not explicitly specified, is to check wether
+ VFIO is available and use it if it's the case. If VFIO is not
+ available, the legacy "kvm" assignment is attempted.
readonly
Indicates that the device is readonly, only supported by SCSI host
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 5d5e4431f9..df28fa684d 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -399,7 +399,7 @@ enum virDomainHostdevSubsysType {
/* the backend driver used for PCI hostdev devices */
typedef enum {
- VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, /* currently kvm, could change */
+ VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, /* detect automaticaly, prefer VFIO */
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM, /* force legacy kvm style */
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO, /* force vfio */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index fe40834c0c..cdeb8e06e6 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -262,6 +262,7 @@ virDomainHostdevFind;
virDomainHostdevInsert;
virDomainHostdevModeTypeToString;
virDomainHostdevRemove;
+virDomainHostdevSubsysPciBackendTypeToString;
virDomainHostdevSubsysTypeToString;
virDomainHubTypeFromString;
virDomainHubTypeToString;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 52dc295254..22cc5f227f 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -5484,10 +5484,10 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
virQEMUCapsPtr qemuCaps)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int backend = dev->source.subsys.u.pci.backend;
- switch ((virDomainHostdevSubsysPciBackendType)
- dev->source.subsys.u.pci.backend) {
- case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
+ /* caller has to assign proper passthrough backend type */
+ switch ((virDomainHostdevSubsysPciBackendType) backend) {
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
virBufferAddLit(&buf, "pci-assign");
if (configfd && *configfd)
@@ -5498,9 +5498,11 @@ qemuBuildPCIHostdevDevStr(virDomainDefPtr def,
virBufferAddLit(&buf, "vfio-pci");
break;
+ case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_TYPE_LAST:
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("PCI passhthrough type needs to be specified"));
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("invalid PCI passthrough type '%s'"),
+ virDomainHostdevSubsysPciBackendTypeToString(backend));
break;
}
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
index 7f3170d5f8..81e0e8848c 100644
--- a/src/qemu/qemu_hostdev.c
+++ b/src/qemu/qemu_hostdev.c
@@ -564,7 +564,8 @@ qemuHostdevHostSupportsPassthroughLegacy(void)
static bool
qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
- size_t nhostdevs)
+ size_t nhostdevs,
+ virQEMUCapsPtr qemuCaps)
{
bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy();
bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
@@ -581,6 +582,23 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
continue;
switch ((virDomainHostdevSubsysPciBackendType) *backend) {
+ case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
+ if (supportsPassthroughVFIO &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI)) {
+ *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
+ } else if (supportsPassthroughKVM &&
+ (virQEMUCapsGet(qemuCaps, QEMU_CAPS_PCIDEVICE) ||
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE))) {
+ *backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("host doesn't support passthrough of "
+ "host PCI devices"));
+ return false;
+ }
+
+ break;
+
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO:
if (!supportsPassthroughVFIO) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -589,7 +607,6 @@ qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
}
break;
- case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT:
case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM:
if (!supportsPassthroughKVM) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
@@ -613,7 +630,8 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
const char *name,
const unsigned char *uuid,
virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
+ int nhostdevs,
+ virQEMUCapsPtr qemuCaps)
{
virPCIDeviceListPtr pcidevs;
int last_processed_hostdev_vf = -1;
@@ -621,7 +639,7 @@ qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
int ret = -1;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
- if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs))
+ if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps))
goto cleanup;
virObjectLock(driver->activePciHostdevs);
@@ -1142,13 +1160,15 @@ cleanup:
int
qemuPrepareHostDevices(virQEMUDriverPtr driver,
virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
bool coldBoot)
{
if (!def->nhostdevs)
return 0;
if (qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid,
- def->hostdevs, def->nhostdevs) < 0)
+ def->hostdevs, def->nhostdevs,
+ qemuCaps) < 0)
return -1;
if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h
index 327d4d5679..272086effa 100644
--- a/src/qemu/qemu_hostdev.h
+++ b/src/qemu/qemu_hostdev.h
@@ -37,7 +37,8 @@ int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
const char *name,
const unsigned char *uuid,
virDomainHostdevDefPtr *hostdevs,
- int nhostdevs);
+ int nhostdevs,
+ virQEMUCapsPtr qemuCaps);
int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
bool mandatory,
virUSBDevicePtr *usb);
@@ -50,6 +51,7 @@ int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
int nhostdevs);
int qemuPrepareHostDevices(virQEMUDriverPtr driver,
virDomainDefPtr def,
+ virQEMUCapsPtr qemuCaps,
bool coldBoot);
void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
const char *name,
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 71c78226b7..b6ae21870e 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1140,7 +1140,7 @@ int qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver,
return -1;
if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid,
- &hostdev, 1) < 0)
+ &hostdev, 1, priv->qemuCaps) < 0)
return -1;
switch ((virDomainHostdevSubsysPciBackendType) backend) {
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 079f062bcd..354e079a75 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3567,6 +3567,12 @@ int qemuProcessStart(virConnectPtr conn,
goto cleanup;
}
+ VIR_DEBUG("Determining emulator version");
+ virObjectUnref(priv->qemuCaps);
+ if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache,
+ vm->def->emulator)))
+ goto cleanup;
+
/* network devices must be "prepared" before hostdevs, because
* setting up a network device might create a new hostdev that
* will need to be setup.
@@ -3577,7 +3583,8 @@ int qemuProcessStart(virConnectPtr conn,
/* Must be run before security labelling */
VIR_DEBUG("Preparing host devices");
- if (qemuPrepareHostDevices(driver, vm->def, !migrateFrom) < 0)
+ if (qemuPrepareHostDevices(driver, vm->def, priv->qemuCaps,
+ !migrateFrom) < 0)
goto cleanup;
VIR_DEBUG("Preparing chr devices");
@@ -3659,12 +3666,6 @@ int qemuProcessStart(virConnectPtr conn,
}
}
- VIR_DEBUG("Determining emulator version");
- virObjectUnref(priv->qemuCaps);
- if (!(priv->qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache,
- vm->def->emulator)))
- goto cleanup;
-
if (!qemuValidateCpuMax(vm->def, priv->qemuCaps))
goto cleanup;
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 286f1a3628..060acf29ba 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -98,6 +98,7 @@ static int testCompareXMLToArgvFiles(const char *xml,
virConnectPtr conn;
char *log = NULL;
virCommandPtr cmd = NULL;
+ size_t i;
if (!(conn = virGetConnect()))
goto out;
@@ -154,6 +155,16 @@ static int testCompareXMLToArgvFiles(const char *xml,
if (qemuAssignDeviceAliases(vmdef, extraFlags) < 0)
goto out;
+ for (i = 0; i < vmdef->nhostdevs; i++) {
+ virDomainHostdevDefPtr hostdev = vmdef->hostdevs[i];
+
+ if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+ hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
+ hostdev->source.subsys.u.pci.backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT) {
+ hostdev->source.subsys.u.pci.backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
+ }
+ }
+
if (!(cmd = qemuBuildCommandLine(conn, &driver, vmdef, &monitor_chr,
(flags & FLAG_JSON), extraFlags,
migrateFrom, migrateFd, NULL,