|
Mark McLoughlin |
c034c1 |
From 332979bb680d833529ab9cecac6828c6ce54d731 Mon Sep 17 00:00:00 2001
|
|
Mark McLoughlin |
c034c1 |
From: Mark McLoughlin <markmc@redhat.com>
|
|
Mark McLoughlin |
c034c1 |
Date: Fri, 14 Aug 2009 08:31:10 +0100
|
|
Mark McLoughlin |
c034c1 |
Subject: [PATCH] Add host PCI device hotplug support
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
Attaching a host PCI device to a qemu guest is done with a
|
|
Mark McLoughlin |
c034c1 |
straightforward 'pci_add pci_addr auto host host=XX:XX.X' command.
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
Like with NIC and disk hotplug, we need to retain the guest PCI address
|
|
Mark McLoughlin |
c034c1 |
assigned by qemu so that we can use it for hot-unplug.
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
Identifying a device for detach is done using the host PCI address.
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
Managed mode is handled by detaching/resetting the device before
|
|
Mark McLoughlin |
c034c1 |
attaching it to the guest and re-attaching it after detaching it from
|
|
Mark McLoughlin |
c034c1 |
the guest.
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
(cherry picked from commit 7636ef4630fc15c3d559eceb5b5c4fb1524b7c5a)
|
|
Mark McLoughlin |
c034c1 |
(cherry picked from commit 0c5b7b93a3cdb197c55d79c2605e9e19e3af43f5)
|
|
Mark McLoughlin |
c034c1 |
(cherry picked from commit 60ff07585ca8f7e639fed477e2e2cf79ce1c5c21)
|
|
Mark McLoughlin |
c034c1 |
(cherry picked from commit 4e12af5623e4a962a6bb911af06fa29aa85befba)
|
|
Mark McLoughlin |
c034c1 |
(cherry picked from commit 4dbecff9fbd5b5d1154bc7a41a5d4dd00533b359)
|
|
Mark McLoughlin |
c034c1 |
(cherry picked from commit 12edef9a6aca5bd9a2ea18b73ca862f615684d84)
|
|
Mark McLoughlin |
c034c1 |
(cherry picked from commit 457e05062863a35c7efb35470886b9b83a49d04d)
|
|
Mark McLoughlin |
c034c1 |
(cherry picked from commit e8ad33931296c67de0538e78d12e21706a826d37)
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
Fedora-patch: libvirt-add-pci-hostdev-hotplug-support.patch
|
|
Mark McLoughlin |
c034c1 |
---
|
|
Mark McLoughlin |
c034c1 |
src/domain_conf.c | 33 +++++-
|
|
Mark McLoughlin |
c034c1 |
src/domain_conf.h | 13 +++
|
|
Mark McLoughlin |
c034c1 |
src/libvirt_private.syms | 2 +
|
|
Mark McLoughlin |
c034c1 |
src/qemu_driver.c | 266 ++++++++++++++++++++++++++++++++++++++++++++--
|
|
Mark McLoughlin |
c034c1 |
4 files changed, 300 insertions(+), 14 deletions(-)
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
diff --git a/src/domain_conf.c b/src/domain_conf.c
|
|
Mark McLoughlin |
c034c1 |
index 2301a96..bad53f7 100644
|
|
Mark McLoughlin |
c034c1 |
--- a/src/domain_conf.c
|
|
Mark McLoughlin |
c034c1 |
+++ b/src/domain_conf.c
|
|
Mark McLoughlin |
c034c1 |
@@ -1977,7 +1977,8 @@ out:
|
|
Mark McLoughlin |
c034c1 |
static int
|
|
Mark McLoughlin |
c034c1 |
virDomainHostdevSubsysPciDefParseXML(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
const xmlNodePtr node,
|
|
Mark McLoughlin |
c034c1 |
- virDomainHostdevDefPtr def) {
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevDefPtr def,
|
|
Mark McLoughlin |
c034c1 |
+ int flags) {
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
int ret = -1;
|
|
Mark McLoughlin |
c034c1 |
xmlNodePtr cur;
|
|
Mark McLoughlin |
c034c1 |
@@ -2049,6 +2050,20 @@ virDomainHostdevSubsysPciDefParseXML(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
_("pci address needs function id"));
|
|
Mark McLoughlin |
c034c1 |
goto out;
|
|
Mark McLoughlin |
c034c1 |
}
|
|
Mark McLoughlin |
c034c1 |
+ } else if ((flags & VIR_DOMAIN_XML_INTERNAL_STATUS) &&
|
|
Mark McLoughlin |
c034c1 |
+ xmlStrEqual(cur->name, BAD_CAST "state")) {
|
|
Mark McLoughlin |
c034c1 |
+ char *devaddr = virXMLPropString(cur, "devaddr");
|
|
Mark McLoughlin |
c034c1 |
+ if (devaddr &&
|
|
Mark McLoughlin |
c034c1 |
+ sscanf(devaddr, "%x:%x:%x",
|
|
Mark McLoughlin |
c034c1 |
+ &def->source.subsys.u.pci.guest_addr.domain,
|
|
Mark McLoughlin |
c034c1 |
+ &def->source.subsys.u.pci.guest_addr.bus,
|
|
Mark McLoughlin |
c034c1 |
+ &def->source.subsys.u.pci.guest_addr.slot) < 3) {
|
|
Mark McLoughlin |
c034c1 |
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
Mark McLoughlin |
c034c1 |
+ _("Unable to parse devaddr parameter '%s'"),
|
|
Mark McLoughlin |
c034c1 |
+ devaddr);
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(devaddr);
|
|
Mark McLoughlin |
c034c1 |
+ goto out;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
} else {
|
|
Mark McLoughlin |
c034c1 |
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
|
|
Mark McLoughlin |
c034c1 |
_("unknown pci source type '%s'"),
|
|
Mark McLoughlin |
c034c1 |
@@ -2123,7 +2138,7 @@ virDomainHostdevDefParseXML(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
}
|
|
Mark McLoughlin |
c034c1 |
if (def->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
Mark McLoughlin |
c034c1 |
def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
|
|
Mark McLoughlin |
c034c1 |
- if (virDomainHostdevSubsysPciDefParseXML(conn, cur, def) < 0)
|
|
Mark McLoughlin |
c034c1 |
+ if (virDomainHostdevSubsysPciDefParseXML(conn, cur, def, flags) < 0)
|
|
Mark McLoughlin |
c034c1 |
goto error;
|
|
Mark McLoughlin |
c034c1 |
}
|
|
Mark McLoughlin |
c034c1 |
} else {
|
|
Mark McLoughlin |
c034c1 |
@@ -3937,7 +3952,8 @@ virDomainGraphicsDefFormat(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
static int
|
|
Mark McLoughlin |
c034c1 |
virDomainHostdevDefFormat(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
virBufferPtr buf,
|
|
Mark McLoughlin |
c034c1 |
- virDomainHostdevDefPtr def)
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevDefPtr def,
|
|
Mark McLoughlin |
c034c1 |
+ int flags)
|
|
Mark McLoughlin |
c034c1 |
{
|
|
Mark McLoughlin |
c034c1 |
const char *mode = virDomainHostdevModeTypeToString(def->mode);
|
|
Mark McLoughlin |
c034c1 |
const char *type;
|
|
Mark McLoughlin |
c034c1 |
@@ -3978,6 +3994,15 @@ virDomainHostdevDefFormat(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
def->source.subsys.u.pci.bus,
|
|
Mark McLoughlin |
c034c1 |
def->source.subsys.u.pci.slot,
|
|
Mark McLoughlin |
c034c1 |
def->source.subsys.u.pci.function);
|
|
Mark McLoughlin |
c034c1 |
+ if (flags & VIR_DOMAIN_XML_INTERNAL_STATUS) {
|
|
Mark McLoughlin |
c034c1 |
+ virBufferAddLit(buf, "
|
|
Mark McLoughlin |
c034c1 |
+ if (virHostdevHasValidGuestAddr(def))
|
|
Mark McLoughlin |
c034c1 |
+ virBufferVSprintf(buf, " devaddr='%.4x:%.2x:%.2x'",
|
|
Mark McLoughlin |
c034c1 |
+ def->source.subsys.u.pci.guest_addr.domain,
|
|
Mark McLoughlin |
c034c1 |
+ def->source.subsys.u.pci.guest_addr.bus,
|
|
Mark McLoughlin |
c034c1 |
+ def->source.subsys.u.pci.guest_addr.slot);
|
|
Mark McLoughlin |
c034c1 |
+ virBufferAddLit(buf, "/>\n");
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
}
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
virBufferAddLit(buf, " </source>\n");
|
|
Mark McLoughlin |
c034c1 |
@@ -4192,7 +4217,7 @@ char *virDomainDefFormat(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
goto cleanup;
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
for (n = 0 ; n < def->nhostdevs ; n++)
|
|
Mark McLoughlin |
c034c1 |
- if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n]) < 0)
|
|
Mark McLoughlin |
c034c1 |
+ if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n], flags) < 0)
|
|
Mark McLoughlin |
c034c1 |
goto cleanup;
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
virBufferAddLit(&buf, " </devices>\n");
|
|
Mark McLoughlin |
c034c1 |
diff --git a/src/domain_conf.h b/src/domain_conf.h
|
|
Mark McLoughlin |
c034c1 |
index 63fca76..44302be 100644
|
|
Mark McLoughlin |
c034c1 |
--- a/src/domain_conf.h
|
|
Mark McLoughlin |
c034c1 |
+++ b/src/domain_conf.h
|
|
Mark McLoughlin |
c034c1 |
@@ -391,6 +391,11 @@ struct _virDomainHostdevDef {
|
|
Mark McLoughlin |
c034c1 |
unsigned bus;
|
|
Mark McLoughlin |
c034c1 |
unsigned slot;
|
|
Mark McLoughlin |
c034c1 |
unsigned function;
|
|
Mark McLoughlin |
c034c1 |
+ struct {
|
|
Mark McLoughlin |
c034c1 |
+ unsigned domain;
|
|
Mark McLoughlin |
c034c1 |
+ unsigned bus;
|
|
Mark McLoughlin |
c034c1 |
+ unsigned slot;
|
|
Mark McLoughlin |
c034c1 |
+ } guest_addr;
|
|
Mark McLoughlin |
c034c1 |
} pci;
|
|
Mark McLoughlin |
c034c1 |
} u;
|
|
Mark McLoughlin |
c034c1 |
} subsys;
|
|
Mark McLoughlin |
c034c1 |
@@ -404,6 +409,14 @@ struct _virDomainHostdevDef {
|
|
Mark McLoughlin |
c034c1 |
char* target;
|
|
Mark McLoughlin |
c034c1 |
};
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
+static inline int
|
|
Mark McLoughlin |
c034c1 |
+virHostdevHasValidGuestAddr(virDomainHostdevDefPtr def)
|
|
Mark McLoughlin |
c034c1 |
+{
|
|
Mark McLoughlin |
c034c1 |
+ return def->source.subsys.u.pci.guest_addr.domain ||
|
|
Mark McLoughlin |
c034c1 |
+ def->source.subsys.u.pci.guest_addr.bus ||
|
|
Mark McLoughlin |
c034c1 |
+ def->source.subsys.u.pci.guest_addr.slot;
|
|
Mark McLoughlin |
c034c1 |
+}
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
/* Flags for the 'type' field in next struct */
|
|
Mark McLoughlin |
c034c1 |
enum virDomainDeviceType {
|
|
Mark McLoughlin |
c034c1 |
VIR_DOMAIN_DEVICE_DISK,
|
|
Mark McLoughlin |
c034c1 |
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
|
|
Mark McLoughlin |
c034c1 |
index 4f1b01f..22131c4 100644
|
|
Mark McLoughlin |
c034c1 |
--- a/src/libvirt_private.syms
|
|
Mark McLoughlin |
c034c1 |
+++ b/src/libvirt_private.syms
|
|
Mark McLoughlin |
c034c1 |
@@ -88,6 +88,8 @@ virDomainGetRootFilesystem;
|
|
Mark McLoughlin |
c034c1 |
virDomainGraphicsTypeFromString;
|
|
Mark McLoughlin |
c034c1 |
virDomainGraphicsDefFree;
|
|
Mark McLoughlin |
c034c1 |
virDomainHostdevDefFree;
|
|
Mark McLoughlin |
c034c1 |
+virDomainHostdevModeTypeToString;
|
|
Mark McLoughlin |
c034c1 |
+virDomainHostdevSubsysTypeToString;
|
|
Mark McLoughlin |
c034c1 |
virDomainInputDefFree;
|
|
Mark McLoughlin |
c034c1 |
virDomainLifecycleTypeFromString;
|
|
Mark McLoughlin |
c034c1 |
virDomainLifecycleTypeToString;
|
|
Mark McLoughlin |
c034c1 |
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
|
|
Mark McLoughlin |
c034c1 |
index cbc27c4..99dac52 100644
|
|
Mark McLoughlin |
c034c1 |
--- a/src/qemu_driver.c
|
|
Mark McLoughlin |
c034c1 |
+++ b/src/qemu_driver.c
|
|
Mark McLoughlin |
c034c1 |
@@ -5258,9 +5258,91 @@ cleanup:
|
|
Mark McLoughlin |
c034c1 |
return -1;
|
|
Mark McLoughlin |
c034c1 |
}
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
-static int qemudDomainAttachHostDevice(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
- virDomainObjPtr vm,
|
|
Mark McLoughlin |
c034c1 |
- virDomainDeviceDefPtr dev)
|
|
Mark McLoughlin |
c034c1 |
+static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
+ struct qemud_driver *driver,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainObjPtr vm,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainDeviceDefPtr dev)
|
|
Mark McLoughlin |
c034c1 |
+{
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevDefPtr hostdev = dev->data.hostdev;
|
|
Mark McLoughlin |
c034c1 |
+ char *cmd, *reply;
|
|
Mark McLoughlin |
c034c1 |
+ unsigned domain, bus, slot;
|
|
Mark McLoughlin |
c034c1 |
+ pciDevice *pci;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
|
|
Mark McLoughlin |
c034c1 |
+ virReportOOMError(conn);
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ pci = pciGetDevice(conn,
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.domain,
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.bus,
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.slot,
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.function);
|
|
Mark McLoughlin |
c034c1 |
+ if (!dev)
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if ((hostdev->managed && pciDettachDevice(conn, pci) < 0) ||
|
|
Mark McLoughlin |
c034c1 |
+ pciResetDevice(conn, pci, driver->activePciHostdevs) < 0) {
|
|
Mark McLoughlin |
c034c1 |
+ pciFreeDevice(conn, pci);
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (pciDeviceListAdd(conn, driver->activePciHostdevs, pci) < 0) {
|
|
Mark McLoughlin |
c034c1 |
+ pciFreeDevice(conn, pci);
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ cmd = reply = NULL;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (virAsprintf(&cmd, "pci_add pci_addr=auto host host=%.2x:%.2x.%.1x",
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.bus,
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.slot,
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.function) < 0) {
|
|
Mark McLoughlin |
c034c1 |
+ virReportOOMError(conn);
|
|
Mark McLoughlin |
c034c1 |
+ goto error;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
|
Mark McLoughlin |
c034c1 |
+ "%s", _("cannot attach host pci device"));
|
|
Mark McLoughlin |
c034c1 |
+ goto error;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (strstr(reply, "invalid type: host")) {
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s",
|
|
Mark McLoughlin |
c034c1 |
+ _("PCI device assignment is not supported by this version of qemu"));
|
|
Mark McLoughlin |
c034c1 |
+ goto error;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (qemudParsePciAddReply(vm, reply, &domain, &bus, &slot) < 0) {
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
|
Mark McLoughlin |
c034c1 |
+ _("parsing pci_add reply failed: %s"), reply);
|
|
Mark McLoughlin |
c034c1 |
+ goto error;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.guest_addr.domain = domain;
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.guest_addr.bus = bus;
|
|
Mark McLoughlin |
c034c1 |
+ hostdev->source.subsys.u.pci.guest_addr.slot = slot;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(reply);
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(cmd);
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ return 0;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+error:
|
|
Mark McLoughlin |
c034c1 |
+ pciDeviceListDel(conn, driver->activePciHostdevs, pci);
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(reply);
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(cmd);
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+}
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+static int qemudDomainAttachHostUsbDevice(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainObjPtr vm,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainDeviceDefPtr dev)
|
|
Mark McLoughlin |
c034c1 |
{
|
|
Mark McLoughlin |
c034c1 |
int ret;
|
|
Mark McLoughlin |
c034c1 |
char *cmd, *reply;
|
|
Mark McLoughlin |
c034c1 |
@@ -5310,6 +5392,36 @@ static int qemudDomainAttachHostDevice(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
return 0;
|
|
Mark McLoughlin |
c034c1 |
}
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
+static int qemudDomainAttachHostDevice(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
+ struct qemud_driver *driver,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainObjPtr vm,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainDeviceDefPtr dev)
|
|
Mark McLoughlin |
c034c1 |
+{
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevDefPtr hostdev = dev->data.hostdev;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
Mark McLoughlin |
c034c1 |
+ _("hostdev mode '%s' not supported"),
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevModeTypeToString(hostdev->mode));
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (qemuDomainSetDeviceOwnership(conn, driver, dev, 0) < 0)
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ switch (hostdev->source.subsys.type) {
|
|
Mark McLoughlin |
c034c1 |
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
|
|
Mark McLoughlin |
c034c1 |
+ return qemudDomainAttachHostPciDevice(conn, driver, vm, dev);
|
|
Mark McLoughlin |
c034c1 |
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
|
Mark McLoughlin |
c034c1 |
+ return qemudDomainAttachHostUsbDevice(conn, vm, dev);
|
|
Mark McLoughlin |
c034c1 |
+ default:
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
Mark McLoughlin |
c034c1 |
+ _("hostdev subsys type '%s' not supported"),
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+}
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
static int qemudDomainAttachDevice(virDomainPtr dom,
|
|
Mark McLoughlin |
c034c1 |
const char *xml) {
|
|
Mark McLoughlin |
c034c1 |
struct qemud_driver *driver = dom->conn->privateData;
|
|
Mark McLoughlin |
c034c1 |
@@ -5411,13 +5523,8 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
|
|
Mark McLoughlin |
c034c1 |
}
|
|
Mark McLoughlin |
c034c1 |
} else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
|
|
Mark McLoughlin |
c034c1 |
ret = qemudDomainAttachNetDevice(dom->conn, driver, vm, dev, qemuCmdFlags);
|
|
Mark McLoughlin |
c034c1 |
- } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
|
|
Mark McLoughlin |
c034c1 |
- dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
|
Mark McLoughlin |
c034c1 |
- dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
|
Mark McLoughlin |
c034c1 |
- if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 0) < 0)
|
|
Mark McLoughlin |
c034c1 |
- goto cleanup;
|
|
Mark McLoughlin |
c034c1 |
-
|
|
Mark McLoughlin |
c034c1 |
- ret = qemudDomainAttachHostDevice(dom->conn, vm, dev);
|
|
Mark McLoughlin |
c034c1 |
+ } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
|
|
Mark McLoughlin |
c034c1 |
+ ret = qemudDomainAttachHostDevice(dom->conn, driver, vm, dev);
|
|
Mark McLoughlin |
c034c1 |
} else {
|
|
Mark McLoughlin |
c034c1 |
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
Mark McLoughlin |
c034c1 |
_("device type '%s' cannot be attached"),
|
|
Mark McLoughlin |
c034c1 |
@@ -5630,6 +5737,143 @@ cleanup:
|
|
Mark McLoughlin |
c034c1 |
return ret;
|
|
Mark McLoughlin |
c034c1 |
}
|
|
Mark McLoughlin |
c034c1 |
|
|
Mark McLoughlin |
c034c1 |
+static int qemudDomainDetachHostPciDevice(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
+ struct qemud_driver *driver,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainObjPtr vm,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainDeviceDefPtr dev)
|
|
Mark McLoughlin |
c034c1 |
+{
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevDefPtr detach;
|
|
Mark McLoughlin |
c034c1 |
+ char *cmd, *reply;
|
|
Mark McLoughlin |
c034c1 |
+ int i, ret;
|
|
Mark McLoughlin |
c034c1 |
+ pciDevice *pci;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ for (i = 0 ; i < vm->def->nhostdevs ; i++) {
|
|
Mark McLoughlin |
c034c1 |
+ unsigned domain = vm->def->hostdevs[i]->source.subsys.u.pci.domain;
|
|
Mark McLoughlin |
c034c1 |
+ unsigned bus = vm->def->hostdevs[i]->source.subsys.u.pci.bus;
|
|
Mark McLoughlin |
c034c1 |
+ unsigned slot = vm->def->hostdevs[i]->source.subsys.u.pci.slot;
|
|
Mark McLoughlin |
c034c1 |
+ unsigned function = vm->def->hostdevs[i]->source.subsys.u.pci.function;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (dev->data.hostdev->source.subsys.u.pci.domain == domain &&
|
|
Mark McLoughlin |
c034c1 |
+ dev->data.hostdev->source.subsys.u.pci.bus == bus &&
|
|
Mark McLoughlin |
c034c1 |
+ dev->data.hostdev->source.subsys.u.pci.slot == slot &&
|
|
Mark McLoughlin |
c034c1 |
+ dev->data.hostdev->source.subsys.u.pci.function == function) {
|
|
Mark McLoughlin |
c034c1 |
+ detach = vm->def->hostdevs[i];
|
|
Mark McLoughlin |
c034c1 |
+ break;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (!detach) {
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
Mark McLoughlin |
c034c1 |
+ _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
|
|
Mark McLoughlin |
c034c1 |
+ dev->data.hostdev->source.subsys.u.pci.domain,
|
|
Mark McLoughlin |
c034c1 |
+ dev->data.hostdev->source.subsys.u.pci.bus,
|
|
Mark McLoughlin |
c034c1 |
+ dev->data.hostdev->source.subsys.u.pci.slot,
|
|
Mark McLoughlin |
c034c1 |
+ dev->data.hostdev->source.subsys.u.pci.function);
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (!virHostdevHasValidGuestAddr(detach)) {
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
Mark McLoughlin |
c034c1 |
+ "%s", _("hostdev cannot be detached - device state missing"));
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (virAsprintf(&cmd, "pci_del pci_addr=%.4x:%.2x:%.2x",
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.guest_addr.domain,
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.guest_addr.bus,
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.guest_addr.slot) < 0) {
|
|
Mark McLoughlin |
c034c1 |
+ virReportOOMError(conn);
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
|
|
Mark McLoughlin |
c034c1 |
+ "%s", _("cannot detach host pci device"));
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(cmd);
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ DEBUG("%s: pci_del reply: %s", vm->def->name, reply);
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ /* If the command fails due to a wrong PCI address qemu prints
|
|
Mark McLoughlin |
c034c1 |
+ * 'invalid pci address'; nothing is printed on success */
|
|
Mark McLoughlin |
c034c1 |
+ if (strstr(reply, "Invalid pci address")) {
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
|
|
Mark McLoughlin |
c034c1 |
+ _("failed to detach host pci device: invalid PCI address %.4x:%.2x:%.2x: %s"),
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.guest_addr.domain,
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.guest_addr.bus,
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.guest_addr.slot,
|
|
Mark McLoughlin |
c034c1 |
+ reply);
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(reply);
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(cmd);
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(reply);
|
|
Mark McLoughlin |
c034c1 |
+ VIR_FREE(cmd);
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ ret = 0;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ pci = pciGetDevice(conn,
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.domain,
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.bus,
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.slot,
|
|
Mark McLoughlin |
c034c1 |
+ detach->source.subsys.u.pci.function);
|
|
Mark McLoughlin |
c034c1 |
+ if (!pci)
|
|
Mark McLoughlin |
c034c1 |
+ ret = -1;
|
|
Mark McLoughlin |
c034c1 |
+ else {
|
|
Mark McLoughlin |
c034c1 |
+ pciDeviceListDel(conn, driver->activePciHostdevs, pci);
|
|
Mark McLoughlin |
c034c1 |
+ if (pciResetDevice(conn, pci, driver->activePciHostdevs) < 0)
|
|
Mark McLoughlin |
c034c1 |
+ ret = -1;
|
|
Mark McLoughlin |
c034c1 |
+ if (detach->managed && pciReAttachDevice(conn, pci) < 0)
|
|
Mark McLoughlin |
c034c1 |
+ ret = -1;
|
|
Mark McLoughlin |
c034c1 |
+ pciFreeDevice(conn, pci);
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (i != --vm->def->nhostdevs)
|
|
Mark McLoughlin |
c034c1 |
+ memmove(&vm->def->hostdevs[i],
|
|
Mark McLoughlin |
c034c1 |
+ &vm->def->hostdevs[i+1],
|
|
Mark McLoughlin |
c034c1 |
+ sizeof(*vm->def->hostdevs) * (vm->def->nhostdevs-i));
|
|
Mark McLoughlin |
c034c1 |
+ if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs) < 0) {
|
|
Mark McLoughlin |
c034c1 |
+ virReportOOMError(conn);
|
|
Mark McLoughlin |
c034c1 |
+ ret = -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ return ret;
|
|
Mark McLoughlin |
c034c1 |
+}
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+static int qemudDomainDetachHostDevice(virConnectPtr conn,
|
|
Mark McLoughlin |
c034c1 |
+ struct qemud_driver *driver,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainObjPtr vm,
|
|
Mark McLoughlin |
c034c1 |
+ virDomainDeviceDefPtr dev)
|
|
Mark McLoughlin |
c034c1 |
+{
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevDefPtr hostdev = dev->data.hostdev;
|
|
Mark McLoughlin |
c034c1 |
+ int ret;
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
Mark McLoughlin |
c034c1 |
+ _("hostdev mode '%s' not supported"),
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevModeTypeToString(hostdev->mode));
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ switch (hostdev->source.subsys.type) {
|
|
Mark McLoughlin |
c034c1 |
+ case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
|
|
Mark McLoughlin |
c034c1 |
+ ret = qemudDomainDetachHostPciDevice(conn, driver, vm, dev);
|
|
Mark McLoughlin |
c034c1 |
+ break;
|
|
Mark McLoughlin |
c034c1 |
+ default:
|
|
Mark McLoughlin |
c034c1 |
+ qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
Mark McLoughlin |
c034c1 |
+ _("hostdev subsys type '%s' not supported"),
|
|
Mark McLoughlin |
c034c1 |
+ virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
|
|
Mark McLoughlin |
c034c1 |
+ return -1;
|
|
Mark McLoughlin |
c034c1 |
+ }
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ if (qemuDomainSetDeviceOwnership(conn, driver, dev, 1) < 0)
|
|
Mark McLoughlin |
c034c1 |
+ VIR_WARN0("Fail to restore disk device ownership");
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
+ return ret;
|
|
Mark McLoughlin |
c034c1 |
+}
|
|
Mark McLoughlin |
c034c1 |
+
|
|
Mark McLoughlin |
c034c1 |
static int qemudDomainDetachDevice(virDomainPtr dom,
|
|
Mark McLoughlin |
c034c1 |
const char *xml) {
|
|
Mark McLoughlin |
c034c1 |
struct qemud_driver *driver = dom->conn->privateData;
|
|
Mark McLoughlin |
c034c1 |
@@ -5670,6 +5914,8 @@ static int qemudDomainDetachDevice(virDomainPtr dom,
|
|
Mark McLoughlin |
c034c1 |
VIR_WARN0("Fail to restore disk device ownership");
|
|
Mark McLoughlin |
c034c1 |
} else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
|
|
Mark McLoughlin |
c034c1 |
ret = qemudDomainDetachNetDevice(dom->conn, vm, dev);
|
|
Mark McLoughlin |
c034c1 |
+ } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
|
|
Mark McLoughlin |
c034c1 |
+ ret = qemudDomainDetachHostDevice(dom->conn, driver, vm, dev);
|
|
Mark McLoughlin |
c034c1 |
} else
|
|
Mark McLoughlin |
c034c1 |
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
|
Mark McLoughlin |
c034c1 |
"%s", _("only SCSI or virtio disk device can be detached dynamically"));
|
|
Mark McLoughlin |
c034c1 |
--
|
|
Mark McLoughlin |
c034c1 |
1.6.2.5
|
|
Mark McLoughlin |
c034c1 |
|