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 | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_hotplug.h | 6 +++ 4 files changed, 173 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 063d76b..6842cab 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 d858131..486de4e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6387,6 +6387,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_CONFIG_UNSUPPORTED, _("device type '%s' cannot be attached"), @@ -6474,6 +6481,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_CONFIG_UNSUPPORTED, "%s", _("This type of device cannot be hot unplugged")); @@ -6890,7 +6900,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; @@ -6938,9 +6948,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; @@ -7168,7 +7182,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; @@ -7216,9 +7230,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 cc8779d..237afe9 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1160,6 +1160,67 @@ error: } +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 (virDomainChrFind(vmdef, chr)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("chardev already exists")); + return ret; + } + + 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 (virDomainChrInsert(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) + virDomainChrRemove(vmdef, chr); + VIR_FREE(charAlias); + VIR_FREE(devstr); + return ret; +} + int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev) @@ -2992,3 +3053,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); + + virDomainChrRemove(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 da20eb1..46cd129 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); #endif /* __QEMU_HOTPLUG_H__ */ -- 1.8.1.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list