mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-11 09:17:52 +03:00
Move QEMU hostdev helper code out of the QEMU driver
The QEMU driver file is far too large. Move all the hostdev helper code out into a separate file. No functional change. * src/qemu/qemu_hostdev.c, src/qemu/qemu_hostdev.h, src/Makefile.am: Add hostdev helper file * src/qemu/qemu_driver.c: Delete hostdev code
This commit is contained in:
parent
52271cfc28
commit
01abc8a1b8
@ -57,6 +57,7 @@ src/qemu/qemu_command.c
|
|||||||
src/qemu/qemu_conf.c
|
src/qemu/qemu_conf.c
|
||||||
src/qemu/qemu_domain.c
|
src/qemu/qemu_domain.c
|
||||||
src/qemu/qemu_driver.c
|
src/qemu/qemu_driver.c
|
||||||
|
src/qemu/qemu_hostdev.c
|
||||||
src/qemu/qemu_monitor.c
|
src/qemu/qemu_monitor.c
|
||||||
src/qemu/qemu_monitor_json.c
|
src/qemu/qemu_monitor_json.c
|
||||||
src/qemu/qemu_monitor_text.c
|
src/qemu/qemu_monitor_text.c
|
||||||
|
@ -272,6 +272,7 @@ QEMU_DRIVER_SOURCES = \
|
|||||||
qemu/qemu_domain.c qemu/qemu_domain.h \
|
qemu/qemu_domain.c qemu/qemu_domain.h \
|
||||||
qemu/qemu_audit.c qemu/qemu_audit.h \
|
qemu/qemu_audit.c qemu/qemu_audit.h \
|
||||||
qemu/qemu_cgroup.c qemu/qemu_cgroup.c \
|
qemu/qemu_cgroup.c qemu/qemu_cgroup.c \
|
||||||
|
qemu/qemu_hostdev.c qemu/qemu_hostdev.h \
|
||||||
qemu/qemu_conf.c qemu/qemu_conf.h \
|
qemu/qemu_conf.c qemu/qemu_conf.h \
|
||||||
qemu/qemu_monitor.c qemu/qemu_monitor.h \
|
qemu/qemu_monitor.c qemu/qemu_monitor.h \
|
||||||
qemu/qemu_monitor_text.c \
|
qemu/qemu_monitor_text.c \
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
#include "qemu_capabilities.h"
|
#include "qemu_capabilities.h"
|
||||||
#include "qemu_command.h"
|
#include "qemu_command.h"
|
||||||
#include "qemu_cgroup.h"
|
#include "qemu_cgroup.h"
|
||||||
|
#include "qemu_hostdev.h"
|
||||||
#include "qemu_monitor.h"
|
#include "qemu_monitor.h"
|
||||||
#include "qemu_bridge_filter.h"
|
#include "qemu_bridge_filter.h"
|
||||||
#include "qemu_audit.h"
|
#include "qemu_audit.h"
|
||||||
@ -144,9 +145,6 @@ static int qemudDomainGetMaxVcpus(virDomainPtr dom);
|
|||||||
static int qemuDetectVcpuPIDs(struct qemud_driver *driver,
|
static int qemuDetectVcpuPIDs(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm);
|
virDomainObjPtr vm);
|
||||||
|
|
||||||
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
|
|
||||||
virDomainDefPtr def);
|
|
||||||
|
|
||||||
static int qemudVMFiltersInstantiate(virConnectPtr conn,
|
static int qemudVMFiltersInstantiate(virConnectPtr conn,
|
||||||
virDomainDefPtr def);
|
virDomainDefPtr def);
|
||||||
|
|
||||||
@ -2758,192 +2756,6 @@ cleanup:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static pciDeviceList *
|
|
||||||
qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
|
|
||||||
{
|
|
||||||
pciDeviceList *list;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!(list = pciDeviceListNew()))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
for (i = 0 ; i < nhostdevs ; i++) {
|
|
||||||
virDomainHostdevDefPtr hostdev = hostdevs[i];
|
|
||||||
pciDevice *dev;
|
|
||||||
|
|
||||||
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
|
||||||
continue;
|
|
||||||
if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
dev = pciGetDevice(hostdev->source.subsys.u.pci.domain,
|
|
||||||
hostdev->source.subsys.u.pci.bus,
|
|
||||||
hostdev->source.subsys.u.pci.slot,
|
|
||||||
hostdev->source.subsys.u.pci.function);
|
|
||||||
if (!dev) {
|
|
||||||
pciDeviceListFree(list);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pciDeviceListAdd(list, dev) < 0) {
|
|
||||||
pciFreeDevice(dev);
|
|
||||||
pciDeviceListFree(list);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pciDeviceSetManaged(dev, hostdev->managed);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
|
|
||||||
virDomainDefPtr def)
|
|
||||||
{
|
|
||||||
pciDeviceList *pcidevs;
|
|
||||||
int i;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
if (!def->nhostdevs)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!(pcidevs = qemuGetPciHostDeviceList(def->hostdevs, def->nhostdevs)))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
|
||||||
pciDeviceListSteal(pcidevs, dev);
|
|
||||||
if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
|
|
||||||
pciFreeDevice(dev);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
pciDeviceListFree(pcidevs);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
|
||||||
virDomainHostdevDefPtr *hostdevs,
|
|
||||||
int nhostdevs)
|
|
||||||
{
|
|
||||||
pciDeviceList *pcidevs;
|
|
||||||
int i;
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* We have to use 3 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* XXX 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 < pciDeviceListCount(pcidevs); i++) {
|
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
|
||||||
if (!pciDeviceIsAssignable(dev, !driver->relaxedACS))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (pciDeviceGetManaged(dev) &&
|
|
||||||
pciDettachDevice(dev, driver->activePciHostdevs) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now that all the PCI hostdevs have be dettached, we can safely
|
|
||||||
* reset them */
|
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
|
||||||
if (pciResetDevice(dev, driver->activePciHostdevs, pcidevs) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now mark all the devices as active */
|
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
|
||||||
pciDeviceListSteal(pcidevs, dev);
|
|
||||||
if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
|
|
||||||
pciFreeDevice(dev);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
pciDeviceListFree(pcidevs);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuPrepareHostPCIDevices(struct qemud_driver *driver,
|
|
||||||
virDomainDefPtr def)
|
|
||||||
{
|
|
||||||
return qemuPrepareHostdevPCIDevices(driver, def->hostdevs, def->nhostdevs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuPrepareHostUSBDevices(struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
|
||||||
virDomainDefPtr def)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0 ; i < def->nhostdevs ; i++) {
|
|
||||||
virDomainHostdevDefPtr 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;
|
|
||||||
|
|
||||||
/* Resolve a vendor/product to bus/device */
|
|
||||||
if (hostdev->source.subsys.u.usb.vendor) {
|
|
||||||
usbDevice *usb
|
|
||||||
= usbFindDevice(hostdev->source.subsys.u.usb.vendor,
|
|
||||||
hostdev->source.subsys.u.usb.product);
|
|
||||||
|
|
||||||
if (!usb)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
|
|
||||||
hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
|
|
||||||
|
|
||||||
usbFreeDevice(usb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuPrepareHostDevices(struct qemud_driver *driver,
|
|
||||||
virDomainDefPtr def)
|
|
||||||
{
|
|
||||||
if (!def->nhostdevs)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (qemuPrepareHostPCIDevices(driver, def) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (qemuPrepareHostUSBDevices(driver, def) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qemuPrepareChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
qemuPrepareChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
||||||
virDomainChrDefPtr dev,
|
virDomainChrDefPtr dev,
|
||||||
@ -2966,80 +2778,6 @@ qemuPrepareChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
qemudReattachPciDevice(pciDevice *dev, struct qemud_driver *driver)
|
|
||||||
{
|
|
||||||
int retries = 100;
|
|
||||||
|
|
||||||
while (pciWaitForDeviceCleanup(dev, "kvm_assigned_device")
|
|
||||||
&& retries) {
|
|
||||||
usleep(100*1000);
|
|
||||||
retries--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pciDeviceGetManaged(dev)) {
|
|
||||||
if (pciReAttachDevice(dev, driver->activePciHostdevs) < 0) {
|
|
||||||
virErrorPtr err = virGetLastError();
|
|
||||||
VIR_ERROR(_("Failed to re-attach PCI device: %s"),
|
|
||||||
err ? err->message : _("unknown error"));
|
|
||||||
virResetError(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
qemuDomainReAttachHostdevDevices(struct qemud_driver *driver,
|
|
||||||
virDomainHostdevDefPtr *hostdevs,
|
|
||||||
int nhostdevs)
|
|
||||||
{
|
|
||||||
pciDeviceList *pcidevs;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs))) {
|
|
||||||
virErrorPtr err = virGetLastError();
|
|
||||||
VIR_ERROR(_("Failed to allocate pciDeviceList: %s"),
|
|
||||||
err ? err->message : _("unknown error"));
|
|
||||||
virResetError(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Again 3 loops; mark all devices as inactive before reset
|
|
||||||
* them and reset all the devices before re-attach */
|
|
||||||
|
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
|
||||||
pciDeviceListDel(driver->activePciHostdevs, dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
|
||||||
if (pciResetDevice(dev, driver->activePciHostdevs, pcidevs) < 0) {
|
|
||||||
virErrorPtr err = virGetLastError();
|
|
||||||
VIR_ERROR(_("Failed to reset PCI device: %s"),
|
|
||||||
err ? err->message : _("unknown error"));
|
|
||||||
virResetError(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
|
||||||
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
|
||||||
qemudReattachPciDevice(dev, driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
pciDeviceListFree(pcidevs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
qemuDomainReAttachHostDevices(struct qemud_driver *driver,
|
|
||||||
virDomainDefPtr def)
|
|
||||||
{
|
|
||||||
if (!def->nhostdevs)
|
|
||||||
return;
|
|
||||||
|
|
||||||
qemuDomainReAttachHostdevDevices(driver, def->hostdevs, def->nhostdevs);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct qemudHookData {
|
struct qemudHookData {
|
||||||
virConnectPtr conn;
|
virConnectPtr conn;
|
||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
@ -8767,7 +8505,7 @@ static int qemudDomainDetachHostPciDevice(struct qemud_driver *driver,
|
|||||||
pciDeviceListDel(driver->activePciHostdevs, pci);
|
pciDeviceListDel(driver->activePciHostdevs, pci);
|
||||||
if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
|
if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
qemudReattachPciDevice(pci, driver);
|
qemuReattachPciDevice(pci, driver);
|
||||||
pciFreeDevice(pci);
|
pciFreeDevice(pci);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
289
src/qemu/qemu_hostdev.c
Normal file
289
src/qemu/qemu_hostdev.c
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* qemu_hostdev.c: QEMU hostdev management
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2007, 2009-2010 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "qemu_hostdev.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "pci.h"
|
||||||
|
#include "hostusb.h"
|
||||||
|
|
||||||
|
static pciDeviceList *
|
||||||
|
qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs)
|
||||||
|
{
|
||||||
|
pciDeviceList *list;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!(list = pciDeviceListNew()))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0 ; i < nhostdevs ; i++) {
|
||||||
|
virDomainHostdevDefPtr hostdev = hostdevs[i];
|
||||||
|
pciDevice *dev;
|
||||||
|
|
||||||
|
if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||||
|
continue;
|
||||||
|
if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
dev = pciGetDevice(hostdev->source.subsys.u.pci.domain,
|
||||||
|
hostdev->source.subsys.u.pci.bus,
|
||||||
|
hostdev->source.subsys.u.pci.slot,
|
||||||
|
hostdev->source.subsys.u.pci.function);
|
||||||
|
if (!dev) {
|
||||||
|
pciDeviceListFree(list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pciDeviceListAdd(list, dev) < 0) {
|
||||||
|
pciFreeDevice(dev);
|
||||||
|
pciDeviceListFree(list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pciDeviceSetManaged(dev, hostdev->managed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
|
||||||
|
virDomainDefPtr def)
|
||||||
|
{
|
||||||
|
pciDeviceList *pcidevs;
|
||||||
|
int i;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (!def->nhostdevs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(pcidevs = qemuGetPciHostDeviceList(def->hostdevs, def->nhostdevs)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
|
pciDeviceListSteal(pcidevs, dev);
|
||||||
|
if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
|
||||||
|
pciFreeDevice(dev);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
pciDeviceListFree(pcidevs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
||||||
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
|
int nhostdevs)
|
||||||
|
{
|
||||||
|
pciDeviceList *pcidevs;
|
||||||
|
int i;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* We have to use 3 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* XXX 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 < pciDeviceListCount(pcidevs); i++) {
|
||||||
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
|
if (!pciDeviceIsAssignable(dev, !driver->relaxedACS))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (pciDeviceGetManaged(dev) &&
|
||||||
|
pciDettachDevice(dev, driver->activePciHostdevs) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now that all the PCI hostdevs have be dettached, we can safely
|
||||||
|
* reset them */
|
||||||
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
|
if (pciResetDevice(dev, driver->activePciHostdevs, pcidevs) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now mark all the devices as active */
|
||||||
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
|
pciDeviceListSteal(pcidevs, dev);
|
||||||
|
if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
|
||||||
|
pciFreeDevice(dev);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
pciDeviceListFree(pcidevs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuPrepareHostPCIDevices(struct qemud_driver *driver,
|
||||||
|
virDomainDefPtr def)
|
||||||
|
{
|
||||||
|
return qemuPrepareHostdevPCIDevices(driver, def->hostdevs, def->nhostdevs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuPrepareHostUSBDevices(struct qemud_driver *driver ATTRIBUTE_UNUSED,
|
||||||
|
virDomainDefPtr def)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0 ; i < def->nhostdevs ; i++) {
|
||||||
|
virDomainHostdevDefPtr 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;
|
||||||
|
|
||||||
|
/* Resolve a vendor/product to bus/device */
|
||||||
|
if (hostdev->source.subsys.u.usb.vendor) {
|
||||||
|
usbDevice *usb
|
||||||
|
= usbFindDevice(hostdev->source.subsys.u.usb.vendor,
|
||||||
|
hostdev->source.subsys.u.usb.product);
|
||||||
|
|
||||||
|
if (!usb)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
hostdev->source.subsys.u.usb.bus = usbDeviceGetBus(usb);
|
||||||
|
hostdev->source.subsys.u.usb.device = usbDeviceGetDevno(usb);
|
||||||
|
|
||||||
|
usbFreeDevice(usb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qemuPrepareHostDevices(struct qemud_driver *driver,
|
||||||
|
virDomainDefPtr def)
|
||||||
|
{
|
||||||
|
if (!def->nhostdevs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (qemuPrepareHostPCIDevices(driver, def) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (qemuPrepareHostUSBDevices(driver, def) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void qemuReattachPciDevice(pciDevice *dev, struct qemud_driver *driver)
|
||||||
|
{
|
||||||
|
int retries = 100;
|
||||||
|
|
||||||
|
while (pciWaitForDeviceCleanup(dev, "kvm_assigned_device")
|
||||||
|
&& retries) {
|
||||||
|
usleep(100*1000);
|
||||||
|
retries--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pciDeviceGetManaged(dev)) {
|
||||||
|
if (pciReAttachDevice(dev, driver->activePciHostdevs) < 0) {
|
||||||
|
virErrorPtr err = virGetLastError();
|
||||||
|
VIR_ERROR(_("Failed to re-attach PCI device: %s"),
|
||||||
|
err ? err->message : _("unknown error"));
|
||||||
|
virResetError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver,
|
||||||
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
|
int nhostdevs)
|
||||||
|
{
|
||||||
|
pciDeviceList *pcidevs;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs))) {
|
||||||
|
virErrorPtr err = virGetLastError();
|
||||||
|
VIR_ERROR(_("Failed to allocate pciDeviceList: %s"),
|
||||||
|
err ? err->message : _("unknown error"));
|
||||||
|
virResetError(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Again 3 loops; mark all devices as inactive before reset
|
||||||
|
* them and reset all the devices before re-attach */
|
||||||
|
|
||||||
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
|
pciDeviceListDel(driver->activePciHostdevs, dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
|
if (pciResetDevice(dev, driver->activePciHostdevs, pcidevs) < 0) {
|
||||||
|
virErrorPtr err = virGetLastError();
|
||||||
|
VIR_ERROR(_("Failed to reset PCI device: %s"),
|
||||||
|
err ? err->message : _("unknown error"));
|
||||||
|
virResetError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < pciDeviceListCount(pcidevs); i++) {
|
||||||
|
pciDevice *dev = pciDeviceListGet(pcidevs, i);
|
||||||
|
qemuReattachPciDevice(dev, driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
pciDeviceListFree(pcidevs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void qemuDomainReAttachHostDevices(struct qemud_driver *driver,
|
||||||
|
virDomainDefPtr def)
|
||||||
|
{
|
||||||
|
if (!def->nhostdevs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qemuDomainReAttachHostdevDevices(driver, def->hostdevs, def->nhostdevs);
|
||||||
|
}
|
45
src/qemu/qemu_hostdev.h
Normal file
45
src/qemu/qemu_hostdev.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* qemu_hostdev.h: QEMU hostdev management
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2007, 2009-2010 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, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __QEMU_HOSTDEV_H__
|
||||||
|
# define __QEMU_HOSTDEV_H__
|
||||||
|
|
||||||
|
# include "qemu_conf.h"
|
||||||
|
# include "domain_conf.h"
|
||||||
|
|
||||||
|
int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
|
||||||
|
virDomainDefPtr def);
|
||||||
|
int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
|
||||||
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
|
int nhostdevs);
|
||||||
|
int qemuPrepareHostDevices(struct qemud_driver *driver,
|
||||||
|
virDomainDefPtr def);
|
||||||
|
void qemuReattachPciDevice(pciDevice *dev, struct qemud_driver *driver);
|
||||||
|
void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver,
|
||||||
|
virDomainHostdevDefPtr *hostdevs,
|
||||||
|
int nhostdevs);
|
||||||
|
void qemuDomainReAttachHostDevices(struct qemud_driver *driver,
|
||||||
|
virDomainDefPtr def);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __QEMU_HOSTDEV_H__ */
|
Loading…
Reference in New Issue
Block a user