[libvirt] [PATCH 00/11] tests: qemu: Add cpu hotplug testing

Add some useful monitor infrastructure to simplify testing and add testing for the cpu hotplug code. The code has some complex logic which was not covered by current test suite. Peter Krempa (11): qemu: monitor: More strict checking of 'query-cpus' if hotplug is supported util: json: Add helper to reformat JSON strings tests: qemu: Document qemuMonitorTestNewFromFile qemu: Prepare for reuse of qemuDomainSetVcpusLive qemu: Move cpu hotplug code into qemu_hotplug.c tests: qemumonitor: Propagate better error messages tests: qemu: monitor: Add helpers to test full command syntax tests: qemu: Add helper to load full monitor conversation from file tests: hotplug: Add test infrastructure for testing qemu CPU hotplug code tests: hotplug: Add test data for legacy cpu hotplug tests: hotplug: Test CPU hotplug with ppc64 data src/libvirt_private.syms | 1 + src/qemu/qemu_driver.c | 319 ----------- src/qemu/qemu_hotplug.c | 328 ++++++++++++ src/qemu/qemu_hotplug.h | 7 + src/qemu/qemu_monitor.c | 6 +- src/qemu/qemu_monitor_json.c | 6 +- src/qemu/qemu_monitor_json.h | 3 +- src/util/virjson.c | 29 + src/util/virjson.h | 2 + tests/qemuagenttest.c | 3 +- tests/qemuhotplugtest.c | 194 +++++++ tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml | 20 + tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json | 593 +++++++++++++++++++++ .../qemuhotplugtestcpus/ppc64-bulk-result-conf.xml | 64 +++ .../qemuhotplugtestcpus/ppc64-bulk-result-live.xml | 72 +++ .../qemuhotplugtestcpus/x86-modern-bulk-domain.xml | 21 + .../x86-modern-bulk-monitor.json | 471 ++++++++++++++++ .../x86-modern-bulk-result-conf.xml | 40 ++ .../x86-modern-bulk-result-live.xml | 48 ++ tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml | 21 + .../qemuhotplugtestcpus/x86-old-bulk-monitor.json | 193 +++++++ .../x86-old-bulk-result-conf.xml | 30 ++ .../x86-old-bulk-result-live.xml | 38 ++ tests/qemumonitorjsontest.c | 2 +- tests/qemumonitortestutils.c | 322 ++++++++++- tests/qemumonitortestutils.h | 12 +- 26 files changed, 2505 insertions(+), 340 deletions(-) create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml -- 2.10.2

In cases where CPU hotplug is supported by qemu force the monitor to reject invalid or broken responses to 'query-cpus'. It's expected that the command returns usable data in such case. --- src/qemu/qemu_monitor.c | 6 +++--- src/qemu/qemu_monitor_json.c | 6 +++++- src/qemu/qemu_monitor_json.h | 3 ++- tests/qemumonitorjsontest.c | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 648168d..847db91 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1921,12 +1921,12 @@ qemuMonitorGetCPUInfo(qemuMonitorPtr mon, goto cleanup; if (mon->json) - rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries); + rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries, hotplug); else rc = qemuMonitorTextQueryCPUs(mon, &cpuentries, &ncpuentries); if (rc < 0) { - if (rc == -2) { + if (!hotplug && rc == -2) { VIR_STEAL_PTR(*vcpus, info); ret = 0; } @@ -1974,7 +1974,7 @@ qemuMonitorGetCpuHalted(qemuMonitorPtr mon, QEMU_CHECK_MONITOR_NULL(mon); if (mon->json) - rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries); + rc = qemuMonitorJSONQueryCPUs(mon, &cpuentries, &ncpuentries, false); else rc = qemuMonitorTextQueryCPUs(mon, &cpuentries, &ncpuentries); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 0c38b8f..350076b 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1394,7 +1394,8 @@ qemuMonitorJSONExtractCPUInfo(virJSONValuePtr data, int qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon, struct qemuMonitorQueryCpusEntry **entries, - size_t *nentries) + size_t *nentries, + bool force) { int ret = -1; virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-cpus", NULL); @@ -1407,6 +1408,9 @@ qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon, if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) goto cleanup; + if (force && qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + if (!(data = virJSONValueObjectGetArray(reply, "return"))) { ret = -2; goto cleanup; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index adff0c3..52b533e 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -60,7 +60,8 @@ int qemuMonitorJSONSystemReset(qemuMonitorPtr mon); int qemuMonitorJSONQueryCPUs(qemuMonitorPtr mon, struct qemuMonitorQueryCpusEntry **entries, - size_t *nentries); + size_t *nentries, + bool force); int qemuMonitorJSONGetVirtType(qemuMonitorPtr mon, virDomainVirtType *virtType); int qemuMonitorJSONUpdateVideoMemorySize(qemuMonitorPtr mon, diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 535fb63..5b2d6bb 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1407,7 +1407,7 @@ testQemuMonitorJSONqemuMonitorJSONQueryCPUs(const void *data) goto cleanup; if (qemuMonitorJSONQueryCPUs(qemuMonitorTestGetMonitor(test), - &cpudata, &ncpudata) < 0) + &cpudata, &ncpudata, true) < 0) goto cleanup; if (ncpudata != 4) { -- 2.10.2

For use in test cases it will be helpful to allow reformatting JSON strings. Add a wrapper on top of the parser and formatter to achieve this. --- src/libvirt_private.syms | 1 + src/util/virjson.c | 29 +++++++++++++++++++++++++++++ src/util/virjson.h | 2 ++ 3 files changed, 32 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 867acdb..bd80f62 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1769,6 +1769,7 @@ virISCSIScanTargets; # util/virjson.h +virJSONStringReformat; virJSONValueArrayAppend; virJSONValueArrayForeachSteal; virJSONValueArrayGet; diff --git a/src/util/virjson.c b/src/util/virjson.c index b42211c..d96f62a 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -1918,3 +1918,32 @@ virJSONValueToString(virJSONValuePtr object ATTRIBUTE_UNUSED, return NULL; } #endif + + +/** + * virJSONStringReformat: + * @jsonstr: string to reformat + * @pretty: use the pretty formatter + * + * Reformats a JSON string by passing it to the parser and then to the + * formatter. If @pretty is true the JSON is formatted for human eye + * compatibility. + * + * Returns the reformatted JSON string on success; NULL and a libvirt error on + * failure. + */ +char * +virJSONStringReformat(const char *jsonstr, + bool pretty) +{ + virJSONValuePtr json; + char *ret; + + if (!(json = virJSONValueFromString(jsonstr))) + return NULL; + + ret = virJSONValueToString(json, pretty); + + virJSONValueFree(json); + return ret; +} diff --git a/src/util/virjson.h b/src/util/virjson.h index 5b4f172..3340a79 100644 --- a/src/util/virjson.h +++ b/src/util/virjson.h @@ -181,4 +181,6 @@ int virJSONValueObjectForeachKeyValue(const virJSONValue *object, virJSONValuePtr virJSONValueCopy(const virJSONValue *in); +char *virJSONStringReformat(const char *jsonstr, bool pretty); + #endif /* __VIR_JSON_H_ */ -- 2.10.2

--- tests/qemumonitortestutils.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index f8f23c3..3722b07 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -1037,6 +1037,19 @@ qemuMonitorTestNew(bool json, } +/** + * qemuMonitorTestNewFromFile: + * @fileName: File name to load monitor replies from + * @xmlopt: XML parser configuration object + * @simple: see below + * + * Create a JSON test monitor simulator object and fill it with replies + * specified in @fileName. The file contains JSON reply objects separated by + * empty lines. If @simple is true a generic QMP greeting is automatically + * added as the first reply, otherwise the first entry in the file is used. + * + * Returns the monitor object on success; NULL on error. + */ qemuMonitorTestPtr qemuMonitorTestNewFromFile(const char *fileName, virDomainXMLOptionPtr xmlopt, -- 2.10.2

Extract the call to qemuDomainSelectHotplugVcpuEntities outside of qemuDomainSetVcpusLive and decide whether to hotplug or unplug the entities specified by the cpumap using a boolean flag. This will allow to use qemuDomainSetVcpusLive in cases where we prepare the list of vcpus to enable or disable by other means. --- src/qemu/qemu_driver.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 842de0a..af8f458 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4776,6 +4776,7 @@ qemuDomainSetVcpusMax(virQEMUDriverPtr driver, * * @def: domain definition * @nvcpus: target vcpu count + * @enable: set to true if vcpus should be enabled * * Tries to find which vcpu entities need to be enabled or disabled to reach * @nvcpus. This function works in order of the legacy hotplug but is able to @@ -4785,7 +4786,8 @@ qemuDomainSetVcpusMax(virQEMUDriverPtr driver, */ static virBitmapPtr qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, - unsigned int nvcpus) + unsigned int nvcpus, + bool *enable) { virBitmapPtr ret = NULL; virDomainVcpuDefPtr vcpu; @@ -4798,6 +4800,8 @@ qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, return NULL; if (nvcpus > curvcpus) { + *enable = true; + for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) { vcpu = virDomainDefGetVcpu(def, i); vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); @@ -4820,6 +4824,8 @@ qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, ignore_value(virBitmapSetBit(ret, i)); } } else { + *enable = false; + for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) { vcpu = virDomainDefGetVcpu(def, i); vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); @@ -4865,22 +4871,19 @@ static int qemuDomainSetVcpusLive(virQEMUDriverPtr driver, virQEMUDriverConfigPtr cfg, virDomainObjPtr vm, - unsigned int nvcpus) + virBitmapPtr vcpumap, + bool enable) { qemuDomainObjPrivatePtr priv = vm->privateData; qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL; - virBitmapPtr vcpumap = NULL; ssize_t nextvcpu = -1; int rc = 0; int ret = -1; - if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus))) - goto cleanup; - if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) goto cleanup; - if (nvcpus > virDomainDefGetVcpus(vm->def)) { + if (enable) { while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) { if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0) break; @@ -4907,7 +4910,6 @@ qemuDomainSetVcpusLive(virQEMUDriverPtr driver, cleanup: qemuCgroupEmulatorAllNodesRestore(emulatorCgroup); - virBitmapFree(vcpumap); return ret; } @@ -4982,6 +4984,8 @@ qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, bool hotpluggable) { virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + virBitmapPtr vcpumap = NULL; + bool enable; int ret = -1; if (def && nvcpus > virDomainDefGetVcpusMax(def)) { @@ -5000,8 +5004,14 @@ qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, goto cleanup; } - if (def && qemuDomainSetVcpusLive(driver, cfg, vm, nvcpus) < 0) - goto cleanup; + if (def) { + if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus, + &enable))) + goto cleanup; + + if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0) + goto cleanup; + } if (persistentDef) { qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable); @@ -5013,6 +5023,7 @@ qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, ret = 0; cleanup: + virBitmapFree(vcpumap); virObjectUnref(cfg); return ret; } -- 2.10.2

Move all the worker code into the appropriate file. This will also allow testing of cpu hotplug. --- src/qemu/qemu_driver.c | 330 ------------------------------------------------ src/qemu/qemu_hotplug.c | 328 +++++++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_hotplug.h | 7 + 3 files changed, 335 insertions(+), 330 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index af8f458..79dadff 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4608,76 +4608,6 @@ static void qemuProcessEventHandler(void *data, void *opaque) static int -qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver, - virDomainObjPtr vm, - unsigned int vcpu) -{ - virJSONValuePtr vcpuprops = NULL; - virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu); - qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo); - unsigned int nvcpus = vcpupriv->vcpus; - bool newhotplug = qemuDomainSupportsNewVcpuHotplug(vm); - int ret = -1; - int rc; - int oldvcpus = virDomainDefGetVcpus(vm->def); - size_t i; - - if (newhotplug) { - if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0) - goto cleanup; - - if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo))) - goto cleanup; - } - - qemuDomainObjEnterMonitor(driver, vm); - - if (newhotplug) { - rc = qemuMonitorAddDeviceArgs(qemuDomainGetMonitor(vm), vcpuprops); - vcpuprops = NULL; - } else { - rc = qemuMonitorSetCPU(qemuDomainGetMonitor(vm), vcpu, true); - } - - if (qemuDomainObjExitMonitor(driver, vm) < 0) - goto cleanup; - - virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0); - - if (rc < 0) - goto cleanup; - - /* start outputting of the new XML element to allow keeping unpluggability */ - if (newhotplug) - vm->def->individualvcpus = true; - - if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0) - goto cleanup; - - /* validation requires us to set the expected state prior to calling it */ - for (i = vcpu; i < vcpu + nvcpus; i++) { - vcpuinfo = virDomainDefGetVcpu(vm->def, i); - vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo); - - vcpuinfo->online = true; - - if (vcpupriv->tid > 0 && - qemuProcessSetupVcpu(vm, i) < 0) - goto cleanup; - } - - if (qemuDomainValidateVcpuInfo(vm) < 0) - goto cleanup; - - ret = 0; - - cleanup: - virJSONValueFree(vcpuprops); - return ret; -} - - -static int qemuDomainSetVcpusAgent(virDomainObjPtr vm, unsigned int nvcpus) { @@ -4769,266 +4699,6 @@ qemuDomainSetVcpusMax(virQEMUDriverPtr driver, virObjectUnref(cfg); return ret; } - - -/** - * qemuDomainSelectHotplugVcpuEntities: - * - * @def: domain definition - * @nvcpus: target vcpu count - * @enable: set to true if vcpus should be enabled - * - * Tries to find which vcpu entities need to be enabled or disabled to reach - * @nvcpus. This function works in order of the legacy hotplug but is able to - * skip over entries that are added out of order. - * - * Returns the bitmap of vcpus to modify on success, NULL on error. - */ -static virBitmapPtr -qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, - unsigned int nvcpus, - bool *enable) -{ - virBitmapPtr ret = NULL; - virDomainVcpuDefPtr vcpu; - qemuDomainVcpuPrivatePtr vcpupriv; - unsigned int maxvcpus = virDomainDefGetVcpusMax(def); - unsigned int curvcpus = virDomainDefGetVcpus(def); - ssize_t i; - - if (!(ret = virBitmapNew(maxvcpus))) - return NULL; - - if (nvcpus > curvcpus) { - *enable = true; - - for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) { - vcpu = virDomainDefGetVcpu(def, i); - vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); - - if (vcpu->online) - continue; - - if (vcpupriv->vcpus == 0) - continue; - - curvcpus += vcpupriv->vcpus; - - if (curvcpus > nvcpus) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("target vm vcpu granularity does not allow the " - "desired vcpu count")); - goto error; - } - - ignore_value(virBitmapSetBit(ret, i)); - } - } else { - *enable = false; - - for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) { - vcpu = virDomainDefGetVcpu(def, i); - vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); - - if (!vcpu->online) - continue; - - if (vcpupriv->vcpus == 0) - continue; - - if (!vcpupriv->alias) - continue; - - curvcpus -= vcpupriv->vcpus; - - if (curvcpus < nvcpus) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("target vm vcpu granularity does not allow the " - "desired vcpu count")); - goto error; - } - - ignore_value(virBitmapSetBit(ret, i)); - } - } - - if (curvcpus != nvcpus) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("failed to find appropriate hotpluggable vcpus to " - "reach the desired target vcpu count")); - goto error; - } - - return ret; - - error: - virBitmapFree(ret); - return NULL; -} - - -static int -qemuDomainSetVcpusLive(virQEMUDriverPtr driver, - virQEMUDriverConfigPtr cfg, - virDomainObjPtr vm, - virBitmapPtr vcpumap, - bool enable) -{ - qemuDomainObjPrivatePtr priv = vm->privateData; - qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL; - ssize_t nextvcpu = -1; - int rc = 0; - int ret = -1; - - if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) - goto cleanup; - - if (enable) { - while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) { - if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0) - break; - } - } else { - for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) { - if (!virBitmapIsBitSet(vcpumap, nextvcpu)) - continue; - - if ((rc = qemuDomainHotplugDelVcpu(driver, vm, nextvcpu)) < 0) - break; - } - } - - qemuDomainVcpuPersistOrder(vm->def); - - if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) - goto cleanup; - - if (rc < 0) - goto cleanup; - - ret = 0; - - cleanup: - qemuCgroupEmulatorAllNodesRestore(emulatorCgroup); - - return ret; -} - - -/** - * qemuDomainSetVcpusConfig: - * @def: config/offline definition of a domain - * @nvcpus: target vcpu count - * - * Properly handle cold(un)plug of vcpus: - * - plug in inactive vcpus/uplug active rather than rewriting state - * - fix hotpluggable state - */ -static void -qemuDomainSetVcpusConfig(virDomainDefPtr def, - unsigned int nvcpus, - bool hotpluggable) -{ - virDomainVcpuDefPtr vcpu; - size_t curvcpus = virDomainDefGetVcpus(def); - size_t maxvcpus = virDomainDefGetVcpusMax(def); - size_t i; - - /* ordering information may become invalid, thus clear it */ - virDomainDefVcpuOrderClear(def); - - if (curvcpus == nvcpus) - return; - - if (curvcpus < nvcpus) { - for (i = 0; i < maxvcpus; i++) { - vcpu = virDomainDefGetVcpu(def, i); - - if (!vcpu || vcpu->online) - continue; - - vcpu->online = true; - if (hotpluggable) { - vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES; - def->individualvcpus = true; - } else { - vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO; - } - - if (++curvcpus == nvcpus) - break; - } - } else { - for (i = maxvcpus; i != 0; i--) { - vcpu = virDomainDefGetVcpu(def, i - 1); - - if (!vcpu || !vcpu->online) - continue; - - vcpu->online = false; - vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES; - - if (--curvcpus == nvcpus) - break; - } - } -} - - -static int -qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, - virDomainObjPtr vm, - virDomainDefPtr def, - virDomainDefPtr persistentDef, - unsigned int nvcpus, - bool hotpluggable) -{ - virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); - virBitmapPtr vcpumap = NULL; - bool enable; - int ret = -1; - - if (def && nvcpus > virDomainDefGetVcpusMax(def)) { - virReportError(VIR_ERR_INVALID_ARG, - _("requested vcpus is greater than max allowable" - " vcpus for the live domain: %u > %u"), - nvcpus, virDomainDefGetVcpusMax(def)); - goto cleanup; - } - - if (persistentDef && nvcpus > virDomainDefGetVcpusMax(persistentDef)) { - virReportError(VIR_ERR_INVALID_ARG, - _("requested vcpus is greater than max allowable" - " vcpus for the persistent domain: %u > %u"), - nvcpus, virDomainDefGetVcpusMax(persistentDef)); - goto cleanup; - } - - if (def) { - if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus, - &enable))) - goto cleanup; - - if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0) - goto cleanup; - } - - if (persistentDef) { - qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable); - - if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0) - goto cleanup; - } - - ret = 0; - - cleanup: - virBitmapFree(vcpumap); - virObjectUnref(cfg); - return ret; -} - - static int qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 55af888..c83bb6e 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -5299,3 +5299,331 @@ qemuDomainHotplugDelVcpu(virQEMUDriverPtr driver, return qemuDomainRemoveVcpu(driver, vm, vcpu); } + + +static int +qemuDomainHotplugAddVcpu(virQEMUDriverPtr driver, + virDomainObjPtr vm, + unsigned int vcpu) +{ + virJSONValuePtr vcpuprops = NULL; + virDomainVcpuDefPtr vcpuinfo = virDomainDefGetVcpu(vm->def, vcpu); + qemuDomainVcpuPrivatePtr vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo); + unsigned int nvcpus = vcpupriv->vcpus; + bool newhotplug = qemuDomainSupportsNewVcpuHotplug(vm); + int ret = -1; + int rc; + int oldvcpus = virDomainDefGetVcpus(vm->def); + size_t i; + + if (newhotplug) { + if (virAsprintf(&vcpupriv->alias, "vcpu%u", vcpu) < 0) + goto cleanup; + + if (!(vcpuprops = qemuBuildHotpluggableCPUProps(vcpuinfo))) + goto cleanup; + } + + qemuDomainObjEnterMonitor(driver, vm); + + if (newhotplug) { + rc = qemuMonitorAddDeviceArgs(qemuDomainGetMonitor(vm), vcpuprops); + vcpuprops = NULL; + } else { + rc = qemuMonitorSetCPU(qemuDomainGetMonitor(vm), vcpu, true); + } + + if (qemuDomainObjExitMonitor(driver, vm) < 0) + goto cleanup; + + virDomainAuditVcpu(vm, oldvcpus, oldvcpus + nvcpus, "update", rc == 0); + + if (rc < 0) + goto cleanup; + + /* start outputting of the new XML element to allow keeping unpluggability */ + if (newhotplug) + vm->def->individualvcpus = true; + + if (qemuDomainRefreshVcpuInfo(driver, vm, QEMU_ASYNC_JOB_NONE, false) < 0) + goto cleanup; + + /* validation requires us to set the expected state prior to calling it */ + for (i = vcpu; i < vcpu + nvcpus; i++) { + vcpuinfo = virDomainDefGetVcpu(vm->def, i); + vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpuinfo); + + vcpuinfo->online = true; + + if (vcpupriv->tid > 0 && + qemuProcessSetupVcpu(vm, i) < 0) + goto cleanup; + } + + if (qemuDomainValidateVcpuInfo(vm) < 0) + goto cleanup; + + ret = 0; + + cleanup: + virJSONValueFree(vcpuprops); + return ret; +} + + +/** + * qemuDomainSelectHotplugVcpuEntities: + * + * @def: domain definition + * @nvcpus: target vcpu count + * @enable: set to true if vcpus should be enabled + * + * Tries to find which vcpu entities need to be enabled or disabled to reach + * @nvcpus. This function works in order of the legacy hotplug but is able to + * skip over entries that are added out of order. + * + * Returns the bitmap of vcpus to modify on success, NULL on error. + */ +static virBitmapPtr +qemuDomainSelectHotplugVcpuEntities(virDomainDefPtr def, + unsigned int nvcpus, + bool *enable) +{ + virBitmapPtr ret = NULL; + virDomainVcpuDefPtr vcpu; + qemuDomainVcpuPrivatePtr vcpupriv; + unsigned int maxvcpus = virDomainDefGetVcpusMax(def); + unsigned int curvcpus = virDomainDefGetVcpus(def); + ssize_t i; + + if (!(ret = virBitmapNew(maxvcpus))) + return NULL; + + if (nvcpus > curvcpus) { + *enable = true; + + for (i = 0; i < maxvcpus && curvcpus < nvcpus; i++) { + vcpu = virDomainDefGetVcpu(def, i); + vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); + + if (vcpu->online) + continue; + + if (vcpupriv->vcpus == 0) + continue; + + curvcpus += vcpupriv->vcpus; + + if (curvcpus > nvcpus) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("target vm vcpu granularity does not allow the " + "desired vcpu count")); + goto error; + } + + ignore_value(virBitmapSetBit(ret, i)); + } + } else { + *enable = false; + + for (i = maxvcpus - 1; i >= 0 && curvcpus > nvcpus; i--) { + vcpu = virDomainDefGetVcpu(def, i); + vcpupriv = QEMU_DOMAIN_VCPU_PRIVATE(vcpu); + + if (!vcpu->online) + continue; + + if (vcpupriv->vcpus == 0) + continue; + + if (!vcpupriv->alias) + continue; + + curvcpus -= vcpupriv->vcpus; + + if (curvcpus < nvcpus) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("target vm vcpu granularity does not allow the " + "desired vcpu count")); + goto error; + } + + ignore_value(virBitmapSetBit(ret, i)); + } + } + + if (curvcpus != nvcpus) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("failed to find appropriate hotpluggable vcpus to " + "reach the desired target vcpu count")); + goto error; + } + + return ret; + + error: + virBitmapFree(ret); + return NULL; +} + + +static int +qemuDomainSetVcpusLive(virQEMUDriverPtr driver, + virQEMUDriverConfigPtr cfg, + virDomainObjPtr vm, + virBitmapPtr vcpumap, + bool enable) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + qemuCgroupEmulatorAllNodesDataPtr emulatorCgroup = NULL; + ssize_t nextvcpu = -1; + int rc = 0; + int ret = -1; + + if (qemuCgroupEmulatorAllNodesAllow(priv->cgroup, &emulatorCgroup) < 0) + goto cleanup; + + if (enable) { + while ((nextvcpu = virBitmapNextSetBit(vcpumap, nextvcpu)) != -1) { + if ((rc = qemuDomainHotplugAddVcpu(driver, vm, nextvcpu)) < 0) + break; + } + } else { + for (nextvcpu = virDomainDefGetVcpusMax(vm->def) - 1; nextvcpu >= 0; nextvcpu--) { + if (!virBitmapIsBitSet(vcpumap, nextvcpu)) + continue; + + if ((rc = qemuDomainHotplugDelVcpu(driver, vm, nextvcpu)) < 0) + break; + } + } + + qemuDomainVcpuPersistOrder(vm->def); + + if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, driver->caps) < 0) + goto cleanup; + + if (rc < 0) + goto cleanup; + + ret = 0; + + cleanup: + qemuCgroupEmulatorAllNodesRestore(emulatorCgroup); + + return ret; +} + + +/** + * qemuDomainSetVcpusConfig: + * @def: config/offline definition of a domain + * @nvcpus: target vcpu count + * + * Properly handle cold(un)plug of vcpus: + * - plug in inactive vcpus/uplug active rather than rewriting state + * - fix hotpluggable state + */ +static void +qemuDomainSetVcpusConfig(virDomainDefPtr def, + unsigned int nvcpus, + bool hotpluggable) +{ + virDomainVcpuDefPtr vcpu; + size_t curvcpus = virDomainDefGetVcpus(def); + size_t maxvcpus = virDomainDefGetVcpusMax(def); + size_t i; + + /* ordering information may become invalid, thus clear it */ + virDomainDefVcpuOrderClear(def); + + if (curvcpus == nvcpus) + return; + + if (curvcpus < nvcpus) { + for (i = 0; i < maxvcpus; i++) { + vcpu = virDomainDefGetVcpu(def, i); + + if (!vcpu || vcpu->online) + continue; + + vcpu->online = true; + if (hotpluggable) { + vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES; + def->individualvcpus = true; + } else { + vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO; + } + + if (++curvcpus == nvcpus) + break; + } + } else { + for (i = maxvcpus; i != 0; i--) { + vcpu = virDomainDefGetVcpu(def, i - 1); + + if (!vcpu || !vcpu->online) + continue; + + vcpu->online = false; + vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES; + + if (--curvcpus == nvcpus) + break; + } + } +} + + +int +qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDefPtr def, + virDomainDefPtr persistentDef, + unsigned int nvcpus, + bool hotpluggable) +{ + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + virBitmapPtr vcpumap = NULL; + bool enable; + int ret = -1; + + if (def && nvcpus > virDomainDefGetVcpusMax(def)) { + virReportError(VIR_ERR_INVALID_ARG, + _("requested vcpus is greater than max allowable" + " vcpus for the live domain: %u > %u"), + nvcpus, virDomainDefGetVcpusMax(def)); + goto cleanup; + } + + if (persistentDef && nvcpus > virDomainDefGetVcpusMax(persistentDef)) { + virReportError(VIR_ERR_INVALID_ARG, + _("requested vcpus is greater than max allowable" + " vcpus for the persistent domain: %u > %u"), + nvcpus, virDomainDefGetVcpusMax(persistentDef)); + goto cleanup; + } + + if (def) { + if (!(vcpumap = qemuDomainSelectHotplugVcpuEntities(vm->def, nvcpus, + &enable))) + goto cleanup; + + if (qemuDomainSetVcpusLive(driver, cfg, vm, vcpumap, enable) < 0) + goto cleanup; + } + + if (persistentDef) { + qemuDomainSetVcpusConfig(persistentDef, nvcpus, hotpluggable); + + if (virDomainSaveConfig(cfg->configDir, driver->caps, persistentDef) < 0) + goto cleanup; + } + + ret = 0; + + cleanup: + virBitmapFree(vcpumap); + virObjectUnref(cfg); + return ret; +} diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 85ec724..13242ee 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -136,4 +136,11 @@ bool qemuDomainSignalDeviceRemoval(virDomainObjPtr vm, const char *devAlias, qemuDomainUnpluggingDeviceStatus status); +int qemuDomainSetVcpusInternal(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDefPtr def, + virDomainDefPtr persistentDef, + unsigned int nvcpus, + bool hotpluggable); + #endif /* __QEMU_HOTPLUG_H__ */ -- 2.10.2

--- tests/qemuagenttest.c | 3 +- tests/qemumonitortestutils.c | 101 +++++++++++++++++++++++++++++++++++++------ tests/qemumonitortestutils.h | 4 +- 3 files changed, 93 insertions(+), 15 deletions(-) diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c index 5dfa58e..3be745e 100644 --- a/tests/qemuagenttest.c +++ b/tests/qemuagenttest.c @@ -375,7 +375,8 @@ qemuAgentShutdownTestMonitorHandler(qemuMonitorTestPtr test, } if (STRNEQ(cmdname, "guest-shutdown")) { - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, "guest-shutdown", + cmdname); goto cleanup; } diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index 3722b07..fb4f51c 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -118,17 +118,89 @@ qemuMonitorTestAddResponse(qemuMonitorTestPtr test, } -int -qemuMonitorTestAddUnexpectedErrorResponse(qemuMonitorTestPtr test) +static int +qemuMonitorTestAddErrorResponse(qemuMonitorTestPtr test, + const char *usermsg) { - if (test->agent || test->json) { - return qemuMonitorTestAddResponse(test, - "{ \"error\": " - " { \"desc\": \"Unexpected command\", " - " \"class\": \"UnexpectedCommand\" } }"); + virBuffer buf = VIR_BUFFER_INITIALIZER; + char *escapemsg = NULL; + char *jsonmsg = NULL; + const char *monmsg = NULL; + char *tmp; + int ret = -1; + + if (!usermsg) + usermsg = "unexpected command"; + + if (test->json || test->agent) { + virBufferEscape(&buf, '\\', "\"", "%s", usermsg); + if (virBufferCheckError(&buf) < 0) + goto error; + escapemsg = virBufferContentAndReset(&buf); + + /* replace newline/carriage return with space */ + tmp = escapemsg; + while (*tmp) { + if (*tmp == '\r' || *tmp == '\n') + *tmp = ' '; + + tmp++; + } + + /* format the JSON error message */ + if (virAsprintf(&jsonmsg, "{ \"error\": " + " { \"desc\": \"%s\", " + " \"class\": \"UnexpectedCommand\" } }", + escapemsg) < 0) + goto error; + + monmsg = jsonmsg; } else { - return qemuMonitorTestAddResponse(test, "unexpected command"); + monmsg = usermsg; } + + ret = qemuMonitorTestAddResponse(test, monmsg); + + error: + VIR_FREE(escapemsg); + VIR_FREE(jsonmsg); + return ret; +} + + +static int +qemuMonitorTestAddUnexpectedErrorResponse(qemuMonitorTestPtr test, + const char *command) +{ + char *msg; + int ret; + + if (virAsprintf(&msg, "unexpected command: '%s'", command) < 0) + return -1; + + ret = qemuMonitorTestAddErrorResponse(test, msg); + + VIR_FREE(msg); + return ret; +} + + +int +qemuMonitorTestAddInvalidCommandResponse(qemuMonitorTestPtr test, + const char *expectedcommand, + const char *actualcommand) +{ + char *msg; + int ret; + + if (virAsprintf(&msg, "expected command '%s' got '%s'", + expectedcommand, actualcommand) < 0) + return -1; + + ret = qemuMonitorTestAddErrorResponse(test, msg); + + VIR_FREE(msg); + return ret; } @@ -181,7 +253,7 @@ qemuMonitorTestProcessCommand(qemuMonitorTestPtr test, VIR_DEBUG("Processing string from monitor handler: '%s", cmdstr); if (test->nitems == 0) { - return qemuMonitorTestAddUnexpectedErrorResponse(test); + return qemuMonitorTestAddUnexpectedErrorResponse(test, cmdstr); } else { qemuMonitorTestItemPtr item = test->items[0]; ret = (item->cb)(test, item, cmdstr); @@ -499,7 +571,8 @@ qemuMonitorTestProcessCommandDefault(qemuMonitorTestPtr test, } if (data->command_name && STRNEQ(data->command_name, cmdname)) - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, data->command_name, + cmdname); else ret = qemuMonitorTestAddResponse(test, data->response); @@ -553,7 +626,7 @@ qemuMonitorTestProcessGuestAgentSync(qemuMonitorTestPtr test, } if (STRNEQ(cmdname, "guest-sync")) { - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, "guest-sync", cmdname); goto cleanup; } @@ -619,7 +692,8 @@ qemuMonitorTestProcessCommandWithArgs(qemuMonitorTestPtr test, if (data->command_name && STRNEQ(data->command_name, cmdname)) { - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, data->command_name, + cmdname); goto cleanup; } @@ -745,7 +819,8 @@ qemuMonitorTestProcessCommandWithArgStr(qemuMonitorTestPtr test, } if (STRNEQ(data->command_name, cmdname)) { - ret = qemuMonitorTestAddUnexpectedErrorResponse(test); + ret = qemuMonitorTestAddInvalidCommandResponse(test, data->command_name, + cmdname); goto cleanup; } diff --git a/tests/qemumonitortestutils.h b/tests/qemumonitortestutils.h index 3890cd4..87c11af 100644 --- a/tests/qemumonitortestutils.h +++ b/tests/qemumonitortestutils.h @@ -42,7 +42,9 @@ int qemuMonitorTestAddHandler(qemuMonitorTestPtr test, int qemuMonitorTestAddResponse(qemuMonitorTestPtr test, const char *response); -int qemuMonitorTestAddUnexpectedErrorResponse(qemuMonitorTestPtr test); +int qemuMonitorTestAddInvalidCommandResponse(qemuMonitorTestPtr test, + const char *expectedcommand, + const char *actualcommand); void *qemuMonitorTestItemGetPrivateData(qemuMonitorTestItemPtr item); -- 2.10.2

Add test monitor infrastructure that will test the commands verbatim rather than trying to do any smart handling. --- tests/qemumonitortestutils.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ tests/qemumonitortestutils.h | 5 +++ 2 files changed, 94 insertions(+) diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index fb4f51c..50042f9 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -508,6 +508,7 @@ struct _qemuMonitorTestCommandArgs { struct qemuMonitorTestHandlerData { char *command_name; + char *cmderr; char *response; size_t nargs; qemuMonitorTestCommandArgsPtr args; @@ -529,6 +530,7 @@ qemuMonitorTestHandlerDataFree(void *opaque) } VIR_FREE(data->command_name); + VIR_FREE(data->cmderr); VIR_FREE(data->response); VIR_FREE(data->args); VIR_FREE(data->expectArgs); @@ -606,6 +608,93 @@ qemuMonitorTestAddItem(qemuMonitorTestPtr test, static int +qemuMonitorTestProcessCommandVerbatim(qemuMonitorTestPtr test, + qemuMonitorTestItemPtr item, + const char *cmdstr) +{ + struct qemuMonitorTestHandlerData *data = item->opaque; + char *reformatted = NULL; + char *errmsg = NULL; + int ret = -1; + + /* JSON strings will be reformatted to simplify checking */ + if (test->json || test->agent) { + if (!(reformatted = virJSONStringReformat(cmdstr, false))) + return -1; + + cmdstr = reformatted; + } + + if (STREQ(data->command_name, cmdstr)) { + ret = qemuMonitorTestAddResponse(test, data->response); + } else { + if (data->cmderr) { + if (virAsprintf(&errmsg, "%s: %s", data->cmderr, cmdstr) < 0) + goto cleanup; + + ret = qemuMonitorTestAddErrorResponse(test, errmsg); + } else { + ret = qemuMonitorTestAddInvalidCommandResponse(test, + data->command_name, + cmdstr); + } + } + + cleanup: + VIR_FREE(errmsg); + VIR_FREE(reformatted); + return ret; +} + + +/** + * qemuMonitorTestAddItemVerbatim: + * @test: monitor test object + * @command: full expected command syntax + * @cmderr: possible explanation of expected command (may be NULL) + * @response: full reply of @command + * + * Adds a test command for the simulated monitor. The full syntax is checked + * as specified in @command. For JSON monitor tests formatting/whitespace is + * ignored. If the command on the monitor is not as expected an error containing + * @cmderr is returned. Otherwise @response is put as-is on the monitor. + * + * Returns 0 when command was succesfully added, -1 on error. + */ +int +qemuMonitorTestAddItemVerbatim(qemuMonitorTestPtr test, + const char *command, + const char *cmderr, + const char *response) +{ + struct qemuMonitorTestHandlerData *data; + + if (VIR_ALLOC(data) < 0) + return -1; + + if (VIR_STRDUP(data->response, response) < 0 || + VIR_STRDUP(data->cmderr, cmderr) < 0) + goto error; + + if (test->json || test->agent) + data->command_name = virJSONStringReformat(command, false); + else + ignore_value(VIR_STRDUP(data->command_name, command)); + + if (!data->command_name) + goto error; + + return qemuMonitorTestAddHandler(test, + qemuMonitorTestProcessCommandVerbatim, + data, qemuMonitorTestHandlerDataFree); + + error: + qemuMonitorTestHandlerDataFree(data); + return -1; +} + + +static int qemuMonitorTestProcessGuestAgentSync(qemuMonitorTestPtr test, qemuMonitorTestItemPtr item ATTRIBUTE_UNUSED, const char *cmdstr) diff --git a/tests/qemumonitortestutils.h b/tests/qemumonitortestutils.h index 87c11af..147996a 100644 --- a/tests/qemumonitortestutils.h +++ b/tests/qemumonitortestutils.h @@ -54,6 +54,11 @@ int qemuMonitorTestAddItem(qemuMonitorTestPtr test, const char *command_name, const char *response); +int qemuMonitorTestAddItemVerbatim(qemuMonitorTestPtr test, + const char *command, + const char *cmderr, + const char *response); + int qemuMonitorTestAddAgentSyncResponse(qemuMonitorTestPtr test); int qemuMonitorTestAddItemParams(qemuMonitorTestPtr test, -- 2.10.2

Similar to the existing qemuMonitorTestNewFromFile the *Full version will allow to check both commands and supply responses for a better monitor testing. --- tests/qemumonitortestutils.c | 119 +++++++++++++++++++++++++++++++++++++++++++ tests/qemumonitortestutils.h | 3 ++ 2 files changed, 122 insertions(+) diff --git a/tests/qemumonitortestutils.c b/tests/qemumonitortestutils.c index 50042f9..80136dc 100644 --- a/tests/qemumonitortestutils.c +++ b/tests/qemumonitortestutils.c @@ -1278,6 +1278,125 @@ qemuMonitorTestNewFromFile(const char *fileName, } +static int +qemuMonitorTestFullAddItem(qemuMonitorTestPtr test, + const char *filename, + const char *command, + const char *response, + size_t line) +{ + char *cmderr; + int ret; + + if (virAsprintf(&cmderr, "wrong expected command in %s:%zu: ", + filename, line) < 0) + return -1; + + ret = qemuMonitorTestAddItemVerbatim(test, command, cmderr, response); + + VIR_FREE(cmderr); + return ret; +} + + +/** + * qemuMonitorTestNewFromFileFull: + * @fileName: File name to load monitor replies from + * @driver: qemu driver object + * @vm: domain object (may be null if it's not needed by the test) + * + * Create a JSON test monitor simulator object and fill it with expected command + * sequence and replies specified in @fileName. + * + * The file contains a sequence of JSON commands and reply objects separated by + * empty lines. A command is followed by a reply. The QMP greeting is added + * automatically. + * + * Returns the monitor object on success; NULL on error. + */ +qemuMonitorTestPtr +qemuMonitorTestNewFromFileFull(const char *fileName, + virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ + qemuMonitorTestPtr ret = NULL; + char *jsonstr = NULL; + char *tmp; + size_t line = 0; + + char *command = NULL; + char *response = NULL; + size_t commandln = 0; + char *cmderr = NULL; + + if (virTestLoadFile(fileName, &jsonstr) < 0) + return NULL; + + if (!(ret = qemuMonitorTestNew(true, driver->xmlopt, vm, driver, NULL))) + goto cleanup; + + tmp = jsonstr; + command = tmp; + while ((tmp = strchr(tmp, '\n'))) { + bool eof = !tmp[1]; + line++; + + if (*(tmp + 1) != '\n') { + *tmp = ' '; + tmp++; + } else { + /* Cut off a single reply. */ + *(tmp + 1) = '\0'; + + if (response) { + if (qemuMonitorTestFullAddItem(ret, fileName, command, + response, commandln) < 0) + goto error; + command = NULL; + response = NULL; + } + + if (!eof) { + /* Move the @tmp and @singleReply. */ + tmp += 2; + + if (!command) { + commandln = line; + command = tmp; + } else { + response = tmp; + } + } + } + + if (eof) + break; + } + + if (command) { + if (!response) { + virReportError(VIR_ERR_INTERNAL_ERROR, "missing response for command " + "on line '%zu' in '%s'", commandln, fileName); + goto error; + } + + if (qemuMonitorTestFullAddItem(ret, fileName, command, + response, commandln) < 0) + goto error; + } + + cleanup: + VIR_FREE(cmderr); + VIR_FREE(jsonstr); + return ret; + + error: + qemuMonitorTestFree(ret); + ret = NULL; + goto cleanup; +} + + qemuMonitorTestPtr qemuMonitorTestNewAgent(virDomainXMLOptionPtr xmlopt) { diff --git a/tests/qemumonitortestutils.h b/tests/qemumonitortestutils.h index 147996a..8b19b37 100644 --- a/tests/qemumonitortestutils.h +++ b/tests/qemumonitortestutils.h @@ -85,6 +85,9 @@ qemuMonitorTestPtr qemuMonitorTestNew(bool json, qemuMonitorTestPtr qemuMonitorTestNewFromFile(const char *fileName, virDomainXMLOptionPtr xmlopt, bool simple); +qemuMonitorTestPtr qemuMonitorTestNewFromFileFull(const char *fileName, + virQEMUDriverPtr driver, + virDomainObjPtr vm); qemuMonitorTestPtr qemuMonitorTestNewAgent(virDomainXMLOptionPtr xmlopt); -- 2.10.2

The cpu hotplug operation is rather complex so the testing code needs to provide quite lot of data and monitor conversations to successfully test it. The code mainly tests the selection of cpus according to the target count request. --- tests/qemuhotplugtest.c | 189 +++++++++ .../qemuhotplugtestcpus/x86-modern-bulk-domain.xml | 21 + .../x86-modern-bulk-monitor.json | 471 +++++++++++++++++++++ .../x86-modern-bulk-result-conf.xml | 40 ++ .../x86-modern-bulk-result-live.xml | 48 +++ 5 files changed, 769 insertions(+) create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index f0a8453..32aaf57 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -347,11 +347,187 @@ testQemuHotplug(const void *data) return ((ret < 0 && fail) || (!ret && !fail)) ? 0 : -1; } + +struct testQemuHotplugCpuData { + char *file_xml_dom; + char *file_xml_res_live; + char *file_xml_res_conf; + char *file_json_monitor; + + char *xml_dom; + + virDomainObjPtr vm; + qemuMonitorTestPtr mon; + bool modern; +}; + + +static void +testQemuHotplugCpuDataFree(struct testQemuHotplugCpuData *data) +{ + if (!data) + return; + + VIR_FREE(data->file_xml_dom); + VIR_FREE(data->file_xml_res_live); + VIR_FREE(data->file_xml_res_conf); + VIR_FREE(data->file_json_monitor); + + VIR_FREE(data->xml_dom); + + virObjectUnref(data->vm); + qemuMonitorTestFree(data->mon); +} + + +static struct testQemuHotplugCpuData * +testQemuHotplugCpuPrepare(const char *test, + bool modern) +{ + qemuDomainObjPrivatePtr priv = NULL; + virCapsPtr caps = NULL; + char *prefix = NULL; + struct testQemuHotplugCpuData *data = NULL; + + if (virAsprintf(&prefix, "%s/qemuhotplugtestcpus/%s", abs_srcdir, test) < 0) + return NULL; + + if (VIR_ALLOC(data) < 0) + goto error; + + data->modern = modern; + + if (virAsprintf(&data->file_xml_dom, "%s-domain.xml", prefix) < 0 || + virAsprintf(&data->file_xml_res_live, "%s-result-live.xml", prefix) < 0 || + virAsprintf(&data->file_xml_res_conf, "%s-result-conf.xml", prefix) < 0 || + virAsprintf(&data->file_json_monitor, "%s-monitor.json", prefix) < 0) + goto error; + + if (virTestLoadFile(data->file_xml_dom, &data->xml_dom) < 0) + goto error; + + if (qemuHotplugCreateObjects(driver.xmlopt, &data->vm, data->xml_dom, true, + "cpu-hotplug-test-domain") < 0) + goto error; + + if (!(caps = virQEMUDriverGetCapabilities(&driver, false))) + goto error; + + /* create vm->newDef */ + data->vm->persistent = true; + if (virDomainObjSetDefTransient(caps, driver.xmlopt, data->vm) < 0) + goto error; + + priv = data->vm->privateData; + + if (data->modern) + virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_QUERY_HOTPLUGGABLE_CPUS); + + if (!(data->mon = qemuMonitorTestNewFromFileFull(data->file_json_monitor, + &driver, data->vm))) + goto error; + + priv->mon = qemuMonitorTestGetMonitor(data->mon); + priv->monJSON = true; + virObjectUnlock(priv->mon); + + if (qemuDomainRefreshVcpuInfo(&driver, data->vm, 0, false) < 0) + goto error; + + return data; + + error: + virObjectUnref(caps); + testQemuHotplugCpuDataFree(data); + VIR_FREE(prefix); + return NULL; +} + + +static int +testQemuHotplugCpuFinalize(struct testQemuHotplugCpuData *data) +{ + int ret = -1; + char *activeXML = NULL; + char *configXML = NULL; + + if (data->file_xml_res_live) { + if (!(activeXML = virDomainDefFormat(data->vm->def, driver.caps, + VIR_DOMAIN_DEF_FORMAT_SECURE))) + goto cleanup; + + if (virTestCompareToFile(activeXML, data->file_xml_res_live) < 0) + goto cleanup; + } + + if (data->file_xml_res_conf) { + if (!(configXML = virDomainDefFormat(data->vm->newDef, driver.caps, + VIR_DOMAIN_DEF_FORMAT_SECURE | + VIR_DOMAIN_DEF_FORMAT_INACTIVE))) + goto cleanup; + + if (virTestCompareToFile(configXML, data->file_xml_res_conf) < 0) + goto cleanup; + } + + ret = 0; + + cleanup: + VIR_FREE(activeXML); + VIR_FREE(configXML); + return ret; +} + + +struct testQemuHotplugCpuParams { + const char *test; + int newcpus; + bool modern; + bool fail; +}; + + +static int +testQemuHotplugCpuGroup(const void *opaque) +{ + const struct testQemuHotplugCpuParams *params = opaque; + struct testQemuHotplugCpuData *data = NULL; + int ret = -1; + int rc; + + if (!(data = testQemuHotplugCpuPrepare(params->test, params->modern))) + return -1; + + rc = qemuDomainSetVcpusInternal(&driver, data->vm, data->vm->def, + data->vm->newDef, params->newcpus, + params->modern); + + if (params->fail) { + if (rc == 0) + fprintf(stderr, "cpu test %s should have failed\n", params->test); + else + ret = 0; + + goto cleanup; + } else { + if (rc < 0) + goto cleanup; + } + + ret = testQemuHotplugCpuFinalize(data); + + cleanup: + testQemuHotplugCpuDataFree(data); + return ret; +} + + static int mymain(void) { int ret = 0; struct qemuHotplugTestData data = {0}; + struct testQemuHotplugCpuParams cpudata; #if !WITH_YAJL fputs("libvirt not compiled with yajl, skipping this test\n", stderr); @@ -584,6 +760,19 @@ mymain(void) "device_del", QMP_OK, "object-del", QMP_OK); +#define DO_TEST_CPU_GROUP(prefix, vcpus, modernhp, expectfail) \ + do { \ + cpudata.test = prefix; \ + cpudata.newcpus = vcpus; \ + cpudata.modern = modernhp; \ + cpudata.fail = expectfail; \ + if (virTestRun("hotplug vcpus group " prefix, \ + testQemuHotplugCpuGroup, &cpudata) < 0) \ + ret = -1; \ + } while (0) + + DO_TEST_CPU_GROUP("x86-modern-bulk", 7, true, false); + qemuTestDriverFree(&driver); return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml b/tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml new file mode 100644 index 0000000..1c2a5b1 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-modern-bulk-domain.xml @@ -0,0 +1,21 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='5'>8</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets="4" cores="2" threads="1"/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json b/tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json new file mode 100644 index 0000000..4dcb6a2 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-modern-bulk-monitor.json @@ -0,0 +1,471 @@ +{"execute":"query-hotpluggable-cpus","id":"libvirt-1"} + +{ + "return": [ + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[5]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[4]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[3]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[2]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[0]", + "type": "qemu64-x86_64-cpu" + } + ], + "id": "libvirt-23" +} + +{"execute":"query-cpus","id":"libvirt-2"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + } + ], + "id": "libvirt-22" +} + +{ + "execute": "device_add", + "arguments": { + "driver": "qemu64-x86_64-cpu", + "id": "vcpu5", + "socket-id": 1, + "core-id": 0, + "thread-id": 1 + }, + "id": "libvirt-3" +} + +{"return": {}} + +{"execute":"query-hotpluggable-cpus","id":"libvirt-4"} + +{ + "return": [ + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/peripheral/vcpu5", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[5]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[4]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[3]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[2]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[0]", + "type": "qemu64-x86_64-cpu" + } + ], + "id": "libvirt-23" +} + +{"execute":"query-cpus","id":"libvirt-5"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + }, + { + "arch": "x86", + "current": false, + "CPU": 5, + "qom_path": "/machine/peripheral/vcpu5", + "pc": -2130415978, + "halted": true, + "thread_id": 518297 + } + ], + "id": "libvirt-22" +} + +{ + "execute": "device_add", + "arguments": { + "driver": "qemu64-x86_64-cpu", + "id": "vcpu6", + "socket-id": 1, + "core-id": 1, + "thread-id": 0 + }, + "id": "libvirt-6" +} + +{"return": {}} + +{"execute":"query-hotpluggable-cpus","id":"libvirt-7"} + +{ + "return": [ + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/peripheral/vcpu6", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/peripheral/vcpu5", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 1 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[5]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[4]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 1, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[3]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 1, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[2]", + "type": "qemu64-x86_64-cpu" + }, + { + "props": { + "core-id": 0, + "thread-id": 0, + "socket-id": 0 + }, + "vcpus-count": 1, + "qom-path": "/machine/unattached/device[0]", + "type": "qemu64-x86_64-cpu" + } + ], + "id": "libvirt-23" +} + +{"execute":"query-cpus","id":"libvirt-8"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + }, + { + "arch": "x86", + "current": false, + "CPU": 5, + "qom_path": "/machine/peripheral/vcpu5", + "pc": -2130415978, + "halted": true, + "thread_id": 518297 + }, + { + "arch": "x86", + "current": false, + "CPU": 6, + "qom_path": "/machine/peripheral/vcpu6", + "pc": -2130415978, + "halted": true, + "thread_id": 518298 + } + ], + "id": "libvirt-22" +} diff --git a/tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml b/tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml new file mode 100644 index 0000000..5c1d18b --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-modern-bulk-result-conf.xml @@ -0,0 +1,40 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='7'>8</vcpu> + <vcpus> + <vcpu id='0' enabled='yes' hotpluggable='no'/> + <vcpu id='1' enabled='yes' hotpluggable='no'/> + <vcpu id='2' enabled='yes' hotpluggable='no'/> + <vcpu id='3' enabled='yes' hotpluggable='no'/> + <vcpu id='4' enabled='yes' hotpluggable='no'/> + <vcpu id='5' enabled='yes' hotpluggable='yes'/> + <vcpu id='6' enabled='yes' hotpluggable='yes'/> + <vcpu id='7' enabled='no' hotpluggable='yes'/> + </vcpus> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='4' cores='2' threads='1'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml b/tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml new file mode 100644 index 0000000..50fd9ea --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-modern-bulk-result-live.xml @@ -0,0 +1,48 @@ +<domain type='qemu' id='7'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='7'>8</vcpu> + <vcpus> + <vcpu id='0' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='1' enabled='yes' hotpluggable='no' order='2'/> + <vcpu id='2' enabled='yes' hotpluggable='no' order='3'/> + <vcpu id='3' enabled='yes' hotpluggable='no' order='4'/> + <vcpu id='4' enabled='yes' hotpluggable='no' order='5'/> + <vcpu id='5' enabled='yes' hotpluggable='yes' order='6'/> + <vcpu id='6' enabled='yes' hotpluggable='yes' order='7'/> + <vcpu id='7' enabled='no' hotpluggable='yes'/> + </vcpus> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='4' cores='2' threads='1'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'> + <alias name='pci'/> + </controller> + <input type='mouse' bus='ps2'> + <alias name='input0'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input1'/> + </input> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> -- 2.10.2

Test that the old approach generates correct commands. --- tests/qemuhotplugtest.c | 1 + tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml | 21 +++ .../qemuhotplugtestcpus/x86-old-bulk-monitor.json | 193 +++++++++++++++++++++ .../x86-old-bulk-result-conf.xml | 30 ++++ .../x86-old-bulk-result-live.xml | 38 ++++ 5 files changed, 283 insertions(+) create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index 32aaf57..f0817eb 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -772,6 +772,7 @@ mymain(void) } while (0) DO_TEST_CPU_GROUP("x86-modern-bulk", 7, true, false); + DO_TEST_CPU_GROUP("x86-old-bulk", 7, false, false); qemuTestDriverFree(&driver); return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml b/tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml new file mode 100644 index 0000000..1c2a5b1 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-old-bulk-domain.xml @@ -0,0 +1,21 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='5'>8</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets="4" cores="2" threads="1"/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json b/tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json new file mode 100644 index 0000000..6caf8cc --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-old-bulk-monitor.json @@ -0,0 +1,193 @@ +{"execute":"query-cpus","id":"libvirt-1"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + } + ], + "id": "libvirt-22" +} + +{"execute":"cpu-add","arguments":{"id":5},"id":"libvirt-2"} + +{"return": {}} + +{"execute":"query-cpus","id":"libvirt-3"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + }, + { + "arch": "x86", + "current": false, + "CPU": 5, + "qom_path": "/machine/peripheral/vcpu5", + "pc": -2130415978, + "halted": true, + "thread_id": 518297 + } + ], + "id": "libvirt-22" +} + +{"execute":"cpu-add","arguments":{"id":6},"id":"libvirt-4"} + +{"return": {}} + +{"execute":"query-cpus","id":"libvirt-5"} + +{ + "return": [ + { + "arch": "x86", + "current": true, + "CPU": 0, + "qom_path": "/machine/unattached/device[0]", + "pc": -2130415978, + "halted": true, + "thread_id": 518291 + }, + { + "arch": "x86", + "current": false, + "CPU": 1, + "qom_path": "/machine/unattached/device[2]", + "pc": -2130415978, + "halted": true, + "thread_id": 518292 + }, + { + "arch": "x86", + "current": false, + "CPU": 2, + "qom_path": "/machine/unattached/device[3]", + "pc": -2130415978, + "halted": true, + "thread_id": 518294 + }, + { + "arch": "x86", + "current": false, + "CPU": 3, + "qom_path": "/machine/unattached/device[4]", + "pc": -2130415978, + "halted": true, + "thread_id": 518295 + }, + { + "arch": "x86", + "current": false, + "CPU": 4, + "qom_path": "/machine/unattached/device[5]", + "pc": -2130415978, + "halted": true, + "thread_id": 518296 + }, + { + "arch": "x86", + "current": false, + "CPU": 5, + "qom_path": "/machine/peripheral/vcpu5", + "pc": -2130415978, + "halted": true, + "thread_id": 518297 + }, + { + "arch": "x86", + "current": false, + "CPU": 6, + "qom_path": "/machine/peripheral/vcpu6", + "pc": -2130415978, + "halted": true, + "thread_id": 518298 + } + ], + "id": "libvirt-22" +} diff --git a/tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml b/tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml new file mode 100644 index 0000000..1ccbf2b --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-old-bulk-result-conf.xml @@ -0,0 +1,30 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='7'>8</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='4' cores='2' threads='1'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml b/tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml new file mode 100644 index 0000000..5286267 --- /dev/null +++ b/tests/qemuhotplugtestcpus/x86-old-bulk-result-live.xml @@ -0,0 +1,38 @@ +<domain type='qemu' id='7'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='7'>8</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='4' cores='2' threads='1'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'> + <alias name='pci'/> + </controller> + <input type='mouse' bus='ps2'> + <alias name='input0'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input1'/> + </input> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> -- 2.10.2

Add a positive test and few negative tests. --- tests/qemuhotplugtest.c | 4 + tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml | 20 + tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json | 593 +++++++++++++++++++++ .../qemuhotplugtestcpus/ppc64-bulk-result-conf.xml | 64 +++ .../qemuhotplugtestcpus/ppc64-bulk-result-live.xml | 72 +++ 5 files changed, 753 insertions(+) create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml create mode 100644 tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index f0817eb..44a5e69 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -773,6 +773,10 @@ mymain(void) DO_TEST_CPU_GROUP("x86-modern-bulk", 7, true, false); DO_TEST_CPU_GROUP("x86-old-bulk", 7, false, false); + DO_TEST_CPU_GROUP("ppc64-bulk", 24, true, false); + DO_TEST_CPU_GROUP("ppc64-bulk", 15, true, true); + DO_TEST_CPU_GROUP("ppc64-bulk", 23, true, true); + DO_TEST_CPU_GROUP("ppc64-bulk", 25, true, true); qemuTestDriverFree(&driver); return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml b/tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml new file mode 100644 index 0000000..eb04e42 --- /dev/null +++ b/tests/qemuhotplugtestcpus/ppc64-bulk-domain.xml @@ -0,0 +1,20 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='8'>32</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets="1" cores="4" threads="8"/> + </cpu> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json b/tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json new file mode 100644 index 0000000..c139426 --- /dev/null +++ b/tests/qemuhotplugtestcpus/ppc64-bulk-monitor.json @@ -0,0 +1,593 @@ +{"execute":"query-hotpluggable-cpus","id":"libvirt-1"} + +{ + "return": [ + { + "props": { + "core-id": 24 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 16 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 8 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 0 + }, + "vcpus-count": 8, + "qom-path": "/machine/unattached/device[1]", + "type": "host-spapr-cpu-core" + } + ], + "id": "libvirt-15" +} + +{"execute":"query-cpus","id":"libvirt-2"} + +{ + "return": [ + { + "arch": "ppc", + "current": true, + "CPU": 0, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[0]", + "halted": false, + "thread_id": 21925 + }, + { + "arch": "ppc", + "current": false, + "CPU": 1, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[1]", + "halted": false, + "thread_id": 21926 + }, + { + "arch": "ppc", + "current": false, + "CPU": 2, + "nip": -4611686018422360608, + "qom_path": "/machine/unattached/device[1]/thread[2]", + "halted": false, + "thread_id": 21927 + }, + { + "arch": "ppc", + "current": false, + "CPU": 3, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[3]", + "halted": false, + "thread_id": 21928 + }, + { + "arch": "ppc", + "current": false, + "CPU": 4, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[4]", + "halted": false, + "thread_id": 21930 + }, + { + "arch": "ppc", + "current": false, + "CPU": 5, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[5]", + "halted": false, + "thread_id": 21931 + }, + { + "arch": "ppc", + "current": false, + "CPU": 6, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[6]", + "halted": false, + "thread_id": 21932 + }, + { + "arch": "ppc", + "current": false, + "CPU": 7, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[7]", + "halted": false, + "thread_id": 21933 + } + ], + "id": "libvirt-12" +} + +{ + "execute": "device_add", + "arguments": { + "driver": "host-spapr-cpu-core", + "id": "vcpu8", + "core-id": 8 + }, + "id": "libvirt-3" +} + +{"return": {}} + +{"execute":"query-hotpluggable-cpus","id":"libvirt-4"} + +{ + "return": [ + { + "props": { + "core-id": 24 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 16 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 8 + }, + "vcpus-count": 8, + "qom-path": "/machine/peripheral/vcpu1", + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 0 + }, + "vcpus-count": 8, + "qom-path": "/machine/unattached/device[1]", + "type": "host-spapr-cpu-core" + } + ], + "id": "libvirt-15" +} + +{"execute":"query-cpus","id":"libvirt-5"} + +{ + "return": [ + { + "arch": "ppc", + "current": true, + "CPU": 0, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[0]", + "halted": false, + "thread_id": 21925 + }, + { + "arch": "ppc", + "current": false, + "CPU": 1, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[1]", + "halted": false, + "thread_id": 21926 + }, + { + "arch": "ppc", + "current": false, + "CPU": 2, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[2]", + "halted": false, + "thread_id": 21927 + }, + { + "arch": "ppc", + "current": false, + "CPU": 3, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[3]", + "halted": false, + "thread_id": 21928 + }, + { + "arch": "ppc", + "current": false, + "CPU": 4, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[4]", + "halted": false, + "thread_id": 21930 + }, + { + "arch": "ppc", + "current": false, + "CPU": 5, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[5]", + "halted": false, + "thread_id": 21931 + }, + { + "arch": "ppc", + "current": false, + "CPU": 6, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[6]", + "halted": false, + "thread_id": 21932 + }, + { + "arch": "ppc", + "current": false, + "CPU": 7, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[7]", + "halted": false, + "thread_id": 21933 + }, + { + "arch": "ppc", + "current": false, + "CPU": 8, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[0]", + "halted": false, + "thread_id": 22131 + }, + { + "arch": "ppc", + "current": false, + "CPU": 9, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[1]", + "halted": false, + "thread_id": 22132 + }, + { + "arch": "ppc", + "current": false, + "CPU": 10, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[2]", + "halted": false, + "thread_id": 22133 + }, + { + "arch": "ppc", + "current": false, + "CPU": 11, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[3]", + "halted": false, + "thread_id": 22134 + }, + { + "arch": "ppc", + "current": false, + "CPU": 12, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[4]", + "halted": false, + "thread_id": 22135 + }, + { + "arch": "ppc", + "current": false, + "CPU": 13, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[5]", + "halted": false, + "thread_id": 22136 + }, + { + "arch": "ppc", + "current": false, + "CPU": 14, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[6]", + "halted": false, + "thread_id": 22137 + }, + { + "arch": "ppc", + "current": false, + "CPU": 15, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[7]", + "halted": false, + "thread_id": 22138 + } + ], + "id": "libvirt-14" +} + +{ + "execute": "device_add", + "arguments": { + "driver": "host-spapr-cpu-core", + "id": "vcpu16", + "core-id": 16 + }, + "id": "libvirt-6" +} + +{"return": {}} + +{"execute":"query-hotpluggable-cpus","id":"libvirt-7"} + +{ + "return": [ + { + "props": { + "core-id": 24 + }, + "vcpus-count": 8, + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 16 + }, + "vcpus-count": 8, + "qom-path": "/machine/peripheral/vcpu2", + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 8 + }, + "vcpus-count": 8, + "qom-path": "/machine/peripheral/vcpu1", + "type": "host-spapr-cpu-core" + }, + { + "props": { + "core-id": 0 + }, + "vcpus-count": 8, + "qom-path": "/machine/unattached/device[1]", + "type": "host-spapr-cpu-core" + } + ], + "id": "libvirt-15" +} + +{"execute":"query-cpus","id":"libvirt-8"} + +{ + "return": [ + { + "arch": "ppc", + "current": true, + "CPU": 0, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[0]", + "halted": false, + "thread_id": 21925 + }, + { + "arch": "ppc", + "current": false, + "CPU": 1, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[1]", + "halted": false, + "thread_id": 21926 + }, + { + "arch": "ppc", + "current": false, + "CPU": 2, + "nip": -4611686018422360576, + "qom_path": "/machine/unattached/device[1]/thread[2]", + "halted": false, + "thread_id": 21927 + }, + { + "arch": "ppc", + "current": false, + "CPU": 3, + "nip": -4611686018422360596, + "qom_path": "/machine/unattached/device[1]/thread[3]", + "halted": false, + "thread_id": 21928 + }, + { + "arch": "ppc", + "current": false, + "CPU": 4, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[4]", + "halted": false, + "thread_id": 21930 + }, + { + "arch": "ppc", + "current": false, + "CPU": 5, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[5]", + "halted": false, + "thread_id": 21931 + }, + { + "arch": "ppc", + "current": false, + "CPU": 6, + "nip": -4611686018426772172, + "qom_path": "/machine/unattached/device[1]/thread[6]", + "halted": false, + "thread_id": 21932 + }, + { + "arch": "ppc", + "current": false, + "CPU": 7, + "nip": -4611686018422360596, + "qom_path": "/machine/unattached/device[1]/thread[7]", + "halted": false, + "thread_id": 21933 + }, + { + "arch": "ppc", + "current": false, + "CPU": 8, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[0]", + "halted": false, + "thread_id": 22131 + }, + { + "arch": "ppc", + "current": false, + "CPU": 9, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[1]", + "halted": false, + "thread_id": 22132 + }, + { + "arch": "ppc", + "current": false, + "CPU": 10, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[2]", + "halted": false, + "thread_id": 22133 + }, + { + "arch": "ppc", + "current": false, + "CPU": 11, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[3]", + "halted": false, + "thread_id": 22134 + }, + { + "arch": "ppc", + "current": false, + "CPU": 12, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[4]", + "halted": false, + "thread_id": 22135 + }, + { + "arch": "ppc", + "current": false, + "CPU": 13, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[5]", + "halted": false, + "thread_id": 22136 + }, + { + "arch": "ppc", + "current": false, + "CPU": 14, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[6]", + "halted": false, + "thread_id": 22137 + }, + { + "arch": "ppc", + "current": false, + "CPU": 15, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu1/thread[7]", + "halted": false, + "thread_id": 22138 + }, + { + "arch": "ppc", + "current": false, + "CPU": 16, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[0]", + "halted": false, + "thread_id": 22223 + }, + { + "arch": "ppc", + "current": false, + "CPU": 17, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[1]", + "halted": false, + "thread_id": 22224 + }, + { + "arch": "ppc", + "current": false, + "CPU": 18, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[2]", + "halted": false, + "thread_id": 22225 + }, + { + "arch": "ppc", + "current": false, + "CPU": 19, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[3]", + "halted": false, + "thread_id": 22226 + }, + { + "arch": "ppc", + "current": false, + "CPU": 20, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[4]", + "halted": false, + "thread_id": 22227 + }, + { + "arch": "ppc", + "current": false, + "CPU": 21, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[5]", + "halted": false, + "thread_id": 22228 + }, + { + "arch": "ppc", + "current": false, + "CPU": 22, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[6]", + "halted": false, + "thread_id": 22229 + }, + { + "arch": "ppc", + "current": false, + "CPU": 23, + "nip": -4611686018426772172, + "qom_path": "/machine/peripheral/vcpu2/thread[7]", + "halted": false, + "thread_id": 22230 + } + ], + "id": "libvirt-17" +} diff --git a/tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml b/tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml new file mode 100644 index 0000000..bd792ea --- /dev/null +++ b/tests/qemuhotplugtestcpus/ppc64-bulk-result-conf.xml @@ -0,0 +1,64 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='24'>32</vcpu> + <vcpus> + <vcpu id='0' enabled='yes' hotpluggable='no'/> + <vcpu id='1' enabled='yes' hotpluggable='no'/> + <vcpu id='2' enabled='yes' hotpluggable='no'/> + <vcpu id='3' enabled='yes' hotpluggable='no'/> + <vcpu id='4' enabled='yes' hotpluggable='no'/> + <vcpu id='5' enabled='yes' hotpluggable='no'/> + <vcpu id='6' enabled='yes' hotpluggable='no'/> + <vcpu id='7' enabled='yes' hotpluggable='no'/> + <vcpu id='8' enabled='yes' hotpluggable='yes'/> + <vcpu id='9' enabled='yes' hotpluggable='yes'/> + <vcpu id='10' enabled='yes' hotpluggable='yes'/> + <vcpu id='11' enabled='yes' hotpluggable='yes'/> + <vcpu id='12' enabled='yes' hotpluggable='yes'/> + <vcpu id='13' enabled='yes' hotpluggable='yes'/> + <vcpu id='14' enabled='yes' hotpluggable='yes'/> + <vcpu id='15' enabled='yes' hotpluggable='yes'/> + <vcpu id='16' enabled='yes' hotpluggable='yes'/> + <vcpu id='17' enabled='yes' hotpluggable='yes'/> + <vcpu id='18' enabled='yes' hotpluggable='yes'/> + <vcpu id='19' enabled='yes' hotpluggable='yes'/> + <vcpu id='20' enabled='yes' hotpluggable='yes'/> + <vcpu id='21' enabled='yes' hotpluggable='yes'/> + <vcpu id='22' enabled='yes' hotpluggable='yes'/> + <vcpu id='23' enabled='yes' hotpluggable='yes'/> + <vcpu id='24' enabled='no' hotpluggable='yes'/> + <vcpu id='25' enabled='no' hotpluggable='yes'/> + <vcpu id='26' enabled='no' hotpluggable='yes'/> + <vcpu id='27' enabled='no' hotpluggable='yes'/> + <vcpu id='28' enabled='no' hotpluggable='yes'/> + <vcpu id='29' enabled='no' hotpluggable='yes'/> + <vcpu id='30' enabled='no' hotpluggable='yes'/> + <vcpu id='31' enabled='no' hotpluggable='yes'/> + </vcpus> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='1' cores='4' threads='8'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml b/tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml new file mode 100644 index 0000000..da40fec --- /dev/null +++ b/tests/qemuhotplugtestcpus/ppc64-bulk-result-live.xml @@ -0,0 +1,72 @@ +<domain type='qemu' id='7'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219100</memory> + <currentMemory unit='KiB'>219100</currentMemory> + <vcpu placement='static' current='24'>32</vcpu> + <vcpus> + <vcpu id='0' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='1' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='2' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='3' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='4' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='5' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='6' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='7' enabled='yes' hotpluggable='no' order='1'/> + <vcpu id='8' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='9' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='10' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='11' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='12' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='13' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='14' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='15' enabled='yes' hotpluggable='yes' order='2'/> + <vcpu id='16' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='17' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='18' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='19' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='20' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='21' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='22' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='23' enabled='yes' hotpluggable='yes' order='3'/> + <vcpu id='24' enabled='no' hotpluggable='yes'/> + <vcpu id='25' enabled='no' hotpluggable='yes'/> + <vcpu id='26' enabled='no' hotpluggable='yes'/> + <vcpu id='27' enabled='no' hotpluggable='yes'/> + <vcpu id='28' enabled='no' hotpluggable='yes'/> + <vcpu id='29' enabled='no' hotpluggable='yes'/> + <vcpu id='30' enabled='no' hotpluggable='yes'/> + <vcpu id='31' enabled='no' hotpluggable='yes'/> + </vcpus> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='network'/> + </os> + <cpu> + <topology sockets='1' cores='4' threads='8'/> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <controller type='usb' index='0'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'> + <alias name='pci'/> + </controller> + <input type='mouse' bus='ps2'> + <alias name='input0'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input1'/> + </input> + <memballoon model='virtio'> + <alias name='balloon0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> -- 2.10.2

On Thu, Jan 05, 2017 at 10:52:18 +0100, Peter Krempa wrote:
On Fri, Dec 09, 2016 at 17:08:04 +0100, Peter Krempa wrote:
Add some useful monitor infrastructure to simplify testing and add testing for the cpu hotplug code. The code has some complex logic which was not covered by current test suite.
Ping
Disregard this version. There was a rebase conflict so I posted a new version.
participants (1)
-
Peter Krempa