diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 6ba1eea99b..5f7ef1952d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -10099,7 +10099,7 @@ virDomainLeaseRemove(virDomainDefPtr def, return virDomainLeaseRemoveAt(def, idx); } -static bool +bool virDomainChrEquals(virDomainChrDefPtr src, virDomainChrDefPtr tgt) { @@ -18036,9 +18036,11 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src, case VIR_DOMAIN_DEVICE_RNG: rc = virDomainRNGDefFormat(&buf, src->data.rng, flags); break; + case VIR_DOMAIN_DEVICE_CHR: + rc = virDomainChrDefFormat(&buf, src->data.chr, flags); + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_SMARTCARD: - case VIR_DOMAIN_DEVICE_CHR: case VIR_DOMAIN_DEVICE_MEMBALLOON: case VIR_DOMAIN_DEVICE_NVRAM: case VIR_DOMAIN_DEVICE_LAST: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index ef72d24830..c26f4e2a44 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2399,6 +2399,9 @@ virDomainChrGetDomainPtrs(virDomainDefPtr vmdef, virDomainChrDefPtr virDomainChrFind(virDomainDefPtr def, virDomainChrDefPtr target); +bool +virDomainChrEquals(virDomainChrDefPtr src, + virDomainChrDefPtr tgt); int virDomainChrInsert(virDomainDefPtr vmdef, virDomainChrDefPtr chr); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 3c27041ed1..fc4e750b53 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -115,6 +115,7 @@ virDomainChrConsoleTargetTypeToString; virDomainChrDefForeach; virDomainChrDefFree; virDomainChrDefNew; +virDomainChrEquals; virDomainChrFind; virDomainChrGetDomainPtrs; virDomainChrInsert; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 495867a50c..852db8ba0e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6686,6 +6686,12 @@ qemuDomainAttachDeviceConfig(virQEMUCapsPtr qemuCaps, return -1; break; + case VIR_DOMAIN_DEVICE_CHR: + if (qemuDomainChrInsert(vmdef, dev->data.chr) < 0) + return -1; + dev->data.chr = NULL; + break; + default: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent attach of device '%s' is not supported"), @@ -6705,6 +6711,7 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainHostdevDefPtr hostdev, det_hostdev; virDomainLeaseDefPtr lease, det_lease; virDomainControllerDefPtr cont, det_cont; + virDomainChrDefPtr chr; int idx; char mac[VIR_MAC_STRING_BUFLEN]; @@ -6772,6 +6779,15 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef, break; + case VIR_DOMAIN_DEVICE_CHR: + if (!(chr = qemuDomainChrRemove(vmdef, dev->data.chr))) + return -1; + + virDomainChrDefFree(chr); + virDomainChrDefFree(dev->data.chr); + dev->data.chr = NULL; + break; + default: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent detach of device '%s' is not supported"), diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index ac9350b0cf..dc24ea4485 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1172,6 +1172,78 @@ error: } +int +qemuDomainChrInsert(virDomainDefPtr vmdef, + virDomainChrDefPtr chr) +{ + if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && + chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("attaching serial console is not supported")); + return -1; + } + + if (virDomainChrFind(vmdef, chr)) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("chardev already exists")); + return -1; + } + + if (virDomainChrInsert(vmdef, chr) < 0) + return -1; + + /* Due to some crazy backcompat stuff, the first serial device is an alias + * to the first console too. If this is the case, the definition must be + * duplicated as first console device. */ + if (vmdef->nserials == 1 && vmdef->nconsoles == 0) { + if ((!vmdef->consoles && VIR_ALLOC(vmdef->consoles) < 0) || + VIR_ALLOC(vmdef->consoles[0]) < 0) { + virDomainChrRemove(vmdef, chr); + return -1; + } + vmdef->nconsoles = 1; + + /* Create an console alias for the serial port */ + vmdef->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE; + vmdef->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL; + } + + return 0; +} + +virDomainChrDefPtr +qemuDomainChrRemove(virDomainDefPtr vmdef, + virDomainChrDefPtr chr) +{ + virDomainChrDefPtr ret; + bool removeCompat; + + if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && + chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("detaching serial console is not supported")); + return NULL; + } + + /* Due to some crazy backcompat stuff, the first serial device is an alias + * to the first console too. If this is the case, the definition must be + * duplicated as first console device. */ + removeCompat = vmdef->nserials && vmdef->nconsoles && + vmdef->consoles[0]->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE && + vmdef->consoles[0]->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL && + virDomainChrEquals(vmdef->serials[0], chr); + + if (!(ret = virDomainChrRemove(vmdef, chr))) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("device not present in domain configuration")); + return NULL; + } + + if (removeCompat) + VIR_DELETE_ELEMENT(vmdef->consoles, 0, vmdef->nconsoles); + + return ret; +} int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainHostdevDefPtr hostdev) diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index da20eb1fe9..c947d56258 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -106,4 +106,11 @@ int qemuDomainDetachLease(virQEMUDriverPtr driver, virDomainLeaseDefPtr lease); +int +qemuDomainChrInsert(virDomainDefPtr vmdef, + virDomainChrDefPtr chr); +virDomainChrDefPtr +qemuDomainChrRemove(virDomainDefPtr vmdef, + virDomainChrDefPtr chr); + #endif /* __QEMU_HOTPLUG_H__ */