提交 01abc8a1 编写于 作者: D Daniel P. Berrange

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
上级 52271cfc
......@@ -57,6 +57,7 @@ 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_monitor.c
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_text.c
......
......@@ -272,6 +272,7 @@ QEMU_DRIVER_SOURCES = \
qemu/qemu_domain.c qemu/qemu_domain.h \
qemu/qemu_audit.c qemu/qemu_audit.h \
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_monitor.c qemu/qemu_monitor.h \
qemu/qemu_monitor_text.c \
......
......@@ -56,6 +56,7 @@
#include "qemu_capabilities.h"
#include "qemu_command.h"
#include "qemu_cgroup.h"
#include "qemu_hostdev.h"
#include "qemu_monitor.h"
#include "qemu_bridge_filter.h"
#include "qemu_audit.h"
......@@ -144,9 +145,6 @@ static int qemudDomainGetMaxVcpus(virDomainPtr dom);
static int qemuDetectVcpuPIDs(struct qemud_driver *driver,
virDomainObjPtr vm);
static int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
virDomainDefPtr def);
static int qemudVMFiltersInstantiate(virConnectPtr conn,
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
qemuPrepareChardevDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
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 {
virConnectPtr conn;
virDomainObjPtr vm;
......@@ -8767,7 +8505,7 @@ static int qemudDomainDetachHostPciDevice(struct qemud_driver *driver,
pciDeviceListDel(driver->activePciHostdevs, pci);
if (pciResetDevice(pci, driver->activePciHostdevs, NULL) < 0)
ret = -1;
qemudReattachPciDevice(pci, driver);
qemuReattachPciDevice(pci, driver);
pciFreeDevice(pci);
}
......
/*
* 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);
}
/*
* 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__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册