From 75f0fd5112470cfe866bda162ef43aa2601fa174 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Tue, 12 Mar 2013 15:59:25 +0100 Subject: [PATCH] qemu: Implement chardev hotplug on config level There are two levels on which a device may be hotplugged: config and live. The config level requires just an insert or remove from internal domain definition structure, which is exactly what this patch does. There is currently no implementation for a chardev update action, as there's not much to be updated. But more importantly, the only thing that can be updated is path or socket address by which chardevs are distinguished. So the update action is currently not supported. --- src/conf/domain_conf.c | 6 ++-- src/conf/domain_conf.h | 3 ++ src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 16 +++++++++ src/qemu/qemu_hotplug.c | 72 ++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_hotplug.h | 7 ++++ 6 files changed, 103 insertions(+), 2 deletions(-) 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__ */