Change qemu driver to use hostdev common library instead of APIs in
qemu_hostdev.[ch] Improve some test files.
Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
---
po/POTFILES.in | 1 -
src/Makefile.am | 1 -
src/qemu/qemu_command.c | 1 -
src/qemu/qemu_conf.h | 9 +-
src/qemu/qemu_domain.c | 22 +
src/qemu/qemu_driver.c | 83 +-
src/qemu/qemu_hostdev.c | 1466 --------------------
src/qemu/qemu_hostdev.h | 76 -
src/qemu/qemu_hotplug.c | 132 +-
src/qemu/qemu_process.c | 40 +-
.../qemuxml2argv-hostdev-pci-address.xml | 1 +
.../qemuxml2argvdata/qemuxml2argv-net-hostdev.xml | 1 +
tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml | 2 +
13 files changed, 130 insertions(+), 1705 deletions(-)
delete mode 100644 src/qemu/qemu_hostdev.c
delete mode 100644 src/qemu/qemu_hostdev.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ba63428..fcd3af9 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -100,7 +100,6 @@ src/qemu/qemu_command.c
src/qemu/qemu_conf.c
src/qemu/qemu_domain.c
src/qemu/qemu_driver.c
-src/qemu/qemu_hostdev.c
src/qemu/qemu_hotplug.c
src/qemu/qemu_migration.c
src/qemu/qemu_monitor.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 98233cd..8b4a25c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -674,7 +674,6 @@ QEMU_DRIVER_SOURCES = \
qemu/qemu_command.c qemu/qemu_command.h \
qemu/qemu_domain.c qemu/qemu_domain.h \
qemu/qemu_cgroup.c qemu/qemu_cgroup.h \
- qemu/qemu_hostdev.c qemu/qemu_hostdev.h \
qemu/qemu_hotplug.c qemu/qemu_hotplug.h \
qemu/qemu_hotplugpriv.h \
qemu/qemu_conf.c qemu/qemu_conf.h \
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index d723dc8..d50c9aa 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -24,7 +24,6 @@
#include <config.h>
#include "qemu_command.h"
-#include "qemu_hostdev.h"
#include "qemu_capabilities.h"
#include "qemu_bridge_filter.h"
#include "cpu/cpu.h"
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 1f44a76..ff5836d 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -53,6 +53,7 @@
# error "Port me"
# endif
+# define QEMU_DRIVER_NAME "QEMU"
typedef struct _virQEMUDriver virQEMUDriver;
typedef virQEMUDriver *virQEMUDriverPtr;
@@ -213,14 +214,6 @@ struct _virQEMUDriver {
/* Immutable pointer. self-locking APIs */
virSecurityManagerPtr securityManager;
- /* Immutable pointers. Requires locks to be held before
- * calling APIs. activePciHostdevs must be locked before
- * inactivePciHostdevs */
- virPCIDeviceListPtr activePciHostdevs;
- virPCIDeviceListPtr inactivePciHostdevs;
- virUSBDeviceListPtr activeUsbHostdevs;
- virSCSIDeviceListPtr activeScsiHostdevs;
-
/* Immutable pointer. Unsafe APIs. XXX */
virHashTablePtr sharedDevices;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index e964c75..76b0dc2 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -38,6 +38,7 @@
#include "virtime.h"
#include "virstoragefile.h"
#include "virstring.h"
+#include "virhostdev.h"
#include <sys/time.h>
#include <fcntl.h>
@@ -817,6 +818,7 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
int ret = -1;
virQEMUDriverPtr driver = opaque;
virQEMUDriverConfigPtr cfg = NULL;
+ virQEMUCapsPtr qemuCaps = NULL;
if (dev->type == VIR_DOMAIN_DEVICE_NET &&
dev->data.net->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
@@ -895,6 +897,26 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
dev->data.chr->source.data.nix.listen = true;
}
+ if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
+ virDomainHostdevDefPtr hostdev = dev->data.hostdev;
+ 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 (driver && driver->qemuCapsCache) {
+ bool supportsPassthroughVFIO = virHostdevHostSupportsPassthroughVFIO();
+ qemuCaps = virQEMUCapsCacheLookupCopy(driver->qemuCapsCache,
+ def->emulator);
+ if (supportsPassthroughVFIO && qemuCaps &&
+ virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI))
+ hostdev->source.subsys.u.pci.backend =
VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
+
+ virObjectUnref(qemuCaps);
+ }
+ }
+ }
+
ret = 0;
cleanup:
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 90820ab..3209dc1 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -50,7 +50,6 @@
#include "qemu_capabilities.h"
#include "qemu_command.h"
#include "qemu_cgroup.h"
-#include "qemu_hostdev.h"
#include "qemu_hotplug.h"
#include "qemu_monitor.h"
#include "qemu_bridge_filter.h"
@@ -94,11 +93,10 @@
#include "virstring.h"
#include "viraccessapicheck.h"
#include "viraccessapicheckqemu.h"
+#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
-#define QEMU_DRIVER_NAME "QEMU"
-
#define QEMU_NB_MEM_PARAM 3
#define QEMU_NB_BLOCK_IO_TUNE_PARAM 6
@@ -698,18 +696,6 @@ qemuStateInitialize(bool privileged,
if (qemuSecurityInit(qemu_driver) < 0)
goto error;
- if ((qemu_driver->activePciHostdevs = virPCIDeviceListNew()) == NULL)
- goto error;
-
- if ((qemu_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL)
- goto error;
-
- if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL)
- goto error;
-
- if ((qemu_driver->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL)
- goto error;
-
if (!(qemu_driver->sharedDevices = virHashCreate(30, qemuSharedDeviceEntryFree)))
goto error;
@@ -989,10 +975,6 @@ qemuStateCleanup(void) {
virNWFilterUnRegisterCallbackDriver(&qemuCallbackDriver);
virObjectUnref(qemu_driver->config);
- virObjectUnref(qemu_driver->activePciHostdevs);
- virObjectUnref(qemu_driver->inactivePciHostdevs);
- virObjectUnref(qemu_driver->activeUsbHostdevs);
- virObjectUnref(qemu_driver->activeScsiHostdevs);
virHashFree(qemu_driver->sharedDevices);
virObjectUnref(qemu_driver->caps);
virQEMUCapsCacheFree(qemu_driver->qemuCapsCache);
@@ -10775,12 +10757,12 @@ qemuNodeDeviceDetachFlags(virNodeDevicePtr dev,
const char *driverName,
unsigned int flags)
{
- virQEMUDriverPtr driver = dev->conn->privateData;
virPCIDevicePtr pci = NULL;
unsigned domain = 0, bus = 0, slot = 0, function = 0;
int ret = -1;
virNodeDeviceDefPtr def = NULL;
char *xml = NULL;
+ virHostdevManagerPtr hostdev_mgr;
virCheckFlags(0, -1);
@@ -10804,9 +10786,9 @@ qemuNodeDeviceDetachFlags(virNodeDevicePtr dev,
if (!driverName) {
/* prefer vfio */
- if (qemuHostdevHostSupportsPassthroughVFIO())
+ if (virHostdevHostSupportsPassthroughVFIO())
driverName = "vfio";
- else if (qemuHostdevHostSupportsPassthroughLegacy())
+ else if (virHostdevHostSupportsPassthroughKVM())
driverName = "kvm";
}
@@ -10827,18 +10809,12 @@ qemuNodeDeviceDetachFlags(virNodeDevicePtr dev,
goto cleanup;
}
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- if (virPCIDeviceDetach(pci, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0) {
- goto out;
- }
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (hostdev_mgr == NULL ||
+ virHostdevPciNodeDeviceDetach(hostdev_mgr, pci) < 0)
+ goto cleanup;
ret = 0;
-out:
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnlock(driver->activePciHostdevs);
cleanup:
virPCIDeviceFree(pci);
virNodeDeviceDefFree(def);
@@ -10855,13 +10831,12 @@ qemuNodeDeviceDettach(virNodeDevicePtr dev)
static int
qemuNodeDeviceReAttach(virNodeDevicePtr dev)
{
- virQEMUDriverPtr driver = dev->conn->privateData;
virPCIDevicePtr pci = NULL;
- virPCIDevicePtr other;
unsigned domain = 0, bus = 0, slot = 0, function = 0;
int ret = -1;
virNodeDeviceDefPtr def = NULL;
char *xml = NULL;
+ virHostdevManagerPtr hostdev_mgr;
xml = virNodeDeviceGetXMLDesc(dev, 0);
if (!xml)
@@ -10881,35 +10856,13 @@ qemuNodeDeviceReAttach(virNodeDevicePtr dev)
if (!pci)
goto cleanup;
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
- other = virPCIDeviceListFind(driver->activePciHostdevs, pci);
- if (other) {
- const char *other_name = NULL;
- const char *other_drvname = NULL;
- virPCIDeviceGetUsedBy(other, &other_drvname, &other_name);
-
- if (other_name)
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("PCI device %s is still in use by domain %s"),
- virPCIDeviceGetName(pci), other_name);
- else
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("PCI device %s is still in use"),
- virPCIDeviceGetName(pci));
- goto out;
- }
-
- virPCIDeviceReattachInit(pci);
-
- if (virPCIDeviceReattach(pci, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (hostdev_mgr == NULL ||
+ virHostdevPciNodeDeviceReAttach(hostdev_mgr, pci) < 0)
goto out;
ret = 0;
out:
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnlock(driver->activePciHostdevs);
virPCIDeviceFree(pci);
cleanup:
virNodeDeviceDefFree(def);
@@ -10920,12 +10873,12 @@ cleanup:
static int
qemuNodeDeviceReset(virNodeDevicePtr dev)
{
- virQEMUDriverPtr driver = dev->conn->privateData;
virPCIDevicePtr pci;
unsigned domain = 0, bus = 0, slot = 0, function = 0;
int ret = -1;
virNodeDeviceDefPtr def = NULL;
char *xml = NULL;
+ virHostdevManagerPtr hostdev_mgr;
xml = virNodeDeviceGetXMLDesc(dev, 0);
if (!xml)
@@ -10945,17 +10898,13 @@ qemuNodeDeviceReset(virNodeDevicePtr dev)
if (!pci)
goto cleanup;
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- if (virPCIDeviceReset(pci, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (hostdev_mgr == NULL ||
+ virHostdevPciNodeDeviceReset(hostdev_mgr, pci) < 0)
goto out;
ret = 0;
out:
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnlock(driver->activePciHostdevs);
virPCIDeviceFree(pci);
cleanup:
virNodeDeviceDefFree(def);
diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c
deleted file mode 100644
index 1dc652b..0000000
--- a/src/qemu/qemu_hostdev.c
+++ /dev/null
@@ -1,1466 +0,0 @@
-/*
- * qemu_hostdev.c: QEMU hostdev management
- *
- * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see
- * <
http://www.gnu.org/licenses/>.
- *
- * Author: Daniel P. Berrange <berrange(a)redhat.com>
- */
-
-#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"
-#include "viralloc.h"
-#include "virpci.h"
-#include "virusb.h"
-#include "virscsi.h"
-#include "virnetdev.h"
-#include "virfile.h"
-
-#define VIR_FROM_THIS VIR_FROM_QEMU
-
-static virPCIDeviceListPtr
-qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
-{
- virPCIDeviceListPtr list;
- size_t i;
-
- if (!(list = virPCIDeviceListNew()))
- return NULL;
-
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- virPCIDevicePtr dev;
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
- continue;
-
- dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
- hostdev->source.subsys.u.pci.addr.bus,
- hostdev->source.subsys.u.pci.addr.slot,
- hostdev->source.subsys.u.pci.addr.function);
- if (!dev) {
- virObjectUnref(list);
- return NULL;
- }
-
- if (virPCIDeviceListAdd(list, dev) < 0) {
- virPCIDeviceFree(dev);
- virObjectUnref(list);
- return NULL;
- }
-
- virPCIDeviceSetManaged(dev, hostdev->managed);
- if (hostdev->source.subsys.u.pci.backend
- == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
- if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0) {
- virObjectUnref(list);
- return NULL;
- }
- } else {
- if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0) {
- virObjectUnref(list);
- return NULL;
- }
- }
- }
-
- return list;
-}
-
-
-/*
- * qemuGetActivePciHostDeviceList - make a new list with a *copy* of
- * every virPCIDevice object that is found on the activePciHostdevs
- * list *and* is in the hostdev list for this domain.
- *
- * Return the new list, or NULL if there was a failure.
- *
- * Pre-condition: driver->activePciHostdevs is locked
- */
-static virPCIDeviceListPtr
-qemuGetActivePciHostDeviceList(virQEMUDriverPtr driver,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- virPCIDeviceListPtr list;
- size_t i;
-
- if (!(list = virPCIDeviceListNew()))
- return NULL;
-
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- virDevicePCIAddressPtr addr;
- virPCIDevicePtr activeDev;
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
- continue;
-
- addr = &hostdev->source.subsys.u.pci.addr;
- activeDev = virPCIDeviceListFindByIDs(driver->activePciHostdevs,
- addr->domain, addr->bus,
- addr->slot, addr->function);
- if (activeDev && virPCIDeviceListAddCopy(list, activeDev) < 0) {
- virObjectUnref(list);
- return NULL;
- }
- }
-
- return list;
-}
-
-
-int
-qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def)
-{
- virDomainHostdevDefPtr hostdev = NULL;
- virPCIDevicePtr dev = NULL;
- size_t i;
- int ret = -1;
-
- if (!def->nhostdevs)
- return 0;
-
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- for (i = 0; i < def->nhostdevs; i++) {
- hostdev = def->hostdevs[i];
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
- continue;
-
- dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
- hostdev->source.subsys.u.pci.addr.bus,
- hostdev->source.subsys.u.pci.addr.slot,
- hostdev->source.subsys.u.pci.addr.function);
-
- if (!dev)
- goto cleanup;
-
- virPCIDeviceSetManaged(dev, hostdev->managed);
- if (hostdev->source.subsys.u.pci.backend
- == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
- if (virPCIDeviceSetStubDriver(dev, "vfio-pci") < 0)
- goto cleanup;
- } else {
- if (virPCIDeviceSetStubDriver(dev, "pci-stub") < 0)
- goto cleanup;
-
- }
- virPCIDeviceSetUsedBy(dev, "QEMU", def->name);
-
- /* Setup the original states for the PCI device */
- virPCIDeviceSetUnbindFromStub(dev,
hostdev->origstates.states.pci.unbind_from_stub);
- virPCIDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot);
- virPCIDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe);
-
- if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0)
- goto cleanup;
- dev = NULL;
- }
-
- ret = 0;
-cleanup:
- virPCIDeviceFree(dev);
- virObjectUnlock(driver->activePciHostdevs);
- virObjectUnlock(driver->inactivePciHostdevs);
- return ret;
-}
-
-
-int
-qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def)
-{
- virDomainHostdevDefPtr hostdev = NULL;
- size_t i;
- int ret = -1;
-
- if (!def->nhostdevs)
- return 0;
-
- virObjectLock(driver->activeUsbHostdevs);
- for (i = 0; i < def->nhostdevs; i++) {
- virUSBDevicePtr usb = NULL;
- hostdev = def->hostdevs[i];
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
- continue;
-
- usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- NULL);
- if (!usb) {
- VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- def->name);
- continue;
- }
-
- virUSBDeviceSetUsedBy(usb, "QEMU", def->name);
-
- if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0) {
- virUSBDeviceFree(usb);
- goto cleanup;
- }
- }
- ret = 0;
-cleanup:
- virObjectUnlock(driver->activeUsbHostdevs);
- return ret;
-}
-
-int
-qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def)
-{
- virDomainHostdevDefPtr hostdev = NULL;
- size_t i;
- int ret = -1;
-
- if (!def->nhostdevs)
- return 0;
-
- virObjectLock(driver->activeScsiHostdevs);
- for (i = 0; i < def->nhostdevs; i++) {
- virSCSIDevicePtr scsi = NULL;
- hostdev = def->hostdevs[i];
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
- hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
- continue;
-
- if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
- hostdev->source.subsys.u.scsi.bus,
- hostdev->source.subsys.u.scsi.target,
- hostdev->source.subsys.u.scsi.unit,
- hostdev->readonly)))
- goto cleanup;
-
- virSCSIDeviceSetUsedBy(scsi, "QEMU", def->name);
-
- if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0) {
- virSCSIDeviceFree(scsi);
- goto cleanup;
- }
- }
- ret = 0;
-
-cleanup:
- virObjectUnlock(driver->activeScsiHostdevs);
- return ret;
-}
-
-
-static int
-qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev,
- char **sysfs_path)
-{
- virPCIDeviceAddress config_address;
-
- config_address.domain = hostdev->source.subsys.u.pci.addr.domain;
- config_address.bus = hostdev->source.subsys.u.pci.addr.bus;
- config_address.slot = hostdev->source.subsys.u.pci.addr.slot;
- config_address.function = hostdev->source.subsys.u.pci.addr.function;
-
- return virPCIDeviceAddressGetSysfsFile(&config_address, sysfs_path);
-}
-
-
-int
-qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev)
-{
- char *sysfs_path = NULL;
- int ret = -1;
-
- if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
- return ret;
-
- ret = virPCIIsVirtualFunction(sysfs_path);
-
- VIR_FREE(sysfs_path);
-
- return ret;
-}
-
-
-static int
-qemuDomainHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev,
- int *vf)
-{
- int ret = -1;
- char *sysfs_path = NULL;
-
- if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0)
- return ret;
-
- if (virPCIIsVirtualFunction(sysfs_path) == 1) {
- if (virPCIGetVirtualFunctionInfo(sysfs_path, linkdev,
- vf) < 0)
- goto cleanup;
- } else {
- if (virPCIGetNetName(sysfs_path, linkdev) < 0)
- goto cleanup;
- *vf = -1;
- }
-
- ret = 0;
-
-cleanup:
- VIR_FREE(sysfs_path);
-
- return ret;
-}
-
-
-static int
-qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf,
- virNetDevVPortProfilePtr virtPort,
- const virMacAddr *macaddr,
- const unsigned char *uuid,
- bool associate)
-{
- int ret = -1;
-
- if (!virtPort)
- return ret;
-
- switch (virtPort->virtPortType) {
- case VIR_NETDEV_VPORT_PROFILE_NONE:
- case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH:
- case VIR_NETDEV_VPORT_PROFILE_8021QBG:
- case VIR_NETDEV_VPORT_PROFILE_LAST:
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("virtualport type %s is "
- "currently not supported on interfaces of type "
- "hostdev"),
- virNetDevVPortTypeToString(virtPort->virtPortType));
- break;
-
- case VIR_NETDEV_VPORT_PROFILE_8021QBH:
- if (associate)
- ret = virNetDevVPortProfileAssociate(NULL, virtPort, macaddr,
- linkdev, vf, uuid,
- VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
false);
- else
- ret = virNetDevVPortProfileDisassociate(NULL, virtPort,
- macaddr, linkdev, vf,
-
VIR_NETDEV_VPORT_PROFILE_OP_DESTROY);
- break;
- }
-
- return ret;
-}
-
-
-int
-qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
- const unsigned char *uuid,
- char *stateDir)
-{
- char *linkdev = NULL;
- virNetDevVlanPtr vlan;
- virNetDevVPortProfilePtr virtPort;
- int ret = -1;
- int vf = -1;
- int vlanid = -1;
- bool port_profile_associate = true;
- int isvf;
-
- isvf = qemuDomainHostdevIsVirtualFunction(hostdev);
- if (isvf <= 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Interface type hostdev is currently supported on"
- " SR-IOV Virtual Functions only"));
- return ret;
- }
-
- if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
- return ret;
-
- vlan = virDomainNetGetActualVlan(hostdev->parent.data.net);
- virtPort = virDomainNetGetActualVirtPortProfile(
-
hostdev->parent.data.net);
- if (virtPort) {
- if (vlan) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("direct setting of the vlan tag is not allowed "
- "for hostdev devices using %s mode"),
- virNetDevVPortTypeToString(virtPort->virtPortType));
- goto cleanup;
- }
- ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf,
- virtPort, &hostdev->parent.data.net->mac, uuid,
- port_profile_associate);
- } else {
- /* Set only mac and vlan */
- if (vlan) {
- if (vlan->nTags != 1 || vlan->trunk) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("vlan trunking is not supported "
- "by SR-IOV network devices"));
- goto cleanup;
- }
- if (vf == -1) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("vlan can only be set for SR-IOV VFs, but "
- "%s is not a VF"), linkdev);
- goto cleanup;
- }
- vlanid = vlan->tag[0];
- } else if (vf >= 0) {
- vlanid = 0; /* assure any current vlan tag is reset */
- }
-
- ret = virNetDevReplaceNetConfig(linkdev, vf,
- &hostdev->parent.data.net->mac,
- vlanid, stateDir);
- }
-cleanup:
- VIR_FREE(linkdev);
- return ret;
-}
-
-
-int
-qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
- char *stateDir)
-{
- char *linkdev = NULL;
- virNetDevVPortProfilePtr virtPort;
- int ret = -1;
- int vf = -1;
- bool port_profile_associate = false;
- int isvf;
-
- /* This is only needed for PCI devices that have been defined
- * using <interface type='hostdev'>. For all others, it is a NOP.
- */
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
- hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI ||
- hostdev->parent.type != VIR_DOMAIN_DEVICE_NET ||
- !hostdev->parent.data.net)
- return 0;
-
- isvf = qemuDomainHostdevIsVirtualFunction(hostdev);
- if (isvf <= 0) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("Interface type hostdev is currently supported on"
- " SR-IOV Virtual Functions only"));
- return ret;
- }
-
- if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0)
- return ret;
-
- virtPort = virDomainNetGetActualVirtPortProfile(
-
hostdev->parent.data.net);
- if (virtPort)
- ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort,
- &hostdev->parent.data.net->mac,
NULL,
- port_profile_associate);
- else
- ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir);
-
- VIR_FREE(linkdev);
-
- return ret;
-}
-
-
-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>
-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
-bool
-qemuHostdevHostSupportsPassthroughLegacy(void)
-{
- return false;
-}
-#endif
-
-
-static bool
-qemuPrepareHostdevPCICheckSupport(virDomainHostdevDefPtr *hostdevs,
- size_t nhostdevs,
- virQEMUCapsPtr qemuCaps)
-{
- bool supportsPassthroughKVM = qemuHostdevHostSupportsPassthroughLegacy();
- bool supportsPassthroughVFIO = qemuHostdevHostSupportsPassthroughVFIO();
- 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_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",
- _("host doesn't support VFIO PCI
passthrough"));
- return false;
- }
- break;
-
- 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,
- const unsigned char *uuid,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs,
- virQEMUCapsPtr qemuCaps)
-{
- virPCIDeviceListPtr pcidevs = NULL;
- int last_processed_hostdev_vf = -1;
- size_t i;
- int ret = -1;
- virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-
- if (!qemuPrepareHostdevPCICheckSupport(hostdevs, nhostdevs, qemuCaps))
- goto cleanup;
-
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
- goto cleanup;
-
- /* We have to use 9 loops here. *All* devices must
- * be detached before we reset any of them, because
- * in some cases you have to reset the whole PCI,
- * which impacts all devices on it. Also, all devices
- * must be reset before being marked as active.
- */
-
- /* Loop 1: validate that non-managed device isn't in use, eg
- * by checking that device is either un-bound, or bound
- * to pci-stub.ko
- */
-
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
- virPCIDevicePtr other;
-
- if (!virPCIDeviceIsAssignable(dev, !cfg->relaxedACS)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("PCI device %s is not assignable"),
- virPCIDeviceGetName(dev));
- goto cleanup;
- }
- /* The device is in use by other active domain if
- * the dev is in list driver->activePciHostdevs.
- */
- if ((other = virPCIDeviceListFind(driver->activePciHostdevs, dev))) {
- const char *other_name = NULL;
- const char *other_drvname = NULL;
- virPCIDeviceGetUsedBy(other, &other_drvname, &other_name);
-
- if (other_name)
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("PCI device %s is in use by domain %s"),
- virPCIDeviceGetName(dev), other_name);
- else
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("PCI device %s is already in use"),
- virPCIDeviceGetName(dev));
- goto cleanup;
- }
- }
-
- /* Loop 2: detach managed devices (i.e. bind to appropriate stub driver) */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
- if (virPCIDeviceGetManaged(dev) &&
- virPCIDeviceDetach(dev, driver->activePciHostdevs, NULL) < 0)
- goto reattachdevs;
- }
-
- /* Loop 3: Now that all the PCI hostdevs have been detached, we
- * can safely reset them */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
-
- if (virPCIDeviceReset(dev, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0)
- goto reattachdevs;
- }
-
- /* Loop 4: For SRIOV network devices, Now that we have detached the
- * the network device, set the netdev config */
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
- continue;
- if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET &&
-
hostdev->parent.data.net) {
- if (qemuDomainHostdevNetConfigReplace(hostdev, uuid,
- cfg->stateDir) < 0) {
- goto resetvfnetconfig;
- }
- }
- last_processed_hostdev_vf = i;
- }
-
- /* Loop 5: Now mark all the devices as active */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
- if (virPCIDeviceListAdd(driver->activePciHostdevs, dev) < 0)
- goto inactivedevs;
- }
-
- /* Loop 6: Now remove the devices from inactive list. */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
- virPCIDeviceListDel(driver->inactivePciHostdevs, dev);
- }
-
- /* Loop 7: Now set the used_by_domain of the device in
- * driver->activePciHostdevs as domain name.
- */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev, activeDev;
-
- dev = virPCIDeviceListGet(pcidevs, i);
- activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
-
- if (activeDev)
- virPCIDeviceSetUsedBy(activeDev, "QEMU", name);
- }
-
- /* Loop 8: Now set the original states for hostdev def */
- for (i = 0; i < nhostdevs; i++) {
- virPCIDevicePtr dev;
- virPCIDevicePtr pcidev;
- virDomainHostdevDefPtr hostdev = hostdevs[i];
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
- continue;
-
- dev = virPCIDeviceNew(hostdev->source.subsys.u.pci.addr.domain,
- hostdev->source.subsys.u.pci.addr.bus,
- hostdev->source.subsys.u.pci.addr.slot,
- hostdev->source.subsys.u.pci.addr.function);
-
- /* original states "unbind_from_stub", "remove_slot",
- * "reprobe" were already set by pciDettachDevice in
- * loop 2.
- */
- if ((pcidev = virPCIDeviceListFind(pcidevs, dev))) {
- hostdev->origstates.states.pci.unbind_from_stub =
- virPCIDeviceGetUnbindFromStub(pcidev);
- hostdev->origstates.states.pci.remove_slot =
- virPCIDeviceGetRemoveSlot(pcidev);
- hostdev->origstates.states.pci.reprobe =
- virPCIDeviceGetReprobe(pcidev);
- }
-
- virPCIDeviceFree(dev);
- }
-
- /* Loop 9: Now steal all the devices from pcidevs */
- while (virPCIDeviceListCount(pcidevs) > 0)
- virPCIDeviceListStealIndex(pcidevs, 0);
-
- ret = 0;
- goto cleanup;
-
-inactivedevs:
- /* Only steal all the devices from driver->activePciHostdevs. We will
- * free them in virObjectUnref().
- */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
- virPCIDeviceListSteal(driver->activePciHostdevs, dev);
- }
-
-resetvfnetconfig:
- for (i = 0;
- last_processed_hostdev_vf != -1 && i < last_processed_hostdev_vf;
i++)
- qemuDomainHostdevNetConfigRestore(hostdevs[i], cfg->stateDir);
-
-reattachdevs:
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
-
- /* NB: This doesn't actually re-bind to original driver, just
- * unbinds from the stub driver
- */
- ignore_value(virPCIDeviceReattach(dev, driver->activePciHostdevs,
- NULL));
- }
-
-cleanup:
- virObjectUnlock(driver->activePciHostdevs);
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnref(pcidevs);
- virObjectUnref(cfg);
- return ret;
-}
-
-
-int
-qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
- const char *name,
- virUSBDeviceListPtr list)
-{
- size_t i, j;
- unsigned int count;
- virUSBDevicePtr tmp;
-
- virObjectLock(driver->activeUsbHostdevs);
- count = virUSBDeviceListCount(list);
-
- for (i = 0; i < count; i++) {
- virUSBDevicePtr usb = virUSBDeviceListGet(list, i);
- if ((tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb))) {
- const char *other_name = NULL;
- const char *other_drvname = NULL;
- virUSBDeviceGetUsedBy(tmp, &other_drvname, &other_name);
-
- if (other_name)
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("USB device %s is in use by domain %s"),
- virUSBDeviceGetName(tmp), other_name);
- else
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("USB device %s is already in use"),
- virUSBDeviceGetName(tmp));
- goto error;
- }
-
- virUSBDeviceSetUsedBy(usb, "QEMU", name);
- VIR_DEBUG("Adding %03d.%03d dom=%s to activeUsbHostdevs",
- virUSBDeviceGetBus(usb), virUSBDeviceGetDevno(usb), name);
- /*
- * The caller is responsible to steal these usb devices
- * from the virUSBDeviceList that passed in on success,
- * perform rollback on failure.
- */
- if (virUSBDeviceListAdd(driver->activeUsbHostdevs, usb) < 0)
- goto error;
- }
-
- virObjectUnlock(driver->activeUsbHostdevs);
- return 0;
-
-error:
- for (j = 0; j < i; j++) {
- tmp = virUSBDeviceListGet(list, i);
- virUSBDeviceListSteal(driver->activeUsbHostdevs, tmp);
- }
- virObjectUnlock(driver->activeUsbHostdevs);
- return -1;
-}
-
-
-int
-qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
- bool mandatory,
- virUSBDevicePtr *usb)
-{
- unsigned vendor = hostdev->source.subsys.u.usb.vendor;
- unsigned product = hostdev->source.subsys.u.usb.product;
- unsigned bus = hostdev->source.subsys.u.usb.bus;
- unsigned device = hostdev->source.subsys.u.usb.device;
- bool autoAddress = hostdev->source.subsys.u.usb.autoAddress;
- int rc;
-
- *usb = NULL;
-
- if (vendor && bus) {
- rc = virUSBDeviceFind(vendor, product, bus, device,
- NULL,
- autoAddress ? false : mandatory,
- usb);
- if (rc < 0) {
- return -1;
- } else if (!autoAddress) {
- goto out;
- } else {
- VIR_INFO("USB device %x:%x could not be found at previous"
- " address (bus:%u device:%u)",
- vendor, product, bus, device);
- }
- }
-
- /* When vendor is specified, its USB address is either unspecified or the
- * device could not be found at the USB device where it had been
- * automatically found before.
- */
- if (vendor) {
- virUSBDeviceListPtr devs;
-
- rc = virUSBDeviceFindByVendor(vendor, product, NULL, mandatory, &devs);
- if (rc < 0)
- return -1;
-
- if (rc == 1) {
- *usb = virUSBDeviceListGet(devs, 0);
- virUSBDeviceListSteal(devs, *usb);
- }
- virObjectUnref(devs);
-
- if (rc == 0) {
- goto out;
- } else if (rc > 1) {
- if (autoAddress) {
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("Multiple USB devices for %x:%x were found,"
- " but none of them is at bus:%u device:%u"),
- vendor, product, bus, device);
- } else {
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("Multiple USB devices for %x:%x, "
- "use <address> to specify one"),
- vendor, product);
- }
- return -1;
- }
-
- hostdev->source.subsys.u.usb.bus = virUSBDeviceGetBus(*usb);
- hostdev->source.subsys.u.usb.device = virUSBDeviceGetDevno(*usb);
- hostdev->source.subsys.u.usb.autoAddress = true;
-
- if (autoAddress) {
- VIR_INFO("USB device %x:%x found at bus:%u device:%u (moved"
- " from bus:%u device:%u)",
- vendor, product,
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- bus, device);
- }
- } else if (!vendor && bus) {
- if (virUSBDeviceFindByBus(bus, device, NULL, mandatory, usb) < 0)
- return -1;
- }
-
-out:
- if (!*usb)
- hostdev->missing = true;
- return 0;
-}
-
-
-static int
-qemuPrepareHostUSBDevices(virQEMUDriverPtr driver,
- virDomainDefPtr def,
- bool coldBoot)
-{
- size_t i;
- int ret = -1;
- virUSBDeviceListPtr list;
- virUSBDevicePtr tmp;
- virDomainHostdevDefPtr *hostdevs = def->hostdevs;
- int nhostdevs = def->nhostdevs;
-
- /* To prevent situation where USB device is assigned to two domains
- * we need to keep a list of currently assigned USB devices.
- * This is done in several loops which cannot be joined into one big
- * loop. See qemuPrepareHostdevPCIDevices()
- */
- if (!(list = virUSBDeviceListNew()))
- goto cleanup;
-
- /* Loop 1: build temporary list
- */
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- bool required = true;
- virUSBDevicePtr usb;
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
- continue;
-
- if (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL ||
- (hostdev->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_REQUISITE &&
- !coldBoot))
- required = false;
-
- if (qemuFindHostdevUSBDevice(hostdev, required, &usb) < 0)
- goto cleanup;
-
- if (usb && virUSBDeviceListAdd(list, usb) < 0) {
- virUSBDeviceFree(usb);
- goto cleanup;
- }
- }
-
- /* Mark devices in temporary list as used by @name
- * and add them do driver list. However, if something goes
- * wrong, perform rollback.
- */
- if (qemuPrepareHostdevUSBDevices(driver, def->name, list) < 0)
- goto cleanup;
-
- /* Loop 2: Temporary list was successfully merged with
- * driver list, so steal all items to avoid freeing them
- * in cleanup label.
- */
- while (virUSBDeviceListCount(list) > 0) {
- tmp = virUSBDeviceListGet(list, 0);
- virUSBDeviceListSteal(list, tmp);
- }
-
- ret = 0;
-
-cleanup:
- virObjectUnref(list);
- return ret;
-}
-
-
-int
-qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- size_t i, j;
- int count;
- virSCSIDeviceListPtr list;
- virSCSIDevicePtr tmp;
-
- /* Loop 1: Add the shared scsi host device to shared device
- * table.
- */
- for (i = 0; i < nhostdevs; i++) {
- virDomainDeviceDef dev;
-
- dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
- dev.data.hostdev = hostdevs[i];
-
- if (qemuAddSharedDevice(driver, &dev, name) < 0)
- return -1;
-
- if (qemuSetUnprivSGIO(&dev) < 0)
- return -1;
- }
-
- /* To prevent situation where SCSI device is assigned to two domains
- * we need to keep a list of currently assigned SCSI devices.
- * This is done in several loops which cannot be joined into one big
- * loop. See qemuPrepareHostdevPCIDevices()
- */
- if (!(list = virSCSIDeviceListNew()))
- goto cleanup;
-
- /* Loop 2: build temporary list */
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- virSCSIDevicePtr scsi;
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
- hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
- continue;
-
- if (hostdev->managed) {
- virReportError(VIR_ERR_XML_ERROR, "%s",
- _("SCSI host device doesn't support managed
mode"));
- goto cleanup;
- }
-
- if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
- hostdev->source.subsys.u.scsi.bus,
- hostdev->source.subsys.u.scsi.target,
- hostdev->source.subsys.u.scsi.unit,
- hostdev->readonly)))
- goto cleanup;
-
- if (scsi && virSCSIDeviceListAdd(list, scsi) < 0) {
- virSCSIDeviceFree(scsi);
- goto cleanup;
- }
- }
-
- /* Loop 3: Mark devices in temporary list as used by @name
- * and add them to driver list. However, if something goes
- * wrong, perform rollback.
- */
- virObjectLock(driver->activeScsiHostdevs);
- count = virSCSIDeviceListCount(list);
-
- for (i = 0; i < count; i++) {
- virSCSIDevicePtr scsi = virSCSIDeviceListGet(list, i);
- if ((tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi))) {
- const char *other_name = NULL;
- const char *other_drvname = NULL;
- virSCSIDeviceGetUsedBy(tmp, &other_drvname, &other_name);
-
- if (other_name)
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("SCSI device %s is in use by domain %s"),
- virSCSIDeviceGetName(tmp), other_name);
- else
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("SCSI device %s is already in use"),
- virSCSIDeviceGetName(tmp));
- goto error;
- }
-
- virSCSIDeviceSetUsedBy(scsi, "QEMU", name);
- VIR_DEBUG("Adding %s to activeScsiHostdevs",
virSCSIDeviceGetName(scsi));
-
- if (virSCSIDeviceListAdd(driver->activeScsiHostdevs, scsi) < 0)
- goto error;
- }
-
- virObjectUnlock(driver->activeScsiHostdevs);
-
- /* Loop 4: Temporary list was successfully merged with
- * driver list, so steal all items to avoid freeing them
- * when freeing temporary list.
- */
- while (virSCSIDeviceListCount(list) > 0) {
- tmp = virSCSIDeviceListGet(list, 0);
- virSCSIDeviceListSteal(list, tmp);
- }
-
- virObjectUnref(list);
- return 0;
-
-error:
- for (j = 0; j < i; j++) {
- tmp = virSCSIDeviceListGet(list, i);
- virSCSIDeviceListSteal(driver->activeScsiHostdevs, tmp);
- }
- virObjectUnlock(driver->activeScsiHostdevs);
-cleanup:
- virObjectUnref(list);
- return -1;
-}
-
-
-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,
- qemuCaps) < 0)
- return -1;
-
- if (qemuPrepareHostUSBDevices(driver, def, coldBoot) < 0)
- return -1;
-
- if (qemuPrepareHostdevSCSIDevices(driver, def->name,
- def->hostdevs, def->nhostdevs) < 0)
- return -1;
-
- return 0;
-}
-
-
-/*
- * Pre-condition: driver->inactivePciHostdevs & driver->activePciHostdevs
- * are locked
- */
-void
-qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver)
-{
- int retries = 100;
-
- /* If the device is not managed and was attached to guest
- * successfully, it must have been inactive.
- */
- if (!virPCIDeviceGetManaged(dev)) {
- if (virPCIDeviceListAdd(driver->inactivePciHostdevs, dev) < 0)
- virPCIDeviceFree(dev);
- return;
- }
-
- while (virPCIDeviceWaitForCleanup(dev, "kvm_assigned_device")
- && retries) {
- usleep(100*1000);
- retries--;
- }
-
- if (virPCIDeviceReattach(dev, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0) {
- virErrorPtr err = virGetLastError();
- VIR_ERROR(_("Failed to re-attach PCI device: %s"),
- err ? err->message : _("unknown error"));
- virResetError(err);
- }
- virPCIDeviceFree(dev);
-}
-
-
-void
-qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- virPCIDeviceListPtr pcidevs;
- size_t i;
- virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
-
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
-
- if (!(pcidevs = qemuGetActivePciHostDeviceList(driver,
- hostdevs,
- nhostdevs))) {
- virErrorPtr err = virGetLastError();
- VIR_ERROR(_("Failed to allocate PCI device list: %s"),
- err ? err->message : _("unknown error"));
- virResetError(err);
- goto cleanup;
- }
-
- /* Again 4 loops; mark all devices as inactive before reset
- * them and reset all the devices before re-attach.
- * Attach mac and port profile parameters to devices
- */
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
- virPCIDevicePtr activeDev = NULL;
-
- /* delete the copy of the dev from pcidevs if it's used by
- * other domain. Or delete it from activePciHostDevs if it had
- * been used by this domain.
- */
- activeDev = virPCIDeviceListFind(driver->activePciHostdevs, dev);
- if (activeDev) {
- const char *tmp_name = NULL;
- const char *tmp_drvname = NULL;
- virPCIDeviceGetUsedBy(activeDev, &tmp_drvname, &tmp_name);
- if (STRNEQ_NULLABLE(name, tmp_name)) {
- virPCIDeviceListDel(pcidevs, dev);
- continue;
- }
- }
-
- virPCIDeviceListDel(driver->activePciHostdevs, dev);
- }
-
- /* At this point, any device that had been used by the guest is in
- * pcidevs, but has been removed from activePciHostdevs.
- */
-
- /*
- * For SRIOV net host devices, unset mac and port profile before
- * reset and reattach device
- */
- for (i = 0; i < nhostdevs; i++)
- qemuDomainHostdevNetConfigRestore(hostdevs[i], cfg->stateDir);
-
- for (i = 0; i < virPCIDeviceListCount(pcidevs); i++) {
- virPCIDevicePtr dev = virPCIDeviceListGet(pcidevs, i);
-
- if (virPCIDeviceReset(dev, driver->activePciHostdevs,
- driver->inactivePciHostdevs) < 0) {
- virErrorPtr err = virGetLastError();
- VIR_ERROR(_("Failed to reset PCI device: %s"),
- err ? err->message : _("unknown error"));
- virResetError(err);
- }
- }
-
- while (virPCIDeviceListCount(pcidevs) > 0) {
- virPCIDevicePtr dev = virPCIDeviceListStealIndex(pcidevs, 0);
- qemuReattachPciDevice(dev, driver);
- }
-
- virObjectUnref(pcidevs);
-cleanup:
- virObjectUnlock(driver->activePciHostdevs);
- virObjectUnlock(driver->inactivePciHostdevs);
- virObjectUnref(cfg);
-}
-
-
-static void
-qemuDomainReAttachHostUsbDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- size_t i;
-
- virObjectLock(driver->activeUsbHostdevs);
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- virUSBDevicePtr usb, tmp;
- const char *used_by = NULL;
- const char *used_by_drvname = NULL;
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
- continue;
- if (hostdev->missing)
- continue;
-
- usb = virUSBDeviceNew(hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- NULL);
-
- if (!usb) {
- VIR_WARN("Unable to reattach USB device %03d.%03d on domain %s",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- name);
- continue;
- }
-
- /* Delete only those USB devices which belongs
- * to domain @name because qemuProcessStart() might
- * have failed because USB device is already taken.
- * Therefore we want to steal only those devices from
- * the list which were taken by @name */
-
- tmp = virUSBDeviceListFind(driver->activeUsbHostdevs, usb);
- virUSBDeviceFree(usb);
-
- if (!tmp) {
- VIR_WARN("Unable to find device %03d.%03d "
- "in list of active USB devices",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device);
- continue;
- }
-
- virUSBDeviceGetUsedBy(tmp, &used_by_drvname, &used_by);
- if (STREQ_NULLABLE(used_by, name)) {
- VIR_DEBUG("Removing %03d.%03d dom=%s from activeUsbHostdevs",
- hostdev->source.subsys.u.usb.bus,
- hostdev->source.subsys.u.usb.device,
- name);
-
- virUSBDeviceListDel(driver->activeUsbHostdevs, tmp);
- }
- }
- virObjectUnlock(driver->activeUsbHostdevs);
-}
-
-
-void
-qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs)
-{
- size_t i;
-
- virObjectLock(driver->activeScsiHostdevs);
- for (i = 0; i < nhostdevs; i++) {
- virDomainHostdevDefPtr hostdev = hostdevs[i];
- virSCSIDevicePtr scsi, tmp;
- const char *used_by = NULL;
- const char *used_by_drvname = NULL;
- virDomainDeviceDef dev;
-
- dev.type = VIR_DOMAIN_DEVICE_HOSTDEV;
- dev.data.hostdev = hostdev;
-
- ignore_value(qemuRemoveSharedDevice(driver, &dev, name));
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
- hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI)
- continue;
-
- if (!(scsi = virSCSIDeviceNew(hostdev->source.subsys.u.scsi.adapter,
- hostdev->source.subsys.u.scsi.bus,
- hostdev->source.subsys.u.scsi.target,
- hostdev->source.subsys.u.scsi.unit,
- hostdev->readonly))) {
- VIR_WARN("Unable to reattach SCSI device %s:%d:%d:%d on domain
%s",
- hostdev->source.subsys.u.scsi.adapter,
- hostdev->source.subsys.u.scsi.bus,
- hostdev->source.subsys.u.scsi.target,
- hostdev->source.subsys.u.scsi.unit,
- name);
- continue;
- }
-
- /* Only delete the devices which are marked as being used by @name,
- * because qemuProcessStart could fail on the half way. */
-
- tmp = virSCSIDeviceListFind(driver->activeScsiHostdevs, scsi);
- virSCSIDeviceFree(scsi);
-
- if (!tmp) {
- VIR_WARN("Unable to find device %s:%d:%d:%d "
- "in list of active SCSI devices",
- hostdev->source.subsys.u.scsi.adapter,
- hostdev->source.subsys.u.scsi.bus,
- hostdev->source.subsys.u.scsi.target,
- hostdev->source.subsys.u.scsi.unit);
- continue;
- }
-
- virSCSIDeviceGetUsedBy(tmp, &used_by_drvname, &used_by);
- if (STREQ_NULLABLE(used_by, name)) {
- VIR_DEBUG("Removing %s:%d:%d:%d dom=%s from activeScsiHostdevs",
- hostdev->source.subsys.u.scsi.adapter,
- hostdev->source.subsys.u.scsi.bus,
- hostdev->source.subsys.u.scsi.target,
- hostdev->source.subsys.u.scsi.unit,
- name);
-
- virSCSIDeviceListDel(driver->activeScsiHostdevs, tmp);
- }
- }
- virObjectUnlock(driver->activeScsiHostdevs);
-}
-
-void
-qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
- virDomainDefPtr def)
-{
- if (!def->nhostdevs)
- return;
-
- qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs,
- def->nhostdevs);
-
- qemuDomainReAttachHostUsbDevices(driver, def->name, def->hostdevs,
- def->nhostdevs);
-
- qemuDomainReAttachHostScsiDevices(driver, def->name, def->hostdevs,
- def->nhostdevs);
-}
diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h
deleted file mode 100644
index ffb3167..0000000
--- a/src/qemu/qemu_hostdev.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * qemu_hostdev.h: QEMU hostdev management
- *
- * Copyright (C) 2006-2007, 2009-2013 Red Hat, Inc.
- * Copyright (C) 2006 Daniel P. Berrange
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see
- * <
http://www.gnu.org/licenses/>.
- *
- * Author: Daniel P. Berrange <berrange(a)redhat.com>
- */
-
-#ifndef __QEMU_HOSTDEV_H__
-# define __QEMU_HOSTDEV_H__
-
-# include "qemu_conf.h"
-# include "domain_conf.h"
-
-int qemuUpdateActivePciHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def);
-int qemuUpdateActiveUsbHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def);
-int qemuUpdateActiveScsiHostdevs(virQEMUDriverPtr driver,
- virDomainDefPtr def);
-bool qemuHostdevHostSupportsPassthroughLegacy(void);
-bool qemuHostdevHostSupportsPassthroughVFIO(void);
-int qemuPrepareHostdevPCIDevices(virQEMUDriverPtr driver,
- const char *name,
- const unsigned char *uuid,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs,
- virQEMUCapsPtr qemuCaps);
-int qemuFindHostdevUSBDevice(virDomainHostdevDefPtr hostdev,
- bool mandatory,
- virUSBDevicePtr *usb);
-int qemuPrepareHostdevUSBDevices(virQEMUDriverPtr driver,
- const char *name,
- virUSBDeviceListPtr list);
-int qemuPrepareHostdevSCSIDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs);
-int qemuPrepareHostDevices(virQEMUDriverPtr driver,
- virDomainDefPtr def,
- virQEMUCapsPtr qemuCaps,
- bool coldBoot);
-void qemuDomainReAttachHostScsiDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs);
-void qemuReattachPciDevice(virPCIDevicePtr dev, virQEMUDriverPtr driver);
-void qemuDomainReAttachHostdevDevices(virQEMUDriverPtr driver,
- const char *name,
- virDomainHostdevDefPtr *hostdevs,
- int nhostdevs);
-void qemuDomainReAttachHostDevices(virQEMUDriverPtr driver,
- virDomainDefPtr def);
-int qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev);
-int qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev,
- const unsigned char *uuid,
- char *stateDir);
-int qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev,
- char *stateDir);
-
-#endif /* __QEMU_HOSTDEV_H__ */
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index a375b6c..9ea95b7 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -30,7 +30,7 @@
#include "qemu_domain.h"
#include "qemu_command.h"
#include "qemu_bridge_filter.h"
-#include "qemu_hostdev.h"
+#include "qemu_conf.h"
#include "domain_audit.h"
#include "domain_nwfilter.h"
#include "virlog.h"
@@ -50,6 +50,7 @@
#include "virstoragefile.h"
#include "virstring.h"
#include "virtime.h"
+#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
#define CHANGE_MEDIA_RETRIES 10
@@ -1155,12 +1156,20 @@ qemuDomainAttachHostPciDevice(virQEMUDriverPtr driver,
bool teardowncgroup = false;
bool teardownlabel = false;
int backend = hostdev->source.subsys.u.pci.backend;
+ virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ virHostdevManagerPtr hostdev_mgr;
+ unsigned int flags = 0;
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
return -1;
- if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid,
- &hostdev, 1, priv->qemuCaps) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (!cfg->relaxedACS)
+ flags |= VIR_STRICT_ACS_CHECK;
+ if (hostdev_mgr == NULL ||
+ virHostdevPreparePciHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, vm->def->uuid,
+ &hostdev, 1, flags) < 0)
return -1;
switch ((virDomainHostdevSubsysPciBackendType) backend) {
@@ -1264,7 +1273,8 @@ error:
if (releaseaddr)
qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
- qemuDomainReAttachHostdevDevices(driver, vm->def->name, &hostdev, 1);
+ virHostdevReAttachPciHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
VIR_FREE(devstr);
VIR_FREE(configfd_name);
@@ -1450,28 +1460,23 @@ qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver,
virDomainHostdevDefPtr hostdev)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
- virUSBDeviceList *list = NULL;
- virUSBDevicePtr usb = NULL;
char *devstr = NULL;
bool added = false;
bool teardowncgroup = false;
bool teardownlabel = false;
int ret = -1;
-
- if (qemuFindHostdevUSBDevice(hostdev, true, &usb) < 0)
+ virHostdevManagerPtr hostdev_mgr;
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (hostdev_mgr == NULL ||
+ virHostdevPrepareUsbHostdevs(hostdev_mgr,
+ QEMU_DRIVER_NAME,
+ vm->def->name,
+ &hostdev,
+ 1, 0) < 0)
return -1;
- if (!(list = virUSBDeviceListNew()))
- goto cleanup;
-
- if (virUSBDeviceListAdd(list, usb) < 0)
- goto cleanup;
-
- if (qemuPrepareHostdevUSBDevices(driver, vm->def->name, list) < 0)
- goto cleanup;
-
added = true;
- virUSBDeviceListSteal(list, usb);
if (qemuSetupHostdevCGroup(vm, hostdev) < 0)
goto cleanup;
@@ -1516,13 +1521,9 @@ cleanup:
vm->def, hostdev, NULL) < 0)
VIR_WARN("Unable to restore host device labelling on hotplug
fail");
if (added)
- virUSBDeviceListSteal(driver->activeUsbHostdevs, usb);
+ virHostdevReAttachUsbHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
}
- if (list && usb &&
- !virUSBDeviceListFind(list, usb) &&
- !virUSBDeviceListFind(driver->activeUsbHostdevs, usb))
- virUSBDeviceFree(usb);
- virObjectUnref(list);
VIR_FREE(devstr);
return ret;
}
@@ -1539,6 +1540,7 @@ qemuDomainAttachHostScsiDevice(virQEMUDriverPtr driver,
char *drvstr = NULL;
bool teardowncgroup = false;
bool teardownlabel = false;
+ virHostdevManagerPtr hostdev_mgr;
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE) ||
!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) ||
@@ -1552,8 +1554,12 @@ qemuDomainAttachHostScsiDevice(virQEMUDriverPtr driver,
if (!cont)
return -1;
- if (qemuPrepareHostdevSCSIDevices(driver, vm->def->name,
- &hostdev, 1)) {
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (hostdev_mgr == NULL ||
+ virHostdevPrepareScsiHostdevs(hostdev_mgr,
+ QEMU_DRIVER_NAME,
+ vm->def->name,
+ &hostdev, 1) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unable to prepare scsi hostdev: %s:%d:%d:%d"),
hostdev->source.subsys.u.scsi.adapter,
@@ -1610,7 +1616,8 @@ qemuDomainAttachHostScsiDevice(virQEMUDriverPtr driver,
ret = 0;
cleanup:
if (ret < 0) {
- qemuDomainReAttachHostScsiDevices(driver, vm->def->name, &hostdev, 1);
+ virHostdevReAttachScsiHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
if (teardowncgroup && qemuTeardownHostdevCgroup(vm, hostdev) < 0)
VIR_WARN("Unable to remove host device cgroup ACL on hotplug
fail");
if (teardownlabel &&
@@ -2526,62 +2533,41 @@ qemuDomainRemoveControllerDevice(virQEMUDriverPtr driver,
static void
-qemuDomainRemovePCIHostDevice(virQEMUDriverPtr driver,
- virDomainObjPtr vm,
+qemuDomainRemovePCIHostDevice(virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
- virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
- virPCIDevicePtr pci;
- virPCIDevicePtr activePci;
-
- virObjectLock(driver->activePciHostdevs);
- virObjectLock(driver->inactivePciHostdevs);
- pci = virPCIDeviceNew(subsys->u.pci.addr.domain, subsys->u.pci.addr.bus,
- subsys->u.pci.addr.slot, subsys->u.pci.addr.function);
- if (pci) {
- activePci = virPCIDeviceListSteal(driver->activePciHostdevs, pci);
- if (activePci &&
- virPCIDeviceReset(activePci, driver->activePciHostdevs,
- driver->inactivePciHostdevs) == 0) {
- qemuReattachPciDevice(activePci, driver);
- } else {
- /* reset of the device failed, treat it as if it was returned */
- virPCIDeviceFree(activePci);
- }
- virPCIDeviceFree(pci);
- }
- virObjectUnlock(driver->activePciHostdevs);
- virObjectUnlock(driver->inactivePciHostdevs);
+ virHostdevManagerPtr hostdev_mgr;
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (hostdev_mgr != NULL)
+ virHostdevReAttachPciHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
qemuDomainReleaseDeviceAddress(vm, hostdev->info, NULL);
}
static void
-qemuDomainRemoveUSBHostDevice(virQEMUDriverPtr driver,
- virDomainObjPtr vm ATTRIBUTE_UNUSED,
+qemuDomainRemoveUSBHostDevice(virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
- virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
- virUSBDevicePtr usb;
-
- usb = virUSBDeviceNew(subsys->u.usb.bus, subsys->u.usb.device, NULL);
- if (usb) {
- virObjectLock(driver->activeUsbHostdevs);
- virUSBDeviceListDel(driver->activeUsbHostdevs, usb);
- virObjectUnlock(driver->activeUsbHostdevs);
- virUSBDeviceFree(usb);
- } else {
- VIR_WARN("Unable to find device %03d.%03d in list of used USB
devices",
- subsys->u.usb.bus, subsys->u.usb.device);
- }
+ virHostdevManagerPtr hostdev_mgr;
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (hostdev_mgr != NULL)
+ virHostdevReAttachUsbHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
}
static void
-qemuDomainRemoveSCSIHostDevice(virQEMUDriverPtr driver,
- virDomainObjPtr vm,
+qemuDomainRemoveSCSIHostDevice(virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
{
- qemuDomainReAttachHostScsiDevices(driver, vm->def->name, &hostdev, 1);
+ virHostdevManagerPtr hostdev_mgr;
+
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (hostdev_mgr != NULL)
+ virHostdevReAttachScsiHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def->name, &hostdev, 1);
}
static void
@@ -2621,17 +2607,15 @@ qemuDomainRemoveHostDevice(virQEMUDriverPtr driver,
virDomainAuditHostdev(vm, hostdev, "detach", true);
- qemuDomainHostdevNetConfigRestore(hostdev, cfg->stateDir);
-
switch ((enum virDomainHostdevSubsysType) hostdev->source.subsys.type) {
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
- qemuDomainRemovePCIHostDevice(driver, vm, hostdev);
+ qemuDomainRemovePCIHostDevice(vm, hostdev);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
- qemuDomainRemoveUSBHostDevice(driver, vm, hostdev);
+ qemuDomainRemoveUSBHostDevice(vm, hostdev);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
- qemuDomainRemoveSCSIHostDevice(driver, vm, hostdev);
+ qemuDomainRemoveSCSIHostDevice(vm, hostdev);
break;
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
break;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d0fde54..8a4df89 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -39,10 +39,10 @@
#include "qemu_capabilities.h"
#include "qemu_monitor.h"
#include "qemu_command.h"
-#include "qemu_hostdev.h"
#include "qemu_hotplug.h"
#include "qemu_bridge_filter.h"
#include "qemu_migration.h"
+#include "qemu_conf.h"
#include "cpu/cpu.h"
#include "datatypes.h"
@@ -66,6 +66,7 @@
#include "viratomic.h"
#include "virnuma.h"
#include "virstring.h"
+#include "virhostdev.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -3118,6 +3119,8 @@ qemuProcessReconnect(void *opaque)
int reason;
virQEMUDriverConfigPtr cfg;
size_t i;
+ virHostdevManagerPtr hostdev_mgr;
+ unsigned int flags;
memcpy(&oldjob, &data->oldjob, sizeof(oldjob));
@@ -3149,14 +3152,12 @@ qemuProcessReconnect(void *opaque)
priv->agentError = true;
}
- if (qemuUpdateActivePciHostdevs(driver, obj->def) < 0) {
- goto error;
- }
-
- if (qemuUpdateActiveUsbHostdevs(driver, obj->def) < 0)
- goto error;
- if (qemuUpdateActiveScsiHostdevs(driver, obj->def) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ flags = VIR_SP_PCI_HOSTDEV | VIR_SP_USB_HOSTDEV | VIR_SP_SCSI_HOSTDEV;
+ if (hostdev_mgr == NULL ||
+ virHostdevUpdateActiveHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ obj->def, flags) < 0)
goto error;
if (qemuConnectCgroup(driver, obj) < 0)
@@ -3588,6 +3589,9 @@ int qemuProcessStart(virConnectPtr conn,
virQEMUDriverConfigPtr cfg;
virCapsPtr caps = NULL;
+ virHostdevManagerPtr hostdev_mgr;
+ unsigned int hostdev_flags;
+
VIR_DEBUG("vm=%p name=%s id=%d pid=%llu",
vm, vm->def->name, vm->def->id,
(unsigned long long)vm->pid);
@@ -3676,8 +3680,16 @@ int qemuProcessStart(virConnectPtr conn,
/* Must be run before security labelling */
VIR_DEBUG("Preparing host devices");
- if (qemuPrepareHostDevices(driver, vm->def, priv->qemuCaps,
- !migrateFrom) < 0)
+ hostdev_mgr = virHostdevManagerGetDefault();
+ if (hostdev_mgr == NULL)
+ goto cleanup;
+ hostdev_flags = VIR_SP_PCI_HOSTDEV | VIR_SP_USB_HOSTDEV | VIR_SP_SCSI_HOSTDEV;
+ if (!migrateFrom)
+ hostdev_flags |= VIR_COLD_BOOT;
+ if (!cfg->relaxedACS)
+ hostdev_flags |= VIR_STRICT_ACS_CHECK;
+ if (virHostdevPrepareDomainHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def, hostdev_flags) < 0)
goto cleanup;
VIR_DEBUG("Preparing chr devices");
@@ -4213,6 +4225,8 @@ void qemuProcessStop(virQEMUDriverPtr driver,
char *timestamp;
char ebuf[1024];
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ virHostdevManagerPtr hostdev_mgr;
+ unsigned int hostdev_flags;
VIR_DEBUG("Shutting down vm=%p name=%s id=%d pid=%llu flags=%x",
vm, vm->def->name, vm->def->id,
@@ -4356,7 +4370,11 @@ void qemuProcessStop(virQEMUDriverPtr driver,
priv->ccwaddrs = NULL;
}
- qemuDomainReAttachHostDevices(driver, vm->def);
+ hostdev_mgr = virHostdevManagerGetDefault();
+ hostdev_flags = VIR_SP_PCI_HOSTDEV | VIR_SP_USB_HOSTDEV | VIR_SP_SCSI_HOSTDEV;
+ if (hostdev_mgr != NULL)
+ virHostdevReAttachDomainHostdevs(hostdev_mgr, QEMU_DRIVER_NAME,
+ vm->def, hostdev_flags);
def = vm->def;
for (i = 0; i < def->nnets; i++) {
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-pci-address.xml
b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-pci-address.xml
index 422127c..b9a221a 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-hostdev-pci-address.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hostdev-pci-address.xml
@@ -24,6 +24,7 @@
<controller type='ide' index='0'/>
<controller type='pci' index='0' model='pci-root'/>
<hostdev mode='subsystem' type='pci' managed='yes'>
+ <driver name='kvm'/>
<source>
<address domain='0x0000' bus='0x06' slot='0x12'
function='0x5'/>
</source>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml
b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml
index d65ef87..9e79348 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-net-hostdev.xml
@@ -24,6 +24,7 @@
<controller type='pci' index='0' model='pci-root'/>
<interface type='hostdev' managed='yes'>
<mac address='00:11:22:33:44:55'/>
+ <driver name='kvm'/>
<source>
<address type='pci' domain='0x0002' bus='0x03'
slot='0x07' function='0x1'/>
</source>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml
b/tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml
index a5e59b2..924842b 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-pci-rom.xml
@@ -33,12 +33,14 @@
<rom file='/etc/fake/bootrom.bin'/>
</interface>
<hostdev mode='subsystem' type='pci' managed='yes'>
+ <driver name='kvm'/>
<source>
<address domain='0x0000' bus='0x06' slot='0x12'
function='0x5'/>
</source>
<rom bar='off'/>
</hostdev>
<hostdev mode='subsystem' type='pci' managed='yes'>
+ <driver name='kvm'/>
<source>
<address domain='0x0000' bus='0x06' slot='0x12'
function='0x6'/>
</source>
--
1.6.0.2