Since previous patches has prepared everything for us, we may now
implement live hotplug of a character device.
---
src/qemu/qemu_command.c | 38 +++++++++++++++++-
src/qemu/qemu_driver.c | 26 ++++++++++--
src/qemu/qemu_hotplug.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_hotplug.h | 6 +++
4 files changed, 168 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index d6ef9cd..735f300 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -863,8 +863,41 @@ qemuAssignDeviceControllerAlias(virDomainControllerDefPtr
controller)
return virAsprintf(&controller->info.alias, "%s%d", prefix,
controller->idx);
}
+static ssize_t
+qemuGetNextChrDevIndex(virDomainDefPtr def,
+ virDomainChrDefPtr chr,
+ const char *prefix)
+{
+ virDomainChrDefPtr **arrPtr;
+ size_t *cntPtr;
+ size_t i;
+ ssize_t idx = 0;
+ const char *prefix2 = NULL;
+
+ if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE)
+ prefix2 = "serial";
+
+ virDomainChrGetDomainPtrs(def, chr, &arrPtr, &cntPtr);
+
+ for (i = 0; i < *cntPtr; i++) {
+ ssize_t thisidx;
+ if (((thisidx = qemuDomainDeviceAliasIndex(&(*arrPtr)[i]->info, prefix))
< 0) &&
+ (prefix2 &&
+ (thisidx = qemuDomainDeviceAliasIndex(&(*arrPtr)[i]->info, prefix2))
< 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to determine device index for character
device"));
+ return -1;
+ }
+ if (thisidx >= idx)
+ idx = thisidx + 1;
+ }
+
+ return idx;
+}
+
+
int
-qemuAssignDeviceChrAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
+qemuAssignDeviceChrAlias(virDomainDefPtr def,
virDomainChrDefPtr chr,
ssize_t idx)
{
@@ -891,6 +924,9 @@ qemuAssignDeviceChrAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
return -1;
}
+ if (idx == -1 && (idx = qemuGetNextChrDevIndex(def, chr, prefix)) < 0)
+ return -1;
+
return virAsprintf(&chr->info.alias, "%s%zd", prefix, idx);
}
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 852db8b..b4a668a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6390,6 +6390,13 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
dev->data.redirdev = NULL;
break;
+ case VIR_DOMAIN_DEVICE_CHR:
+ ret = qemuDomainAttachChrDevice(driver, vm,
+ dev->data.chr);
+ if (!ret)
+ dev->data.chr = NULL;
+ break;
+
default:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("live attach of device '%s' is not
supported"),
@@ -6477,6 +6484,9 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
case VIR_DOMAIN_DEVICE_HOSTDEV:
ret = qemuDomainDetachHostDevice(driver, vm, dev);
break;
+ case VIR_DOMAIN_DEVICE_CHR:
+ ret = qemuDomainDetachChrDevice(driver, vm, dev->data.chr);
+ break;
default:
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("live detach of device '%s' is not
supported"),
@@ -6886,7 +6896,7 @@ static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char
*xml,
virDomainDefPtr vmdef = NULL;
virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
int ret = -1;
- unsigned int affect;
+ unsigned int affect, parse_flags = 0;
virQEMUCapsPtr qemuCaps = NULL;
qemuDomainObjPrivatePtr priv;
virQEMUDriverConfigPtr cfg = NULL;
@@ -6934,9 +6944,13 @@ static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char
*xml,
goto endjob;
}
+ if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
+ !(flags & VIR_DOMAIN_AFFECT_LIVE))
+ parse_flags |= VIR_DOMAIN_XML_INACTIVE;
+
dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
caps, driver->xmlopt,
- VIR_DOMAIN_XML_INACTIVE);
+ parse_flags);
if (dev == NULL)
goto endjob;
@@ -7164,7 +7178,7 @@ static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char
*xml,
virDomainDefPtr vmdef = NULL;
virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
int ret = -1;
- unsigned int affect;
+ unsigned int affect, parse_flags = 0;
virQEMUCapsPtr qemuCaps = NULL;
qemuDomainObjPrivatePtr priv;
virQEMUDriverConfigPtr cfg = NULL;
@@ -7212,9 +7226,13 @@ static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char
*xml,
goto endjob;
}
+ if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
+ !(flags & VIR_DOMAIN_AFFECT_LIVE))
+ parse_flags |= VIR_DOMAIN_XML_INACTIVE;
+
dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
caps, driver->xmlopt,
- VIR_DOMAIN_XML_INACTIVE);
+ parse_flags);
if (dev == NULL)
goto endjob;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 94f29e5..966e11c 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1234,6 +1234,62 @@ qemuDomainChrRemove(virDomainDefPtr vmdef,
return ret;
}
+
+int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainChrDefPtr chr)
+{
+ int ret = -1;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ virDomainDefPtr vmdef = vm->def;
+ char *devstr = NULL;
+ char *charAlias = NULL;
+ bool remove = false;
+
+ if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("qemu does not support -device"));
+ return ret;
+ }
+
+ if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0)
+ return ret;
+
+ if (qemuBuildChrDeviceStr(&devstr, vm->def, chr, priv->qemuCaps) < 0)
+ return ret;
+
+ if (virAsprintf(&charAlias, "char%s", chr->info.alias) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (qemuDomainChrInsert(vmdef, chr) < 0)
+ goto cleanup;
+ remove = true;
+
+ qemuDomainObjEnterMonitor(driver, vm);
+ if (qemuMonitorAttachCharDev(priv->mon, charAlias, &chr->source) < 0) {
+ qemuDomainObjExitMonitor(driver, vm);
+ goto cleanup;
+ }
+
+ if (devstr && qemuMonitorAddDevice(priv->mon, devstr) < 0) {
+ /* detach associated chardev on error */
+ qemuMonitorDetachCharDev(priv->mon, charAlias);
+ qemuDomainObjExitMonitor(driver, vm);
+ goto cleanup;
+ }
+ qemuDomainObjExitMonitor(driver, vm);
+
+ ret = 0;
+cleanup:
+ if (ret < 0 && remove)
+ qemuDomainChrRemove(vmdef, chr);
+ VIR_FREE(charAlias);
+ VIR_FREE(devstr);
+ return ret;
+}
+
int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainHostdevDefPtr hostdev)
@@ -3068,3 +3124,50 @@ int qemuDomainDetachLease(virQEMUDriverPtr driver,
virDomainLeaseDefFree(det_lease);
return 0;
}
+
+int qemuDomainDetachChrDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainChrDefPtr chr)
+{
+ int ret = -1;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ virDomainDefPtr vmdef = vm->def;
+ virDomainChrDefPtr tmpChr;
+ char *charAlias = NULL;
+ char *devstr = NULL;
+
+ if (!(tmpChr = virDomainChrFind(vmdef, chr))) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("device not present in domain configuration"));
+ return ret;
+ }
+
+ if (qemuBuildChrDeviceStr(&devstr, vm->def, chr, priv->qemuCaps) < 0)
+ return ret;
+
+ if (virAsprintf(&charAlias, "char%s", tmpChr->info.alias) < 0) {
+ virReportOOMError();
+ return ret;
+ }
+
+ qemuDomainObjEnterMonitor(driver, vm);
+ if (devstr && qemuMonitorDelDevice(priv->mon, tmpChr->info.alias) <
0) {
+ qemuDomainObjExitMonitor(driver, vm);
+ goto cleanup;
+ }
+
+ if (qemuMonitorDetachCharDev(priv->mon, charAlias) < 0) {
+ qemuDomainObjExitMonitor(driver, vm);
+ goto cleanup;
+ }
+ qemuDomainObjExitMonitor(driver, vm);
+
+ qemuDomainChrRemove(vmdef, tmpChr);
+ virDomainChrDefFree(tmpChr);
+ ret = 0;
+
+cleanup:
+ VIR_FREE(devstr);
+ VIR_FREE(charAlias);
+ return ret;
+}
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index c947d56..3f7e77e 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -104,6 +104,12 @@ int qemuDomainAttachLease(virQEMUDriverPtr driver,
int qemuDomainDetachLease(virQEMUDriverPtr driver,
virDomainObjPtr vm,
virDomainLeaseDefPtr lease);
+int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainChrDefPtr chr);
+int qemuDomainDetachChrDevice(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ virDomainChrDefPtr chr);
int
--
1.8.1.5