* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new
API qemuMonitorAddPCIHostDevice()
* src/qemu/qemu_driver.c: Switch to using qemuMonitorAddPCIHostDevice()
for PCI host device hotplug
---
src/qemu/qemu_driver.c | 46 +++-------------
src/qemu/qemu_monitor_text.c | 121 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_text.h | 11 ++++
3 files changed, 140 insertions(+), 38 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f33c24e..e9e7543 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4903,8 +4903,6 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
virDomainDeviceDefPtr dev)
{
virDomainHostdevDefPtr hostdev = dev->data.hostdev;
- char *cmd, *reply;
- unsigned domain, bus, slot;
pciDevice *pci;
if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
@@ -4931,51 +4929,23 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
return -1;
}
- cmd = reply = NULL;
-
- if (virAsprintf(&cmd, "pci_add pci_addr=auto host
host=%.2x:%.2x.%.1x",
- hostdev->source.subsys.u.pci.bus,
- hostdev->source.subsys.u.pci.slot,
- hostdev->source.subsys.u.pci.function) < 0) {
- virReportOOMError(conn);
- goto error;
- }
-
- if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
- qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
- "%s", _("cannot attach host pci device"));
+ if (qemuMonitorAddPCIHostDevice(vm,
+ hostdev->source.subsys.u.pci.domain,
+ hostdev->source.subsys.u.pci.bus,
+ hostdev->source.subsys.u.pci.slot,
+ hostdev->source.subsys.u.pci.function,
+
&hostdev->source.subsys.u.pci.guest_addr.domain,
+ &hostdev->source.subsys.u.pci.guest_addr.bus,
+ &hostdev->source.subsys.u.pci.guest_addr.slot)
< 0)
goto error;
- }
-
- if (strstr(reply, "invalid type: host")) {
- qemudReportError(conn, dom, NULL, VIR_ERR_NO_SUPPORT, "%s",
- _("PCI device assignment is not supported by this version
of qemu"));
- goto error;
- }
-
- if (qemudParsePciAddReply(vm, reply, &domain, &bus, &slot) < 0) {
- qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
- _("parsing pci_add reply failed: %s"), reply);
- goto error;
- }
-
- hostdev->source.subsys.u.pci.guest_addr.domain = domain;
- hostdev->source.subsys.u.pci.guest_addr.bus = bus;
- hostdev->source.subsys.u.pci.guest_addr.slot = slot;
vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
- VIR_FREE(reply);
- VIR_FREE(cmd);
-
return 0;
error:
pciDeviceListDel(conn, driver->activePciHostdevs, pci);
- VIR_FREE(reply);
- VIR_FREE(cmd);
-
return -1;
}
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 0e0334c..ca84fc6 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -1315,3 +1315,124 @@ int qemuMonitorAddUSBDeviceMatch(const virDomainObjPtr vm,
VIR_FREE(addr);
return ret;
}
+
+
+static int
+qemuMonitorParsePciAddReply(virDomainObjPtr vm,
+ const char *reply,
+ unsigned *domain,
+ unsigned *bus,
+ unsigned *slot)
+{
+ char *s, *e;
+
+ DEBUG("%s: pci_add reply: %s", vm->def->name, reply);
+
+ /* If the command succeeds qemu prints:
+ * OK bus 0, slot XXX...
+ * or
+ * OK domain 0, bus 0, slot XXX
+ */
+ if (!(s = strstr(reply, "OK ")))
+ return -1;
+
+ s += 3;
+
+ if (STRPREFIX(s, "domain ")) {
+ s += strlen("domain ");
+
+ if (virStrToLong_ui(s, &e, 10, domain) == -1) {
+ VIR_WARN(_("Unable to parse domain number '%s'\n"), s);
+ return -1;
+ }
+
+ if (!STRPREFIX(e, ", ")) {
+ VIR_WARN(_("Expected ', ' parsing pci_add reply
'%s'\n"), s);
+ return -1;
+ }
+ s = e + 2;
+ }
+
+ if (!STRPREFIX(s, "bus ")) {
+ VIR_WARN(_("Expected 'bus ' parsing pci_add reply
'%s'\n"), s);
+ return -1;
+ }
+ s += strlen("bus ");
+
+ if (virStrToLong_ui(s, &e, 10, bus) == -1) {
+ VIR_WARN(_("Unable to parse bus number '%s'\n"), s);
+ return -1;
+ }
+
+ if (!STRPREFIX(e, ", ")) {
+ VIR_WARN(_("Expected ', ' parsing pci_add reply
'%s'\n"), s);
+ return -1;
+ }
+ s = e + 2;
+
+ if (!STRPREFIX(s, "slot ")) {
+ VIR_WARN(_("Expected 'slot ' parsing pci_add reply
'%s'\n"), s);
+ return -1;
+ }
+ s += strlen("slot ");
+
+ if (virStrToLong_ui(s, &e, 10, slot) == -1) {
+ VIR_WARN(_("Unable to parse slot number '%s'\n"), s);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int qemuMonitorAddPCIHostDevice(const virDomainObjPtr vm,
+ unsigned hostDomain ATTRIBUTE_UNUSED,
+ unsigned hostBus,
+ unsigned hostSlot,
+ unsigned hostFunction,
+ unsigned *guestDomain,
+ unsigned *guestBus,
+ unsigned *guestSlot)
+{
+ char *cmd;
+ char *reply = NULL;
+ int ret = -1;
+
+ *guestDomain = *guestBus = *guestSlot = 0;
+
+ /* XXX hostDomain */
+ if (virAsprintf(&cmd, "pci_add pci_addr=auto host
host=%.2x:%.2x.%.1x",
+ hostBus, hostSlot, hostFunction) < 0) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "%s", _("cannot attach host pci device"));
+ goto cleanup;
+ }
+
+ if (strstr(reply, "invalid type: host")) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_NO_SUPPORT, "%s",
+ _("PCI device assignment is not supported by this version
of qemu"));
+ goto cleanup;
+ }
+
+ if (qemuMonitorParsePciAddReply(vm, reply,
+ guestDomain,
+ guestBus,
+ guestSlot) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ _("parsing pci_add reply failed: %s"), reply);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(cmd);
+ VIR_FREE(reply);
+ return ret;
+}
+
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 4153090..0e1b27b 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -147,4 +147,15 @@ int qemuMonitorAddUSBDeviceMatch(const virDomainObjPtr vm,
int vendor,
int product);
+
+int qemuMonitorAddPCIHostDevice(const virDomainObjPtr vm,
+ unsigned hostDomain,
+ unsigned hostBus,
+ unsigned hostSlot,
+ unsigned hostFunction,
+ unsigned *guestDomain,
+ unsigned *guestBus,
+ unsigned *guestSlot);
+
+
#endif /* QEMU_MONITOR_TEXT_H */
--
1.6.2.5