[libvirt] [PATCH v4 00/37] BaselineHypervisorCPU using QEMU QMP exchanges

Some architectures (S390) depend on QEMU to compute baseline CPU model and expand a models feature set. Interacting with QEMU requires starting the QEMU process and completing one or more query-cpu-model-baseline QMP exchanges with QEMU in addition to a query-cpu-model-expansion QMP exchange to expand all features in the model. See "s390x CPU models: exposing features" patch set on Qemu-devel for discussion of QEMU aspects. This is part of resolution of: https://bugzilla.redhat.com/show_bug.cgi?id=1511999 Version 4 attempts to address all issues from V1,2,3 including making the QEMU process activation for QMP Queries generic (not specific to capabilities) and moving that code from qemu_capabilities to qemu_process. Version 4 greatly expands the number of patches to make the set easier to review. The patches to do hypervisor baseline using QEMU are primarily in qemu_driver.c The patches to make the process code generic (not capabilities specific) are mostly in qemu_process.c Many of the patches are cut / paste of existing code. The patches that change functionality are as modular and minimal as possible to make reviewing easier. I attempted to make the new qemu_process functions consistent with the existing domain activation qemu_process functions. A thread safe library function creates a unique directory under libDir for each QEMU process (for QMP messaging) to decouple processes in terms of sockets and file system footprint. The last patch is based on past discussion of QEMU cpu expansion only returning migratable features except for one x86 case where non-migratable features are explicitly requested. The patch records that features are migratable based on QEMU only returning migratable features. The main result is the CPU xml for S390 CPU's contains the same migratability info the X86 currently does. The testcases were updated to reflect the change. Every patch should compile independently if applied in sequence. Thanks, Chris Chris Venteicher (37): qemu_monitor: Introduce qemuMonitorCPUModelInfoNew qemu_monitor: Introduce qemuMonitorCPUModelInfo / JSON conversion qemu_capabilities: Introduce virQEMuCapsMigratablePropsDiff qemu_monitor: qemuMonitorGetCPUModelExpansion inputs and outputs CPUModelInfo qemu_process: Move process code from qemu_capabilities to qemu_process qemu_process: Use qemuProcess prefix qemu_process: Limit qemuProcessNew to const input strings qemu_process: Refer to proc not cmd in process code qemu_process: Use consistent name for stop process function qemu_capabilities: Stop QEMU process before freeing qemu_process: Use qemuProcess struct for a single process qemu_process: Persist stderr in qemuProcess struct qemu_capabilities: Detect caps probe failure by checking monitor ptr qemu_process: Introduce qemuProcessStartQmp qemu_process: Add debug message in qemuProcessLaunchQmp qemu_process: Collect monitor code in single function qemu_process: Store libDir in qemuProcess struct qemu_process: Setup paths within qemuProcessInitQmp qemu_process: Stop retaining Qemu Monitor config in qemuProcess qemu_process: Don't open monitor if process failed qemu_process: Cleanup qemuProcess alloc function qemu_process: Cleanup qemuProcessStopQmp function qemu_process: Catch process free before process stop qemu_monitor: Make monitor callbacks optional qemu_process: Enter QMP command mode when starting QEMU Process qemu_process: Use unique directories for QMP processes qemu_process: Stop locking QMP process monitor immediately qemu_capabilities: Introduce CPUModelInfo to virCPUDef function qemu_capabilities: Introduce virCPUDef to CPUModelInfo function qemu_monitor: Support query-cpu-model-baseline QMP command qemu_driver: Consolidate code to baseline using libvirt qemu_driver: Decouple code for baseline using libvirt qemu_driver: Identify using libvirt as a distinct way to compute baseline qemu_driver: Support baseline calculation using QEMU qemu_driver: Support feature expansion via QEMU when baselining cpu qemu_driver: Remove unsupported props in expanded hypervisor baseline output qemu_monitor: Default props to migratable when expanding cpu model src/qemu/qemu_capabilities.c | 567 ++++++++---------- src/qemu/qemu_capabilities.h | 4 + src/qemu/qemu_driver.c | 219 ++++++- src/qemu/qemu_monitor.c | 184 +++++- src/qemu/qemu_monitor.h | 29 +- src/qemu/qemu_monitor_json.c | 226 +++++-- src/qemu/qemu_monitor_json.h | 12 +- src/qemu/qemu_process.c | 359 +++++++++++ src/qemu/qemu_process.h | 37 ++ tests/cputest.c | 11 +- .../caps_2.10.0.s390x.xml | 60 +- .../caps_2.11.0.s390x.xml | 58 +- .../caps_2.12.0.s390x.xml | 56 +- .../qemucapabilitiesdata/caps_2.8.0.s390x.xml | 32 +- .../qemucapabilitiesdata/caps_2.9.0.s390x.xml | 34 +- .../qemucapabilitiesdata/caps_3.0.0.s390x.xml | 64 +- tests/qemucapabilitiestest.c | 7 + 17 files changed, 1388 insertions(+), 571 deletions(-) -- 2.17.1

A helper function allocates an initializes model name in CPU Model Info structs. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_monitor.c | 32 +++++++++++++++++++++++++++----- src/qemu/qemu_monitor.h | 2 ++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 2ca5af3297..eb9dca05f8 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -3024,7 +3024,7 @@ virQEMUCapsLoadHostCPUModelInfo(virQEMUCapsPtr qemuCaps, goto cleanup; } - if (VIR_ALLOC(hostCPU) < 0) + if (!(hostCPU = qemuMonitorCPUModelInfoNew(NULL))) goto cleanup; if (!(hostCPU->name = virXMLPropString(hostCPUNode, "model"))) { diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 7f7013e115..45a4568fcc 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3670,6 +3670,31 @@ qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon, } +qemuMonitorCPUModelInfoPtr +qemuMonitorCPUModelInfoNew(const char *name) +{ + qemuMonitorCPUModelInfoPtr ret = NULL; + qemuMonitorCPUModelInfoPtr model; + + if (VIR_ALLOC(model) < 0) + return NULL; + + model->name = NULL; + model->nprops = 0; + model->props = NULL; + model->migratability = false; + + if (VIR_STRDUP(model->name, name) < 0) + goto cleanup; + + VIR_STEAL_PTR(ret, model); + + cleanup: + qemuMonitorCPUModelInfoFree(model); + return ret; +} + + void qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info) { @@ -3693,18 +3718,15 @@ qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info) qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig) { - qemuMonitorCPUModelInfoPtr copy; + qemuMonitorCPUModelInfoPtr copy = NULL; size_t i; - if (VIR_ALLOC(copy) < 0) + if (!orig || !(copy = qemuMonitorCPUModelInfoNew(orig->name))) goto error; if (VIR_ALLOC_N(copy->props, orig->nprops) < 0) goto error; - if (VIR_STRDUP(copy->name, orig->name) < 0) - goto error; - copy->migratability = orig->migratability; copy->nprops = orig->nprops; diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 48b142a4f4..d87b5a4ec0 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1042,6 +1042,8 @@ int qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon, void qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info); +qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoNew(const char *name); + qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig); -- 2.17.1

Conversion functions are used convert CPUModelInfo structs into QMP JSON and the reverse. QMP JSON is of form: {"model": {"name": "IvyBridge", "props": {}}} qemuMonitorCPUModelInfoBoolPropAdd is used to add boolean properties to CPUModelInfo struct. qemuMonitorJSONGetCPUModelExpansion makes full use of conversions and propAdd in prep to support input of full cpu model in future. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_monitor.c | 24 ++++++ src/qemu/qemu_monitor.h | 5 ++ src/qemu/qemu_monitor_json.c | 154 +++++++++++++++++++++++++---------- 3 files changed, 138 insertions(+), 45 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 45a4568fcc..801c072eff 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3764,6 +3764,30 @@ qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig) } +int +qemuMonitorCPUModelInfoBoolPropAdd(qemuMonitorCPUModelInfoPtr model, + const char *prop_name, + bool prop_value) +{ + int ret = -1; + qemuMonitorCPUProperty prop; + prop.type = QEMU_MONITOR_CPU_PROPERTY_BOOLEAN; + prop.value.boolean = prop_value; + + if (VIR_STRDUP(prop.name, prop_name) < 0) + goto cleanup; + + if (VIR_APPEND_ELEMENT(model->props, model->nprops, prop) < 0) + goto cleanup; + + ret = 0; + + cleanup: + VIR_FREE(prop.name); + return ret; +} + + int qemuMonitorGetCommands(qemuMonitorPtr mon, char ***commands) diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index d87b5a4ec0..0a09590ed1 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1047,6 +1047,11 @@ qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoNew(const char *name); qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig); +int qemuMonitorCPUModelInfoBoolPropAdd(qemuMonitorCPUModelInfoPtr model, + const char *prop_name, + bool prop_value) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int qemuMonitorGetCommands(qemuMonitorPtr mon, char ***commands); int qemuMonitorGetEvents(qemuMonitorPtr mon, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 3de298c9e2..f20e9e9379 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5505,6 +5505,101 @@ qemuMonitorJSONParseCPUModelProperty(const char *key, return 0; } + +/* model_json: {"name": "z13-base", "props": {}} + */ +static virJSONValuePtr +qemuMonitorJSONBuildCPUModelInfoToJSON(qemuMonitorCPUModelInfoPtr model) +{ + virJSONValuePtr cpu_props = NULL; + virJSONValuePtr model_json = NULL; + size_t i; + + if (!model) + goto cleanup; + + if (model->nprops > 0 && !(cpu_props = virJSONValueNewObject())) + goto cleanup; + + for (i = 0; i < model->nprops; i++) { + qemuMonitorCPUPropertyPtr prop = &(model->props[i]); + + switch (prop->type) { + case QEMU_MONITOR_CPU_PROPERTY_BOOLEAN: + if (virJSONValueObjectAppendBoolean(cpu_props, prop->name, + prop->value.boolean) < 0) + goto cleanup; + break; + + case QEMU_MONITOR_CPU_PROPERTY_STRING: + if (virJSONValueObjectAppendString(cpu_props, prop->name, + prop->value.string) < 0) + goto cleanup; + break; + + case QEMU_MONITOR_CPU_PROPERTY_NUMBER: + if (virJSONValueObjectAppendNumberLong(cpu_props, prop->name, + prop->value.number) < 0) + goto cleanup; + break; + + case QEMU_MONITOR_CPU_PROPERTY_LAST: + default: + virReportEnumRangeError(qemuMonitorCPUPropertyPtr, prop->type); + goto cleanup; + } + } + + ignore_value(virJSONValueObjectCreate(&model_json, "s:name", model->name, + "A:props", &cpu_props, NULL)); + + cleanup: + virJSONValueFree(cpu_props); + return model_json; +} + + +/* model_json: {"name": "IvyBridge", "props": {}} + */ +static qemuMonitorCPUModelInfoPtr +qemuMonitorJSONBuildCPUModelInfoFromJSON(virJSONValuePtr cpu_model) +{ + virJSONValuePtr cpu_props; + qemuMonitorCPUModelInfoPtr model = NULL; + qemuMonitorCPUModelInfoPtr ret = NULL; + char const *cpu_name; + + if (!(cpu_name = virJSONValueObjectGetString(cpu_model, "name"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Parsed JSON reply missing 'name'")); + goto cleanup; + } + + if (VIR_ALLOC(model) < 0) + goto cleanup; + + if (VIR_STRDUP(model->name, cpu_name) < 0) + goto cleanup; + + if ((cpu_props = virJSONValueObjectGetObject(cpu_model, "props"))) { + if (VIR_ALLOC_N(model->props, + virJSONValueObjectKeysNumber(cpu_props)) < 0) + goto cleanup; + + if (virJSONValueObjectForeachKeyValue(cpu_props, + qemuMonitorJSONParseCPUModelProperty, + model) < 0) + goto cleanup; + } + + VIR_STEAL_PTR(ret, model); + + cleanup: + qemuMonitorCPUModelInfoFree(model); + + return ret; +} + int qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelExpansionType type, @@ -5513,32 +5608,25 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelInfoPtr *model_info) { int ret = -1; - virJSONValuePtr model = NULL; - virJSONValuePtr props = NULL; + virJSONValuePtr json_model_in = NULL; virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; virJSONValuePtr data; virJSONValuePtr cpu_model; - virJSONValuePtr cpu_props; - qemuMonitorCPUModelInfoPtr machine_model = NULL; - char const *cpu_name; + qemuMonitorCPUModelInfoPtr model_in = NULL; const char *typeStr = ""; *model_info = NULL; - if (!(model = virJSONValueNewObject())) + if (!(model_in = qemuMonitorCPUModelInfoNew(model_name))) goto cleanup; - if (virJSONValueObjectAppendString(model, "name", model_name) < 0) + if (!migratable && + qemuMonitorCPUModelInfoBoolPropAdd(model_in, "migratable", false) < 0) goto cleanup; - if (!migratable) { - if (!(props = virJSONValueNewObject()) || - virJSONValueObjectAppendBoolean(props, "migratable", false) < 0 || - virJSONValueObjectAppend(model, "props", props) < 0) - goto cleanup; - props = NULL; - } + if (!(json_model_in = qemuMonitorJSONBuildCPUModelInfoToJSON(model_in))) + goto cleanup; retry: switch (type) { @@ -5554,7 +5642,7 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, if (!(cmd = qemuMonitorJSONMakeCommand("query-cpu-model-expansion", "s:type", typeStr, - "a:model", &model, + "a:model", &json_model_in, NULL))) goto cleanup; @@ -5585,7 +5673,9 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, * on the result of the initial "static" expansion. */ if (type == QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC_FULL) { - if (!(model = virJSONValueCopy(cpu_model))) + virJSONValueFree(json_model_in); + + if (!(json_model_in = virJSONValueCopy(cpu_model))) goto cleanup; virJSONValueFree(cmd); @@ -5594,42 +5684,16 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, goto retry; } - if (!(cpu_name = virJSONValueObjectGetString(cpu_model, "name"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("query-cpu-model-expansion reply data was missing 'name'")); - goto cleanup; - } - - if (!(cpu_props = virJSONValueObjectGetObject(cpu_model, "props"))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("query-cpu-model-expansion reply data was missing 'props'")); - goto cleanup; - } - - if (VIR_ALLOC(machine_model) < 0) - goto cleanup; - - if (VIR_STRDUP(machine_model->name, cpu_name) < 0) - goto cleanup; - - if (VIR_ALLOC_N(machine_model->props, virJSONValueObjectKeysNumber(cpu_props)) < 0) - goto cleanup; - - if (virJSONValueObjectForeachKeyValue(cpu_props, - qemuMonitorJSONParseCPUModelProperty, - machine_model) < 0) + if (!(*model_info = qemuMonitorJSONBuildCPUModelInfoFromJSON(cpu_model))) goto cleanup; ret = 0; - *model_info = machine_model; - machine_model = NULL; cleanup: - qemuMonitorCPUModelInfoFree(machine_model); + qemuMonitorCPUModelInfoFree(model_in); virJSONValueFree(cmd); virJSONValueFree(reply); - virJSONValueFree(model); - virJSONValueFree(props); + virJSONValueFree(json_model_in); return ret; } -- 2.17.1

Create an augmented CPUModelInfo identifying which props are/aren't migratable based on a diff between migratable and non-migratable inputs. This patch pulls existing logic out of virQEMUCapsProbeQMPHostCPU and wraps the existing logic in a standalone function hopefully simplifying both functions and making the inputs and outputs clearer. The patch also sets cpuData->info = NULL to make sure bad data does not remain in failure cases. Q) Can the right people quickly determine if they should review this? Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 131 ++++++++++++++++++++++++----------- 1 file changed, 92 insertions(+), 39 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index eb9dca05f8..c8e9b8f65d 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2355,14 +2355,91 @@ virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps, } +/* virQEMUCapsMigratablePropsDiff + * @migratable: input where all migratable props have value true + * and non-migratable and unsupported props have value false + * + * @nonMigratable: input where all migratable & non-migratable props + * have value true and unsupported props have value false + * + * @augmented: output including all props listed in @migratable but + * both migratable & non-migratable props have value true, + * unsupported props have value false, + * and prop->migratable is set to VIR_TRISTATE_BOOL_{YES/NO} + * for each supported prop + * + * Differences in expanded CPUModelInfo inputs @migratable and @nonMigratable are + * used to create output @augmented where individual props have prop->migratable + * set to indicate if prop is or isn't migratable. + */ +static int +virQEMUCapsMigratablePropsDiff(qemuMonitorCPUModelInfoPtr migratable, + qemuMonitorCPUModelInfoPtr nonMigratable, + qemuMonitorCPUModelInfoPtr *augmented) +{ + int ret = -1; + qemuMonitorCPUModelInfoPtr tmp; + qemuMonitorCPUPropertyPtr prop; + qemuMonitorCPUPropertyPtr mProp; + qemuMonitorCPUPropertyPtr nmProp; + virHashTablePtr hash = NULL; + size_t i; + + *augmented = NULL; + + if (!(tmp = qemuMonitorCPUModelInfoCopy(migratable))) + goto cleanup; + + if (!nonMigratable) + goto done; + + if (!(hash = virHashCreate(0, NULL))) + goto cleanup; + + for (i = 0; i < tmp->nprops; i++) { + prop = tmp->props + i; + + if (virHashAddEntry(hash, prop->name, prop) < 0) + goto cleanup; + } + + for (i = 0; i < nonMigratable->nprops; i++) { + nmProp = nonMigratable->props + i; + + if (!(mProp = virHashLookup(hash, nmProp->name)) || + mProp->type != QEMU_MONITOR_CPU_PROPERTY_BOOLEAN || + mProp->type != nmProp->type) + continue; /* In non-migratable list but not in migratable list */ + + if (mProp->value.boolean) { + mProp->migratable = VIR_TRISTATE_BOOL_YES; + } else if (nmProp->value.boolean) { + mProp->value.boolean = true; + mProp->migratable = VIR_TRISTATE_BOOL_NO; + } + } + + tmp->migratability = true; + + done: + VIR_STEAL_PTR(*augmented, tmp); + ret = 0; + + cleanup: + qemuMonitorCPUModelInfoFree(tmp); + virHashFree(hash); + return ret; +} + + static int virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps, qemuMonitorPtr mon, bool tcg) { - qemuMonitorCPUModelInfoPtr modelInfo = NULL; + qemuMonitorCPUModelInfoPtr migratable = NULL; qemuMonitorCPUModelInfoPtr nonMigratable = NULL; - virHashTablePtr hash = NULL; + qemuMonitorCPUModelInfoPtr augmented = NULL; const char *model; qemuMonitorCPUModelExpansionType type; virDomainVirtType virtType; @@ -2381,6 +2458,7 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps, } cpuData = virQEMUCapsGetHostCPUData(qemuCaps, virtType); + cpuData->info = NULL; /* Some x86_64 features defined in cpu_map.xml use spelling which differ * from the one preferred by QEMU. Static expansion would give us only the @@ -2392,54 +2470,29 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps, else type = QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC; - if (qemuMonitorGetCPUModelExpansion(mon, type, model, true, &modelInfo) < 0) + if (qemuMonitorGetCPUModelExpansion(mon, type, model, true, &migratable) < 0) + goto cleanup; + + if (!migratable) { + ret = 0; /* Qemu can't expand the model name, exit without error */ goto cleanup; + } /* Try to check migratability of each feature. */ - if (modelInfo && - qemuMonitorGetCPUModelExpansion(mon, type, model, false, + if (qemuMonitorGetCPUModelExpansion(mon, type, model, false, &nonMigratable) < 0) goto cleanup; - if (nonMigratable) { - qemuMonitorCPUPropertyPtr prop; - qemuMonitorCPUPropertyPtr nmProp; - size_t i; - - if (!(hash = virHashCreate(0, NULL))) - goto cleanup; - - for (i = 0; i < modelInfo->nprops; i++) { - prop = modelInfo->props + i; - if (virHashAddEntry(hash, prop->name, prop) < 0) - goto cleanup; - } - - for (i = 0; i < nonMigratable->nprops; i++) { - nmProp = nonMigratable->props + i; - if (!(prop = virHashLookup(hash, nmProp->name)) || - prop->type != QEMU_MONITOR_CPU_PROPERTY_BOOLEAN || - prop->type != nmProp->type) - continue; - - if (prop->value.boolean) { - prop->migratable = VIR_TRISTATE_BOOL_YES; - } else if (nmProp->value.boolean) { - prop->value.boolean = true; - prop->migratable = VIR_TRISTATE_BOOL_NO; - } - } - - modelInfo->migratability = true; - } + if (virQEMUCapsMigratablePropsDiff(migratable, nonMigratable, &augmented) < 0) + goto cleanup; - VIR_STEAL_PTR(cpuData->info, modelInfo); + VIR_STEAL_PTR(cpuData->info, augmented); ret = 0; cleanup: - virHashFree(hash); + qemuMonitorCPUModelInfoFree(migratable); qemuMonitorCPUModelInfoFree(nonMigratable); - qemuMonitorCPUModelInfoFree(modelInfo); + qemuMonitorCPUModelInfoFree(augmented); return ret; } -- 2.17.1

A Full CPUModelInfo structure with props is sent to QEMU for expansion. virQEMUCapsProbeQMPHostCPU migratability logic partitioned into new function for clarity. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 8 +++++--- src/qemu/qemu_monitor.c | 31 ++++++++++++++++++++++++++----- src/qemu/qemu_monitor.h | 5 +++-- src/qemu/qemu_monitor_json.c | 16 +++++++++++----- src/qemu/qemu_monitor_json.h | 6 +++--- tests/cputest.c | 11 ++++++++--- 6 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c8e9b8f65d..b2bb2347fd 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2437,6 +2437,7 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps, qemuMonitorPtr mon, bool tcg) { + qemuMonitorCPUModelInfoPtr input; qemuMonitorCPUModelInfoPtr migratable = NULL; qemuMonitorCPUModelInfoPtr nonMigratable = NULL; qemuMonitorCPUModelInfoPtr augmented = NULL; @@ -2470,7 +2471,8 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps, else type = QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC; - if (qemuMonitorGetCPUModelExpansion(mon, type, model, true, &migratable) < 0) + if (!(input = qemuMonitorCPUModelInfoNew(model)) || + qemuMonitorGetCPUModelExpansion(mon, type, true, input, &migratable) < 0) goto cleanup; if (!migratable) { @@ -2479,8 +2481,7 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps, } /* Try to check migratability of each feature. */ - if (qemuMonitorGetCPUModelExpansion(mon, type, model, false, - &nonMigratable) < 0) + if (qemuMonitorGetCPUModelExpansion(mon, type, false, input, &nonMigratable) < 0) goto cleanup; if (virQEMUCapsMigratablePropsDiff(migratable, nonMigratable, &augmented) < 0) @@ -2490,6 +2491,7 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps, ret = 0; cleanup: + qemuMonitorCPUModelInfoFree(input); qemuMonitorCPUModelInfoFree(migratable); qemuMonitorCPUModelInfoFree(nonMigratable); qemuMonitorCPUModelInfoFree(augmented); diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 801c072eff..4c0c2decf7 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3653,20 +3653,41 @@ qemuMonitorCPUDefInfoFree(qemuMonitorCPUDefInfoPtr cpu) } +/** + * qemuMonitorGetCPUModelExpansion: + * @mon: + * @type: qemuMonitorCPUModelExpansionType + * @migratable: Prompt QEMU to include non-migratable props for X86 models if false + * @input: Input model + * @expansion: Expanded output model (or NULL if QEMU rejects model or request) + * + * Re-represent @input CPU props using a new CPUModelInfo constructed + * by naming a STATIC or DYNAMIC model cooresponding to a set of properties and + * a FULL or PARTIAL (only deltas from model) property list. + * + * if @type == QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC + * construct @expansion using STATIC model name and a PARTIAL (delta) property list + * + * if @type == QEMU_MONITOR_CPU_MODEL_EXPANSION_FULL + * construct @expansion using DYNAMIC model name and a FULL property list + * + * if @type == QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC_FULL + * construct @expansion using STATIC model name and a FULL property list + */ int qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelExpansionType type, - const char *model_name, bool migratable, - qemuMonitorCPUModelInfoPtr *model_info) + qemuMonitorCPUModelInfoPtr input, + qemuMonitorCPUModelInfoPtr *expansion + ) { VIR_DEBUG("type=%d model_name=%s migratable=%d", - type, model_name, migratable); + type, input->name, migratable); QEMU_CHECK_MONITOR(mon); - return qemuMonitorJSONGetCPUModelExpansion(mon, type, model_name, - migratable, model_info); + return qemuMonitorJSONGetCPUModelExpansion(mon, type, migratable, input, expansion); } diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 0a09590ed1..d3efd37099 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1036,9 +1036,10 @@ typedef enum { int qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelExpansionType type, - const char *model_name, bool migratable, - qemuMonitorCPUModelInfoPtr *model_info); + qemuMonitorCPUModelInfoPtr input, + qemuMonitorCPUModelInfoPtr *expansion) + ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5); void qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index f20e9e9379..2eabfdac70 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5600,12 +5600,13 @@ qemuMonitorJSONBuildCPUModelInfoFromJSON(virJSONValuePtr cpu_model) return ret; } + int qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelExpansionType type, - const char *model_name, bool migratable, - qemuMonitorCPUModelInfoPtr *model_info) + qemuMonitorCPUModelInfoPtr input, + qemuMonitorCPUModelInfoPtr *expansion) { int ret = -1; virJSONValuePtr json_model_in = NULL; @@ -5613,12 +5614,13 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, virJSONValuePtr reply = NULL; virJSONValuePtr data; virJSONValuePtr cpu_model; + qemuMonitorCPUModelInfoPtr expanded_model = NULL; qemuMonitorCPUModelInfoPtr model_in = NULL; const char *typeStr = ""; - *model_info = NULL; + *expansion = NULL; - if (!(model_in = qemuMonitorCPUModelInfoNew(model_name))) + if (!(model_in = qemuMonitorCPUModelInfoCopy(input))) goto cleanup; if (!migratable && @@ -5684,13 +5686,17 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, goto retry; } - if (!(*model_info = qemuMonitorJSONBuildCPUModelInfoFromJSON(cpu_model))) + if (!(expanded_model = qemuMonitorJSONBuildCPUModelInfoFromJSON(cpu_model))) goto cleanup; + VIR_STEAL_PTR(*expansion, expanded_model); ret = 0; cleanup: + VIR_FREE(expanded_model); /* Free structure but not reused contents */ qemuMonitorCPUModelInfoFree(model_in); + qemuMonitorCPUModelInfoFree(expanded_model); + virJSONValueFree(cmd); virJSONValueFree(reply); virJSONValueFree(json_model_in); diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index da267b15b0..2d5679094e 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -367,10 +367,10 @@ int qemuMonitorJSONGetCPUDefinitions(qemuMonitorPtr mon, int qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelExpansionType type, - const char *model_name, bool migratable, - qemuMonitorCPUModelInfoPtr *model_info) - ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(5); + qemuMonitorCPUModelInfoPtr input, + qemuMonitorCPUModelInfoPtr *expansion) + ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5); int qemuMonitorJSONGetCommands(qemuMonitorPtr mon, char ***commands) diff --git a/tests/cputest.c b/tests/cputest.c index 339119c63f..c438a8d09e 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -483,6 +483,7 @@ cpuTestMakeQEMUCaps(const struct data *data) virQEMUCapsPtr qemuCaps = NULL; qemuMonitorTestPtr testMon = NULL; qemuMonitorCPUModelInfoPtr model = NULL; + qemuMonitorCPUModelInfoPtr expansion = NULL; char *json = NULL; if (virAsprintf(&json, "%s/cputestdata/%s-cpuid-%s.json", @@ -492,9 +493,12 @@ cpuTestMakeQEMUCaps(const struct data *data) if (!(testMon = qemuMonitorTestNewFromFile(json, driver.xmlopt, true))) goto error; + if (!(model = qemuMonitorCPUModelInfoNew("host"))) + goto cleanup; + if (qemuMonitorGetCPUModelExpansion(qemuMonitorTestGetMonitor(testMon), QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC, - "host", true, &model) < 0) + true, model, &expansion) < 0) goto error; if (!(qemuCaps = virQEMUCapsNew())) @@ -506,8 +510,8 @@ cpuTestMakeQEMUCaps(const struct data *data) virQEMUCapsSet(qemuCaps, QEMU_CAPS_QUERY_CPU_DEFINITIONS); virQEMUCapsSetArch(qemuCaps, data->arch); - virQEMUCapsSetCPUModelInfo(qemuCaps, VIR_DOMAIN_VIRT_KVM, model); - model = NULL; + virQEMUCapsSetCPUModelInfo(qemuCaps, VIR_DOMAIN_VIRT_KVM, expansion); + expansion = NULL; if (virQEMUCapsProbeQMPCPUDefinitions(qemuCaps, qemuMonitorTestGetMonitor(testMon), @@ -516,6 +520,7 @@ cpuTestMakeQEMUCaps(const struct data *data) cleanup: qemuMonitorCPUModelInfoFree(model); + qemuMonitorCPUModelInfoFree(expansion); qemuMonitorTestFree(testMon); VIR_FREE(json); -- 2.17.1

Qemu process code in qemu_capabilities.c is moved to qemu_process.c in order to make the code usable outside the original capabilities usecases. This process code activates and manages Qemu processes without establishing a guest domain. This patch is a straight cut/paste move between files. Following patches modify the process code making it more generic and consistent with qemu_process. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 218 +---------------------------------- src/qemu/qemu_process.c | 201 ++++++++++++++++++++++++++++++++ src/qemu/qemu_process.h | 29 +++++ 3 files changed, 231 insertions(+), 217 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index b2bb2347fd..d5e63aca5c 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -47,6 +47,7 @@ #define __QEMU_CAPSPRIV_H_ALLOW__ #include "qemu_capspriv.h" #include "qemu_qapi.h" +#include "qemu_process.h" #include <fcntl.h> #include <sys/stat.h> @@ -3972,18 +3973,6 @@ virQEMUCapsIsValid(void *data, } -static void virQEMUCapsMonitorNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED, - virDomainObjPtr vm ATTRIBUTE_UNUSED, - void *opaque ATTRIBUTE_UNUSED) -{ -} - -static qemuMonitorCallbacks callbacks = { - .eofNotify = virQEMUCapsMonitorNotify, - .errorNotify = virQEMUCapsMonitorNotify, -}; - - /** * virQEMUCapsInitQMPArch: * @qemuCaps: QEMU capabilities @@ -4278,211 +4267,6 @@ virQEMUCapsInitQMPMonitorTCG(virQEMUCapsPtr qemuCaps ATTRIBUTE_UNUSED, } -typedef struct _virQEMUCapsInitQMPCommand virQEMUCapsInitQMPCommand; -typedef virQEMUCapsInitQMPCommand *virQEMUCapsInitQMPCommandPtr; -struct _virQEMUCapsInitQMPCommand { - char *binary; - uid_t runUid; - gid_t runGid; - char **qmperr; - char *monarg; - char *monpath; - char *pidfile; - virCommandPtr cmd; - qemuMonitorPtr mon; - virDomainChrSourceDef config; - pid_t pid; - virDomainObjPtr vm; -}; - - -static void -virQEMUCapsInitQMPCommandAbort(virQEMUCapsInitQMPCommandPtr cmd) -{ - if (cmd->mon) - virObjectUnlock(cmd->mon); - qemuMonitorClose(cmd->mon); - cmd->mon = NULL; - - virCommandAbort(cmd->cmd); - virCommandFree(cmd->cmd); - cmd->cmd = NULL; - - if (cmd->monpath) - unlink(cmd->monpath); - - virDomainObjEndAPI(&cmd->vm); - - if (cmd->pid != 0) { - char ebuf[1024]; - - VIR_DEBUG("Killing QMP caps process %lld", (long long)cmd->pid); - if (virProcessKill(cmd->pid, SIGKILL) < 0 && errno != ESRCH) - VIR_ERROR(_("Failed to kill process %lld: %s"), - (long long)cmd->pid, - virStrerror(errno, ebuf, sizeof(ebuf))); - - VIR_FREE(*cmd->qmperr); - } - if (cmd->pidfile) - unlink(cmd->pidfile); - cmd->pid = 0; -} - - -static void -virQEMUCapsInitQMPCommandFree(virQEMUCapsInitQMPCommandPtr cmd) -{ - if (!cmd) - return; - - virQEMUCapsInitQMPCommandAbort(cmd); - VIR_FREE(cmd->binary); - VIR_FREE(cmd->monpath); - VIR_FREE(cmd->monarg); - VIR_FREE(cmd->pidfile); - VIR_FREE(cmd); -} - - -static virQEMUCapsInitQMPCommandPtr -virQEMUCapsInitQMPCommandNew(char *binary, - const char *libDir, - uid_t runUid, - gid_t runGid, - char **qmperr) -{ - virQEMUCapsInitQMPCommandPtr cmd = NULL; - - if (VIR_ALLOC(cmd) < 0) - goto error; - - if (VIR_STRDUP(cmd->binary, binary) < 0) - goto error; - - cmd->runUid = runUid; - cmd->runGid = runGid; - cmd->qmperr = qmperr; - - /* the ".sock" sufix is important to avoid a possible clash with a qemu - * domain called "capabilities" - */ - if (virAsprintf(&cmd->monpath, "%s/%s", libDir, - "capabilities.monitor.sock") < 0) - goto error; - if (virAsprintf(&cmd->monarg, "unix:%s,server,nowait", cmd->monpath) < 0) - goto error; - - /* ".pidfile" suffix is used rather than ".pid" to avoid a possible clash - * with a qemu domain called "capabilities" - * Normally we'd use runDir for pid files, but because we're using - * -daemonize we need QEMU to be allowed to create them, rather - * than libvirtd. So we're using libDir which QEMU can write to - */ - if (virAsprintf(&cmd->pidfile, "%s/%s", libDir, "capabilities.pidfile") < 0) - goto error; - - virPidFileForceCleanupPath(cmd->pidfile); - - cmd->config.type = VIR_DOMAIN_CHR_TYPE_UNIX; - cmd->config.data.nix.path = cmd->monpath; - cmd->config.data.nix.listen = false; - - return cmd; - - error: - virQEMUCapsInitQMPCommandFree(cmd); - return NULL; -} - - -/* Returns -1 on fatal error, - * 0 on success, - * 1 when probing QEMU failed - */ -static int -virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd, - bool forceTCG) -{ - virDomainXMLOptionPtr xmlopt = NULL; - const char *machine; - int status = 0; - int ret = -1; - - if (forceTCG) - machine = "none,accel=tcg"; - else - machine = "none,accel=kvm:tcg"; - - VIR_DEBUG("Try to probe capabilities of '%s' via QMP, machine %s", - cmd->binary, machine); - - /* - * We explicitly need to use -daemonize here, rather than - * virCommandDaemonize, because we need to synchronize - * with QEMU creating its monitor socket API. Using - * daemonize guarantees control won't return to libvirt - * until the socket is present. - */ - cmd->cmd = virCommandNewArgList(cmd->binary, - "-S", - "-no-user-config", - "-nodefaults", - "-nographic", - "-machine", machine, - "-qmp", cmd->monarg, - "-pidfile", cmd->pidfile, - "-daemonize", - NULL); - virCommandAddEnvPassCommon(cmd->cmd); - virCommandClearCaps(cmd->cmd); - virCommandSetGID(cmd->cmd, cmd->runGid); - virCommandSetUID(cmd->cmd, cmd->runUid); - - virCommandSetErrorBuffer(cmd->cmd, cmd->qmperr); - - /* Log, but otherwise ignore, non-zero status. */ - if (virCommandRun(cmd->cmd, &status) < 0) - goto cleanup; - - if (status != 0) { - VIR_DEBUG("QEMU %s exited with status %d: %s", - cmd->binary, status, *cmd->qmperr); - goto ignore; - } - - if (virPidFileReadPath(cmd->pidfile, &cmd->pid) < 0) { - VIR_DEBUG("Failed to read pidfile %s", cmd->pidfile); - goto ignore; - } - - if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) || - !(cmd->vm = virDomainObjNew(xmlopt))) - goto cleanup; - - cmd->vm->pid = cmd->pid; - - if (!(cmd->mon = qemuMonitorOpen(cmd->vm, &cmd->config, true, true, - 0, &callbacks, NULL))) - goto ignore; - - virObjectLock(cmd->mon); - - ret = 0; - - cleanup: - if (!cmd->mon) - virQEMUCapsInitQMPCommandAbort(cmd); - virObjectUnref(xmlopt); - - return ret; - - ignore: - ret = 1; - goto cleanup; -} - - static int virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, const char *libDir, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 9cf971808c..62886fd910 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8061,3 +8061,204 @@ qemuProcessReconnectAll(virQEMUDriverPtr driver) struct qemuProcessReconnectData data = {.driver = driver}; virDomainObjListForEach(driver->domains, qemuProcessReconnectHelper, &data); } + + +static void virQEMUCapsMonitorNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED, + void *opaque ATTRIBUTE_UNUSED) +{ +} + +static qemuMonitorCallbacks callbacks = { + .eofNotify = virQEMUCapsMonitorNotify, + .errorNotify = virQEMUCapsMonitorNotify, +}; + + + + +void +virQEMUCapsInitQMPCommandFree(virQEMUCapsInitQMPCommandPtr cmd) +{ + if (!cmd) + return; + + virQEMUCapsInitQMPCommandAbort(cmd); + VIR_FREE(cmd->binary); + VIR_FREE(cmd->monpath); + VIR_FREE(cmd->monarg); + VIR_FREE(cmd->pidfile); + VIR_FREE(cmd); +} + + +virQEMUCapsInitQMPCommandPtr +virQEMUCapsInitQMPCommandNew(char *binary, + const char *libDir, + uid_t runUid, + gid_t runGid, + char **qmperr) +{ + virQEMUCapsInitQMPCommandPtr cmd = NULL; + + if (VIR_ALLOC(cmd) < 0) + goto error; + + if (VIR_STRDUP(cmd->binary, binary) < 0) + goto error; + + cmd->runUid = runUid; + cmd->runGid = runGid; + cmd->qmperr = qmperr; + + /* the ".sock" sufix is important to avoid a possible clash with a qemu + * domain called "capabilities" + */ + if (virAsprintf(&cmd->monpath, "%s/%s", libDir, + "capabilities.monitor.sock") < 0) + goto error; + if (virAsprintf(&cmd->monarg, "unix:%s,server,nowait", cmd->monpath) < 0) + goto error; + + /* ".pidfile" suffix is used rather than ".pid" to avoid a possible clash + * with a qemu domain called "capabilities" + * Normally we'd use runDir for pid files, but because we're using + * -daemonize we need QEMU to be allowed to create them, rather + * than libvirtd. So we're using libDir which QEMU can write to + */ + if (virAsprintf(&cmd->pidfile, "%s/%s", libDir, "capabilities.pidfile") < 0) + goto error; + + virPidFileForceCleanupPath(cmd->pidfile); + + cmd->config.type = VIR_DOMAIN_CHR_TYPE_UNIX; + cmd->config.data.nix.path = cmd->monpath; + cmd->config.data.nix.listen = false; + + return cmd; + + error: + virQEMUCapsInitQMPCommandFree(cmd); + return NULL; +} + + +/* Returns -1 on fatal error, + * 0 on success, + * 1 when probing QEMU failed + */ +int +virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd, + bool forceTCG) +{ + virDomainXMLOptionPtr xmlopt = NULL; + const char *machine; + int status = 0; + int ret = -1; + + if (forceTCG) + machine = "none,accel=tcg"; + else + machine = "none,accel=kvm:tcg"; + + VIR_DEBUG("Try to probe capabilities of '%s' via QMP, machine %s", + cmd->binary, machine); + + /* + * We explicitly need to use -daemonize here, rather than + * virCommandDaemonize, because we need to synchronize + * with QEMU creating its monitor socket API. Using + * daemonize guarantees control won't return to libvirt + * until the socket is present. + */ + cmd->cmd = virCommandNewArgList(cmd->binary, + "-S", + "-no-user-config", + "-nodefaults", + "-nographic", + "-machine", machine, + "-qmp", cmd->monarg, + "-pidfile", cmd->pidfile, + "-daemonize", + NULL); + virCommandAddEnvPassCommon(cmd->cmd); + virCommandClearCaps(cmd->cmd); + virCommandSetGID(cmd->cmd, cmd->runGid); + virCommandSetUID(cmd->cmd, cmd->runUid); + + virCommandSetErrorBuffer(cmd->cmd, cmd->qmperr); + + /* Log, but otherwise ignore, non-zero status. */ + if (virCommandRun(cmd->cmd, &status) < 0) + goto cleanup; + + if (status != 0) { + VIR_DEBUG("QEMU %s exited with status %d: %s", + cmd->binary, status, *cmd->qmperr); + goto ignore; + } + + if (virPidFileReadPath(cmd->pidfile, &cmd->pid) < 0) { + VIR_DEBUG("Failed to read pidfile %s", cmd->pidfile); + goto ignore; + } + + if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) || + !(cmd->vm = virDomainObjNew(xmlopt))) + goto cleanup; + + cmd->vm->pid = cmd->pid; + + if (!(cmd->mon = qemuMonitorOpen(cmd->vm, &cmd->config, true, true, + 0, &callbacks, NULL))) + goto ignore; + + virObjectLock(cmd->mon); + + ret = 0; + + cleanup: + if (!cmd->mon) + virQEMUCapsInitQMPCommandAbort(cmd); + virObjectUnref(xmlopt); + + return ret; + + ignore: + ret = 1; + goto cleanup; +} + + +void +virQEMUCapsInitQMPCommandAbort(virQEMUCapsInitQMPCommandPtr cmd) +{ + if (cmd->mon) + virObjectUnlock(cmd->mon); + qemuMonitorClose(cmd->mon); + cmd->mon = NULL; + + virCommandAbort(cmd->cmd); + virCommandFree(cmd->cmd); + cmd->cmd = NULL; + + if (cmd->monpath) + unlink(cmd->monpath); + + virDomainObjEndAPI(&cmd->vm); + + if (cmd->pid != 0) { + char ebuf[1024]; + + VIR_DEBUG("Killing QMP caps process %lld", (long long)cmd->pid); + if (virProcessKill(cmd->pid, SIGKILL) < 0 && errno != ESRCH) + VIR_ERROR(_("Failed to kill process %lld: %s"), + (long long)cmd->pid, + virStrerror(errno, ebuf, sizeof(ebuf))); + + VIR_FREE(*cmd->qmperr); + } + if (cmd->pidfile) + unlink(cmd->pidfile); + cmd->pid = 0; +} diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 2037467c94..4ba3988e3d 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -214,4 +214,33 @@ int qemuProcessStartManagedPRDaemon(virDomainObjPtr vm); void qemuProcessKillManagedPRDaemon(virDomainObjPtr vm); +typedef struct _virQEMUCapsInitQMPCommand virQEMUCapsInitQMPCommand; +typedef virQEMUCapsInitQMPCommand *virQEMUCapsInitQMPCommandPtr; +struct _virQEMUCapsInitQMPCommand { + char *binary; + uid_t runUid; + gid_t runGid; + char **qmperr; + char *monarg; + char *monpath; + char *pidfile; + virCommandPtr cmd; + qemuMonitorPtr mon; + virDomainChrSourceDef config; + pid_t pid; + virDomainObjPtr vm; +}; + +virQEMUCapsInitQMPCommandPtr virQEMUCapsInitQMPCommandNew(char *binary, + const char *libDir, + uid_t runUid, + gid_t runGid, + char **qmperr); + +void virQEMUCapsInitQMPCommandFree(virQEMUCapsInitQMPCommandPtr cmd); + +int virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd, bool forceTCG); + +void virQEMUCapsInitQMPCommandAbort(virQEMUCapsInitQMPCommandPtr cmd); + #endif /* __QEMU_PROCESS_H__ */ -- 2.17.1

s/virQEMUCapsInitQMPCommand/qemuProcess/ No functionality change. Use appropriate prefix in moved code. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 14 +++++++------- src/qemu/qemu_process.c | 28 ++++++++++++++-------------- src/qemu/qemu_process.h | 22 +++++++++++----------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index d5e63aca5c..6f4d9139bf 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4274,15 +4274,15 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, gid_t runGid, char **qmperr) { - virQEMUCapsInitQMPCommandPtr cmd = NULL; + qemuProcessPtr cmd = NULL; int ret = -1; int rc; - if (!(cmd = virQEMUCapsInitQMPCommandNew(qemuCaps->binary, libDir, - runUid, runGid, qmperr))) + if (!(proc = qemuProcessNew(qemuCaps->binary, libDir, + runUid, runGid, qmperr))) goto cleanup; - if ((rc = virQEMUCapsInitQMPCommandRun(cmd, false)) != 0) { + if ((rc = qemuProcessRun(cmd, false)) != 0) { if (rc == 1) ret = 0; goto cleanup; @@ -4292,8 +4292,8 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, goto cleanup; if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { - virQEMUCapsInitQMPCommandAbort(cmd); - if ((rc = virQEMUCapsInitQMPCommandRun(cmd, true)) != 0) { + qemuProcessAbort(cmd); + if ((rc = qemuProcessRun(cmd, true)) != 0) { if (rc == 1) ret = 0; goto cleanup; @@ -4306,7 +4306,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, ret = 0; cleanup: - virQEMUCapsInitQMPCommandFree(cmd); + qemuProcessFree(cmd); return ret; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 62886fd910..2de1362cbb 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8078,12 +8078,12 @@ static qemuMonitorCallbacks callbacks = { void -virQEMUCapsInitQMPCommandFree(virQEMUCapsInitQMPCommandPtr cmd) +qemuProcessFree(qemuProcessPtr cmd) { if (!cmd) return; - virQEMUCapsInitQMPCommandAbort(cmd); + qemuProcessAbort(cmd); VIR_FREE(cmd->binary); VIR_FREE(cmd->monpath); VIR_FREE(cmd->monarg); @@ -8092,14 +8092,14 @@ virQEMUCapsInitQMPCommandFree(virQEMUCapsInitQMPCommandPtr cmd) } -virQEMUCapsInitQMPCommandPtr -virQEMUCapsInitQMPCommandNew(char *binary, - const char *libDir, - uid_t runUid, - gid_t runGid, - char **qmperr) +qemuProcessPtr +qemuProcessNew(char *binary, + const char *libDir, + uid_t runUid, + gid_t runGid, + char **qmperr) { - virQEMUCapsInitQMPCommandPtr cmd = NULL; + qemuProcessPtr cmd = NULL; if (VIR_ALLOC(cmd) < 0) goto error; @@ -8138,7 +8138,7 @@ virQEMUCapsInitQMPCommandNew(char *binary, return cmd; error: - virQEMUCapsInitQMPCommandFree(cmd); + qemuProcessFree(cmd); return NULL; } @@ -8148,8 +8148,8 @@ virQEMUCapsInitQMPCommandNew(char *binary, * 1 when probing QEMU failed */ int -virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd, - bool forceTCG) +qemuProcessRun(qemuProcessPtr cmd, + bool forceTCG) { virDomainXMLOptionPtr xmlopt = NULL; const char *machine; @@ -8219,7 +8219,7 @@ virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd, cleanup: if (!cmd->mon) - virQEMUCapsInitQMPCommandAbort(cmd); + qemuProcessAbort(cmd); virObjectUnref(xmlopt); return ret; @@ -8231,7 +8231,7 @@ virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd, void -virQEMUCapsInitQMPCommandAbort(virQEMUCapsInitQMPCommandPtr cmd) +qemuProcessAbort(qemuProcessPtr cmd) { if (cmd->mon) virObjectUnlock(cmd->mon); diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 4ba3988e3d..5417cb416f 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -214,9 +214,9 @@ int qemuProcessStartManagedPRDaemon(virDomainObjPtr vm); void qemuProcessKillManagedPRDaemon(virDomainObjPtr vm); -typedef struct _virQEMUCapsInitQMPCommand virQEMUCapsInitQMPCommand; -typedef virQEMUCapsInitQMPCommand *virQEMUCapsInitQMPCommandPtr; -struct _virQEMUCapsInitQMPCommand { +typedef struct _qemuProcess qemuProcess; +typedef qemuProcess *qemuProcessPtr; +struct _qemuProcess { char *binary; uid_t runUid; gid_t runGid; @@ -231,16 +231,16 @@ struct _virQEMUCapsInitQMPCommand { virDomainObjPtr vm; }; -virQEMUCapsInitQMPCommandPtr virQEMUCapsInitQMPCommandNew(char *binary, - const char *libDir, - uid_t runUid, - gid_t runGid, - char **qmperr); +qemuProcessPtr qemuProcessNew(char *binary, + const char *libDir, + uid_t runUid, + gid_t runGid, + char **qmperr); -void virQEMUCapsInitQMPCommandFree(virQEMUCapsInitQMPCommandPtr cmd); +void qemuProcessFree(qemuProcessPtr cmd); -int virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd, bool forceTCG); +int qemuProcessRun(qemuProcessPtr cmd, bool forceTCG); -void virQEMUCapsInitQMPCommandAbort(virQEMUCapsInitQMPCommandPtr cmd); +void qemuProcessAbort(qemuProcessPtr cmd); #endif /* __QEMU_PROCESS_H__ */ -- 2.17.1

Prevent compile errors due to trying to use a const string as a non-const input to qemuProcessNew. No functionality change. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 2 +- src/qemu/qemu_process.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 2de1362cbb..b93b3d6cf4 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8093,7 +8093,7 @@ qemuProcessFree(qemuProcessPtr cmd) qemuProcessPtr -qemuProcessNew(char *binary, +qemuProcessNew(const char *binary, const char *libDir, uid_t runUid, gid_t runGid, diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 5417cb416f..39a2368ce5 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -231,7 +231,7 @@ struct _qemuProcess { virDomainObjPtr vm; }; -qemuProcessPtr qemuProcessNew(char *binary, +qemuProcessPtr qemuProcessNew(const char *binary, const char *libDir, uid_t runUid, gid_t runGid, -- 2.17.1

s/cmd/proc/ in process code imported from qemu_capabilities. No functionality is changed. Process code imported from qemu_capabilities was oriented around starting a process to issue a single QMP command. Future usecases were targeting use a single process for multiple different QMP commands. Patch changes the variable naming to focus on the process not the command. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 14 ++-- src/qemu/qemu_process.c | 140 +++++++++++++++++------------------ src/qemu/qemu_process.h | 6 +- 3 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 6f4d9139bf..cf09002523 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4274,7 +4274,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, gid_t runGid, char **qmperr) { - qemuProcessPtr cmd = NULL; + qemuProcessPtr proc = NULL; int ret = -1; int rc; @@ -4282,31 +4282,31 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, runUid, runGid, qmperr))) goto cleanup; - if ((rc = qemuProcessRun(cmd, false)) != 0) { + if ((rc = qemuProcessRun(proc, false)) != 0) { if (rc == 1) ret = 0; goto cleanup; } - if (virQEMUCapsInitQMPMonitor(qemuCaps, cmd->mon) < 0) + if (virQEMUCapsInitQMPMonitor(qemuCaps, proc->mon) < 0) goto cleanup; if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { - qemuProcessAbort(cmd); - if ((rc = qemuProcessRun(cmd, true)) != 0) { + qemuProcessAbort(proc); + if ((rc = qemuProcessRun(proc, true)) != 0) { if (rc == 1) ret = 0; goto cleanup; } - if (virQEMUCapsInitQMPMonitorTCG(qemuCaps, cmd->mon) < 0) + if (virQEMUCapsInitQMPMonitorTCG(qemuCaps, proc->mon) < 0) goto cleanup; } ret = 0; cleanup: - qemuProcessFree(cmd); + qemuProcessFree(proc); return ret; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index b93b3d6cf4..2d3e8cac7a 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8078,17 +8078,17 @@ static qemuMonitorCallbacks callbacks = { void -qemuProcessFree(qemuProcessPtr cmd) +qemuProcessFree(qemuProcessPtr proc) { - if (!cmd) + if (!proc) return; - qemuProcessAbort(cmd); - VIR_FREE(cmd->binary); - VIR_FREE(cmd->monpath); - VIR_FREE(cmd->monarg); - VIR_FREE(cmd->pidfile); - VIR_FREE(cmd); + qemuProcessAbort(proc); + VIR_FREE(proc->binary); + VIR_FREE(proc->monpath); + VIR_FREE(proc->monarg); + VIR_FREE(proc->pidfile); + VIR_FREE(proc); } @@ -8099,25 +8099,25 @@ qemuProcessNew(const char *binary, gid_t runGid, char **qmperr) { - qemuProcessPtr cmd = NULL; + qemuProcessPtr proc = NULL; - if (VIR_ALLOC(cmd) < 0) + if (VIR_ALLOC(proc) < 0) goto error; - if (VIR_STRDUP(cmd->binary, binary) < 0) + if (VIR_STRDUP(proc->binary, binary) < 0) goto error; - cmd->runUid = runUid; - cmd->runGid = runGid; - cmd->qmperr = qmperr; + proc->runUid = runUid; + proc->runGid = runGid; + proc->qmperr = qmperr; /* the ".sock" sufix is important to avoid a possible clash with a qemu * domain called "capabilities" */ - if (virAsprintf(&cmd->monpath, "%s/%s", libDir, + if (virAsprintf(&proc->monpath, "%s/%s", libDir, "capabilities.monitor.sock") < 0) goto error; - if (virAsprintf(&cmd->monarg, "unix:%s,server,nowait", cmd->monpath) < 0) + if (virAsprintf(&proc->monarg, "unix:%s,server,nowait", proc->monpath) < 0) goto error; /* ".pidfile" suffix is used rather than ".pid" to avoid a possible clash @@ -8126,19 +8126,19 @@ qemuProcessNew(const char *binary, * -daemonize we need QEMU to be allowed to create them, rather * than libvirtd. So we're using libDir which QEMU can write to */ - if (virAsprintf(&cmd->pidfile, "%s/%s", libDir, "capabilities.pidfile") < 0) + if (virAsprintf(&proc->pidfile, "%s/%s", libDir, "capabilities.pidfile") < 0) goto error; - virPidFileForceCleanupPath(cmd->pidfile); + virPidFileForceCleanupPath(proc->pidfile); - cmd->config.type = VIR_DOMAIN_CHR_TYPE_UNIX; - cmd->config.data.nix.path = cmd->monpath; - cmd->config.data.nix.listen = false; + proc->config.type = VIR_DOMAIN_CHR_TYPE_UNIX; + proc->config.data.nix.path = proc->monpath; + proc->config.data.nix.listen = false; - return cmd; + return proc; error: - qemuProcessFree(cmd); + qemuProcessFree(proc); return NULL; } @@ -8148,7 +8148,7 @@ qemuProcessNew(const char *binary, * 1 when probing QEMU failed */ int -qemuProcessRun(qemuProcessPtr cmd, +qemuProcessRun(qemuProcessPtr proc, bool forceTCG) { virDomainXMLOptionPtr xmlopt = NULL; @@ -8162,7 +8162,7 @@ qemuProcessRun(qemuProcessPtr cmd, machine = "none,accel=kvm:tcg"; VIR_DEBUG("Try to probe capabilities of '%s' via QMP, machine %s", - cmd->binary, machine); + proc->binary, machine); /* * We explicitly need to use -daemonize here, rather than @@ -8171,55 +8171,55 @@ qemuProcessRun(qemuProcessPtr cmd, * daemonize guarantees control won't return to libvirt * until the socket is present. */ - cmd->cmd = virCommandNewArgList(cmd->binary, - "-S", - "-no-user-config", - "-nodefaults", - "-nographic", - "-machine", machine, - "-qmp", cmd->monarg, - "-pidfile", cmd->pidfile, - "-daemonize", - NULL); - virCommandAddEnvPassCommon(cmd->cmd); - virCommandClearCaps(cmd->cmd); - virCommandSetGID(cmd->cmd, cmd->runGid); - virCommandSetUID(cmd->cmd, cmd->runUid); - - virCommandSetErrorBuffer(cmd->cmd, cmd->qmperr); + proc->cmd = virCommandNewArgList(proc->binary, + "-S", + "-no-user-config", + "-nodefaults", + "-nographic", + "-machine", machine, + "-qmp", proc->monarg, + "-pidfile", proc->pidfile, + "-daemonize", + NULL); + virCommandAddEnvPassCommon(proc->cmd); + virCommandClearCaps(proc->cmd); + virCommandSetGID(proc->cmd, proc->runGid); + virCommandSetUID(proc->cmd, proc->runUid); + + virCommandSetErrorBuffer(proc->cmd, proc->qmperr); /* Log, but otherwise ignore, non-zero status. */ - if (virCommandRun(cmd->cmd, &status) < 0) + if (virCommandRun(proc->cmd, &status) < 0) goto cleanup; if (status != 0) { VIR_DEBUG("QEMU %s exited with status %d: %s", - cmd->binary, status, *cmd->qmperr); + proc->binary, status, *proc->qmperr); goto ignore; } - if (virPidFileReadPath(cmd->pidfile, &cmd->pid) < 0) { - VIR_DEBUG("Failed to read pidfile %s", cmd->pidfile); + if (virPidFileReadPath(proc->pidfile, &proc->pid) < 0) { + VIR_DEBUG("Failed to read pidfile %s", proc->pidfile); goto ignore; } if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) || - !(cmd->vm = virDomainObjNew(xmlopt))) + !(proc->vm = virDomainObjNew(xmlopt))) goto cleanup; - cmd->vm->pid = cmd->pid; + proc->vm->pid = proc->pid; - if (!(cmd->mon = qemuMonitorOpen(cmd->vm, &cmd->config, true, true, + if (!(proc->mon = qemuMonitorOpen(proc->vm, &proc->config, true, true, 0, &callbacks, NULL))) goto ignore; - virObjectLock(cmd->mon); + virObjectLock(proc->mon); ret = 0; cleanup: - if (!cmd->mon) - qemuProcessAbort(cmd); + if (!proc->mon) + qemuProcessAbort(proc); virObjectUnref(xmlopt); return ret; @@ -8231,34 +8231,34 @@ qemuProcessRun(qemuProcessPtr cmd, void -qemuProcessAbort(qemuProcessPtr cmd) +qemuProcessAbort(qemuProcessPtr proc) { - if (cmd->mon) - virObjectUnlock(cmd->mon); - qemuMonitorClose(cmd->mon); - cmd->mon = NULL; + if (proc->mon) + virObjectUnlock(proc->mon); + qemuMonitorClose(proc->mon); + proc->mon = NULL; - virCommandAbort(cmd->cmd); - virCommandFree(cmd->cmd); - cmd->cmd = NULL; + virCommandAbort(proc->cmd); + virCommandFree(proc->cmd); + proc->cmd = NULL; - if (cmd->monpath) - unlink(cmd->monpath); + if (proc->monpath) + unlink(proc->monpath); - virDomainObjEndAPI(&cmd->vm); + virDomainObjEndAPI(&proc->vm); - if (cmd->pid != 0) { + if (proc->pid != 0) { char ebuf[1024]; - VIR_DEBUG("Killing QMP caps process %lld", (long long)cmd->pid); - if (virProcessKill(cmd->pid, SIGKILL) < 0 && errno != ESRCH) + VIR_DEBUG("Killing QMP caps process %lld", (long long)proc->pid); + if (virProcessKill(proc->pid, SIGKILL) < 0 && errno != ESRCH) VIR_ERROR(_("Failed to kill process %lld: %s"), - (long long)cmd->pid, + (long long)proc->pid, virStrerror(errno, ebuf, sizeof(ebuf))); - VIR_FREE(*cmd->qmperr); + VIR_FREE(*proc->qmperr); } - if (cmd->pidfile) - unlink(cmd->pidfile); - cmd->pid = 0; + if (proc->pidfile) + unlink(proc->pidfile); + proc->pid = 0; } diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 39a2368ce5..161311d007 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -237,10 +237,10 @@ qemuProcessPtr qemuProcessNew(const char *binary, gid_t runGid, char **qmperr); -void qemuProcessFree(qemuProcessPtr cmd); +void qemuProcessFree(qemuProcessPtr proc); -int qemuProcessRun(qemuProcessPtr cmd, bool forceTCG); +int qemuProcessRun(qemuProcessPtr proc, bool forceTCG); -void qemuProcessAbort(qemuProcessPtr cmd); +void qemuProcessAbort(qemuProcessPtr proc); #endif /* __QEMU_PROCESS_H__ */ -- 2.17.1

s/qemuProcessAbort/qemuProcessStopQmp/ applied to change function name used to stop QEMU processes in process code moved from qemu_capabilities. No functionality change. The new name, qemuProcessStopQmp, is consistent with the existing function qemuProcessStop used to stop Domain processes. Qmp is added to the end of qemuProcessStop to differentiate between the Domain and new non-domain version of the functions. qemuProcessStartQmp will be used in a future patch to mirror the qemuProcessStart function with a non-domain equivalent. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 2 +- src/qemu/qemu_process.c | 6 +++--- src/qemu/qemu_process.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index cf09002523..1d83ebdbe0 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4292,7 +4292,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, goto cleanup; if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { - qemuProcessAbort(proc); + qemuProcessStopQmp(proc); if ((rc = qemuProcessRun(proc, true)) != 0) { if (rc == 1) ret = 0; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 2d3e8cac7a..70d73cd457 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8083,7 +8083,7 @@ qemuProcessFree(qemuProcessPtr proc) if (!proc) return; - qemuProcessAbort(proc); + qemuProcessStopQmp(proc); VIR_FREE(proc->binary); VIR_FREE(proc->monpath); VIR_FREE(proc->monarg); @@ -8219,7 +8219,7 @@ qemuProcessRun(qemuProcessPtr proc, cleanup: if (!proc->mon) - qemuProcessAbort(proc); + qemuProcessStopQmp(proc); virObjectUnref(xmlopt); return ret; @@ -8231,7 +8231,7 @@ qemuProcessRun(qemuProcessPtr proc, void -qemuProcessAbort(qemuProcessPtr proc) +qemuProcessStopQmp(qemuProcessPtr proc) { if (proc->mon) virObjectUnlock(proc->mon); diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 161311d007..25343c4592 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -241,6 +241,6 @@ void qemuProcessFree(qemuProcessPtr proc); int qemuProcessRun(qemuProcessPtr proc, bool forceTCG); -void qemuProcessAbort(qemuProcessPtr proc); +void qemuProcessStopQmp(qemuProcessPtr proc); #endif /* __QEMU_PROCESS_H__ */ -- 2.17.1

Follow the convention established in qemu_process of 1) alloc process structure 2) start process 3) use process 4) stop process 5) free process data structure The process data structure persists after the process activation fails or the process dies or is killed so stderr strings can be retrieved until the process data structure is freed. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 1d83ebdbe0..359b6fbb9b 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4306,6 +4306,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, ret = 0; cleanup: + qemuProcessStopQmp(proc); qemuProcessFree(proc); return ret; } -- 2.17.1

In new process code, move from model where qemuProcess struct can be used to activate a series of Qemu processes to model where one qemuProcess struct is used for one and only one Qemu process. The forceTCG parameter (use / don't use KVM) will be passed when the qemuProcess struct is initialized since the qemuProcess struct won't be reused. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 16 ++++++++++++---- src/qemu/qemu_process.c | 11 +++++++---- src/qemu/qemu_process.h | 6 ++++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 359b6fbb9b..99a963912c 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4275,14 +4275,16 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, char **qmperr) { qemuProcessPtr proc = NULL; + qemuProcessPtr proc_kvm = NULL; int ret = -1; int rc; + bool forceTCG = false; if (!(proc = qemuProcessNew(qemuCaps->binary, libDir, - runUid, runGid, qmperr))) + runUid, runGid, qmperr, forceTCG))) goto cleanup; - if ((rc = qemuProcessRun(proc, false)) != 0) { + if ((rc = qemuProcessRun(proc)) != 0) { if (rc == 1) ret = 0; goto cleanup; @@ -4293,13 +4295,17 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { qemuProcessStopQmp(proc); - if ((rc = qemuProcessRun(proc, true)) != 0) { + + forceTCG = true; + proc_kvm = qemuProcessNew(qemuCaps->binary, libDir, runUid, runGid, NULL, forceTCG); + + if ((rc = qemuProcessRun(proc_kvm)) != 0) { if (rc == 1) ret = 0; goto cleanup; } - if (virQEMUCapsInitQMPMonitorTCG(qemuCaps, proc->mon) < 0) + if (virQEMUCapsInitQMPMonitorTCG(qemuCaps, proc_kvm->mon) < 0) goto cleanup; } @@ -4307,7 +4313,9 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, cleanup: qemuProcessStopQmp(proc); + qemuProcessStopQmp(proc_kvm); qemuProcessFree(proc); + qemuProcessFree(proc_kvm); return ret; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 70d73cd457..d017efad84 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8097,7 +8097,8 @@ qemuProcessNew(const char *binary, const char *libDir, uid_t runUid, gid_t runGid, - char **qmperr) + char **qmperr, + bool forceTCG) { qemuProcessPtr proc = NULL; @@ -8107,10 +8108,13 @@ qemuProcessNew(const char *binary, if (VIR_STRDUP(proc->binary, binary) < 0) goto error; + proc->forceTCG = forceTCG; + proc->runUid = runUid; proc->runGid = runGid; proc->qmperr = qmperr; + /* the ".sock" sufix is important to avoid a possible clash with a qemu * domain called "capabilities" */ @@ -8148,15 +8152,14 @@ qemuProcessNew(const char *binary, * 1 when probing QEMU failed */ int -qemuProcessRun(qemuProcessPtr proc, - bool forceTCG) +qemuProcessRun(qemuProcessPtr proc) { virDomainXMLOptionPtr xmlopt = NULL; const char *machine; int status = 0; int ret = -1; - if (forceTCG) + if (proc->forceTCG) machine = "none,accel=tcg"; else machine = "none,accel=kvm:tcg"; diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 25343c4592..ab2640ce7c 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -229,17 +229,19 @@ struct _qemuProcess { virDomainChrSourceDef config; pid_t pid; virDomainObjPtr vm; + bool forceTCG; }; qemuProcessPtr qemuProcessNew(const char *binary, const char *libDir, uid_t runUid, gid_t runGid, - char **qmperr); + char **qmperr, + bool forceTCG); void qemuProcessFree(qemuProcessPtr proc); -int qemuProcessRun(qemuProcessPtr proc, bool forceTCG); +int qemuProcessRun(qemuProcessPtr proc); void qemuProcessStopQmp(qemuProcessPtr proc); -- 2.17.1

A qemuProcess struct tracks the entire lifespan of a single QEMU Process including storing error output when the process terminates or activation fails. Error output remains available until qemuProcessFree is called. The qmperr buffer no longer needs to be maintained outside of the qemuProcess structure because the structure is used for a single QEMU process and the structures can be maintained as long as required to retrieve the process error info. Capabilities init code is refactored but continues to report QEMU process error data only when the initial (non KVM) QEMU process activation fails to result in a usable monitor connection for retrieving capabilities. The VIR_ERR_INTERNAL_ERROR "Failed to probe QEMU binary" reporting is moved into virQEMUCapsInitQMP function and the stderr string is extracted from the qemuProcess struct using a macro to retrieve the string. The same error and log message should be generated, in the same conditions, after this patch as before. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 27 ++++++++++++--------------- src/qemu/qemu_process.c | 12 ++++-------- src/qemu/qemu_process.h | 6 ++++-- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 99a963912c..9a86838d8a 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4271,8 +4271,7 @@ static int virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, const char *libDir, uid_t runUid, - gid_t runGid, - char **qmperr) + gid_t runGid) { qemuProcessPtr proc = NULL; qemuProcessPtr proc_kvm = NULL; @@ -4281,7 +4280,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, bool forceTCG = false; if (!(proc = qemuProcessNew(qemuCaps->binary, libDir, - runUid, runGid, qmperr, forceTCG))) + runUid, runGid, forceTCG))) goto cleanup; if ((rc = qemuProcessRun(proc)) != 0) { @@ -4297,7 +4296,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, qemuProcessStopQmp(proc); forceTCG = true; - proc_kvm = qemuProcessNew(qemuCaps->binary, libDir, runUid, runGid, NULL, forceTCG); + proc_kvm = qemuProcessNew(qemuCaps->binary, libDir, runUid, runGid, forceTCG); if ((rc = qemuProcessRun(proc_kvm)) != 0) { if (rc == 1) @@ -4312,6 +4311,13 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, ret = 0; cleanup: + if (proc && !proc->mon) { + char *err = QEMU_PROCESS_ERROR(proc) ? QEMU_PROCESS_ERROR(proc) : _("unknown error"); + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Failed to probe QEMU binary with QMP: %s"), err); + } + qemuProcessStopQmp(proc); qemuProcessStopQmp(proc_kvm); qemuProcessFree(proc); @@ -4351,7 +4357,6 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch, { virQEMUCapsPtr qemuCaps; struct stat sb; - char *qmperr = NULL; if (!(qemuCaps = virQEMUCapsNew())) goto error; @@ -4378,15 +4383,8 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch, goto error; } - if (virQEMUCapsInitQMP(qemuCaps, libDir, runUid, runGid, &qmperr) < 0) { - virQEMUCapsLogProbeFailure(binary); - goto error; - } - - if (!qemuCaps->usedQMP) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Failed to probe QEMU binary with QMP: %s"), - qmperr ? qmperr : _("unknown error")); + if (virQEMUCapsInitQMP(qemuCaps, libDir, runUid, runGid) < 0 || + !qemuCaps->usedQMP) { virQEMUCapsLogProbeFailure(binary); goto error; } @@ -4405,7 +4403,6 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch, } cleanup: - VIR_FREE(qmperr); return qemuCaps; error: diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index d017efad84..99b720b380 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8088,6 +8088,7 @@ qemuProcessFree(qemuProcessPtr proc) VIR_FREE(proc->monpath); VIR_FREE(proc->monarg); VIR_FREE(proc->pidfile); + VIR_FREE(proc->qmperr); VIR_FREE(proc); } @@ -8097,7 +8098,6 @@ qemuProcessNew(const char *binary, const char *libDir, uid_t runUid, gid_t runGid, - char **qmperr, bool forceTCG) { qemuProcessPtr proc = NULL; @@ -8112,8 +8112,6 @@ qemuProcessNew(const char *binary, proc->runUid = runUid; proc->runGid = runGid; - proc->qmperr = qmperr; - /* the ".sock" sufix is important to avoid a possible clash with a qemu * domain called "capabilities" @@ -8152,8 +8150,7 @@ qemuProcessNew(const char *binary, * 1 when probing QEMU failed */ int -qemuProcessRun(qemuProcessPtr proc) -{ +qemuProcessRun(qemuProcessPtr proc){ virDomainXMLOptionPtr xmlopt = NULL; const char *machine; int status = 0; @@ -8189,7 +8186,7 @@ qemuProcessRun(qemuProcessPtr proc) virCommandSetGID(proc->cmd, proc->runGid); virCommandSetUID(proc->cmd, proc->runUid); - virCommandSetErrorBuffer(proc->cmd, proc->qmperr); + virCommandSetErrorBuffer(proc->cmd, &(proc->qmperr)); /* Log, but otherwise ignore, non-zero status. */ if (virCommandRun(proc->cmd, &status) < 0) @@ -8197,7 +8194,7 @@ qemuProcessRun(qemuProcessPtr proc) if (status != 0) { VIR_DEBUG("QEMU %s exited with status %d: %s", - proc->binary, status, *proc->qmperr); + proc->binary, status, proc->qmperr); goto ignore; } @@ -8259,7 +8256,6 @@ qemuProcessStopQmp(qemuProcessPtr proc) (long long)proc->pid, virStrerror(errno, ebuf, sizeof(ebuf))); - VIR_FREE(*proc->qmperr); } if (proc->pidfile) unlink(proc->pidfile); diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index ab2640ce7c..abd80baf5c 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -220,7 +220,7 @@ struct _qemuProcess { char *binary; uid_t runUid; gid_t runGid; - char **qmperr; + char *qmperr; /* qemu process stderr */ char *monarg; char *monpath; char *pidfile; @@ -232,11 +232,13 @@ struct _qemuProcess { bool forceTCG; }; +#define QEMU_PROCESS_ERROR(proc) \ + ((char *) (proc ? proc->qmperr: NULL)) + qemuProcessPtr qemuProcessNew(const char *binary, const char *libDir, uid_t runUid, gid_t runGid, - char **qmperr, bool forceTCG); void qemuProcessFree(qemuProcessPtr proc); -- 2.17.1

Failure to connect to QEMU to probe capabilities is not considered a error case and does not result in a negative return value. Check for a NULL monitor connection pointer before trying to send capabilities commands to QEMU rather than depending on a special positive return value. This simplifies logic and is more consistent with the operation of existing qemu_process functions. A macro is introduced to easily obtain the monitor pointer from the qemuProcess structure. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 28 ++++++++++++++++++---------- src/qemu/qemu_process.c | 9 +-------- src/qemu/qemu_process.h | 3 +++ 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 9a86838d8a..48b58ca02a 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4275,43 +4275,51 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, { qemuProcessPtr proc = NULL; qemuProcessPtr proc_kvm = NULL; + qemuMonitorPtr mon = NULL; + qemuMonitorPtr mon_kvm = NULL; int ret = -1; - int rc; bool forceTCG = false; if (!(proc = qemuProcessNew(qemuCaps->binary, libDir, runUid, runGid, forceTCG))) goto cleanup; - if ((rc = qemuProcessRun(proc)) != 0) { - if (rc == 1) - ret = 0; + + if (qemuProcessRun(proc) < 0) + goto cleanup; + + if (!(mon = QEMU_PROCESS_MONITOR(proc))) { + ret = 0; /* Failure probing QEMU not considered error case */ goto cleanup; } - if (virQEMUCapsInitQMPMonitor(qemuCaps, proc->mon) < 0) + /* Pull capabilities from QEMU */ + if (virQEMUCapsInitQMPMonitor(qemuCaps, mon) < 0) goto cleanup; + /* Pull capabilities again if KVM supported */ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) { qemuProcessStopQmp(proc); forceTCG = true; proc_kvm = qemuProcessNew(qemuCaps->binary, libDir, runUid, runGid, forceTCG); - if ((rc = qemuProcessRun(proc_kvm)) != 0) { - if (rc == 1) - ret = 0; + if (qemuProcessRun(proc_kvm) < 0) + goto cleanup; + + if (!(mon_kvm = QEMU_PROCESS_MONITOR(proc_kvm))) { + ret = 0; /* Failure probing QEMU not considered error case */ goto cleanup; } - if (virQEMUCapsInitQMPMonitorTCG(qemuCaps, proc_kvm->mon) < 0) + if (virQEMUCapsInitQMPMonitorTCG(qemuCaps, mon_kvm) < 0) goto cleanup; } ret = 0; cleanup: - if (proc && !proc->mon) { + if (!mon) { char *err = QEMU_PROCESS_ERROR(proc) ? QEMU_PROCESS_ERROR(proc) : _("unknown error"); virReportError(VIR_ERR_INTERNAL_ERROR, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 99b720b380..140c657087 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8145,10 +8145,6 @@ qemuProcessNew(const char *binary, } -/* Returns -1 on fatal error, - * 0 on success, - * 1 when probing QEMU failed - */ int qemuProcessRun(qemuProcessPtr proc){ virDomainXMLOptionPtr xmlopt = NULL; @@ -8215,6 +8211,7 @@ qemuProcessRun(qemuProcessPtr proc){ virObjectLock(proc->mon); + ignore: ret = 0; cleanup: @@ -8223,10 +8220,6 @@ qemuProcessRun(qemuProcessPtr proc){ virObjectUnref(xmlopt); return ret; - - ignore: - ret = 1; - goto cleanup; } diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index abd80baf5c..37194e2501 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -235,6 +235,9 @@ struct _qemuProcess { #define QEMU_PROCESS_ERROR(proc) \ ((char *) (proc ? proc->qmperr: NULL)) +#define QEMU_PROCESS_MONITOR(proc) \ + ((qemuMonitorPtr) (proc ? proc->mon : NULL)) + qemuProcessPtr qemuProcessNew(const char *binary, const char *libDir, uid_t runUid, -- 2.17.1

Move a step closer to the function structure used elsewhere in qemu_process where qemuProcessStart and qemuProcessStop are the exposed functions. qemuProcessStartQmp mirrors qemuProcessStart in calling sub functions to intialize, launch the process and connect the monitor to the QEMU process. static functions qemuProcessInitQmp, qemuProcessLaunchQmp and qemuConnectMonitorQmp are also introduced. qemuProcessLaunchQmp is just renamed from qemuProcessRun and encapsulates all of the original code. qemuProcessInitQmp and qemuProcessMonitorQmp are introduced as empty wrappers into which subsequent patches will partition code from qemuProcessLaunchQmp. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 4 +- src/qemu/qemu_process.c | 96 +++++++++++++++++++++++++++++++++++- src/qemu/qemu_process.h | 2 +- 3 files changed, 97 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 48b58ca02a..5cbc726bb9 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4285,7 +4285,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, goto cleanup; - if (qemuProcessRun(proc) < 0) + if (qemuProcessStartQmp(proc) < 0) goto cleanup; if (!(mon = QEMU_PROCESS_MONITOR(proc))) { @@ -4304,7 +4304,7 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps, forceTCG = true; proc_kvm = qemuProcessNew(qemuCaps->binary, libDir, runUid, runGid, forceTCG); - if (qemuProcessRun(proc_kvm) < 0) + if (qemuProcessStartQmp(proc_kvm) < 0) goto cleanup; if (!(mon_kvm = QEMU_PROCESS_MONITOR(proc_kvm))) { diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 140c657087..1d96a43206 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8145,8 +8145,29 @@ qemuProcessNew(const char *binary, } -int -qemuProcessRun(qemuProcessPtr proc){ +/* Initialize configuration and paths prior to starting QEMU + */ +static int +qemuProcessInitQmp(qemuProcessPtr proc) +{ + int ret = -1; + + VIR_DEBUG("Beginning VM startup process" + "emulator=%s", + proc->binary); + + ret = 0; + + VIR_DEBUG("ret=%i", ret); + return ret; +} + + +/* Launch QEMU Process + */ +static int +qemuProcessLaunchQmp(qemuProcessPtr proc) +{ virDomainXMLOptionPtr xmlopt = NULL; const char *machine; int status = 0; @@ -8223,6 +8244,77 @@ qemuProcessRun(qemuProcessPtr proc){ } +/* Connect Monitor to QEMU Process + */ +static int +qemuConnectMonitorQmp(qemuProcessPtr proc) +{ + int ret = -1; + + VIR_DEBUG("proc=%p, emulator=%s, proc->pid=%lld", + proc, NULLSTR(proc->binary), (long long) proc->pid); + + ret = 0; + + VIR_DEBUG("ret=%i", ret); + return ret; +} + + +/** + * qemuProcessStartQmp: + * @proc: Stores Process and Connection State + * + * Start and connect to QEMU binary so QMP queries can be made. + * + * Usage: + * proc = qemuProcessNew(binary, forceTCG, libDir, runUid, runGid); + * qemuProcessStartQmp(proc); + * mon = QEMU_PROCESS_MONITOR(proc); + * ** Send QMP Queries to QEMU using monitor ** + * qemuProcessStopQmp(proc); + * qemuProcessFree(proc); + * + * Check monitor is not NULL before using. + * + * QEMU probing failure results in monitor being NULL but is not considered + * an error case and does not result in a negative return value. + * + * Both qemuProcessStopQmp and qemuProcessFree must be called to cleanup and + * free resources, even in activation failure cases. + * + * Process error output (proc->qmperr) remains available in qemuProcess struct + * until qemuProcessFree is called. + */ +int +qemuProcessStartQmp(qemuProcessPtr proc) +{ + int ret = -1; + + VIR_DEBUG("emulator=%s", + proc->binary); + + if (qemuProcessInitQmp(proc) < 0) + goto cleanup; + + if (qemuProcessLaunchQmp(proc) < 0) + goto stop; + + if (qemuConnectMonitorQmp(proc) < 0) + goto stop; + + ret = 0; + + cleanup: + VIR_DEBUG("ret=%i", ret); + return ret; + + stop: + qemuProcessStopQmp(proc); + goto cleanup; +} + + void qemuProcessStopQmp(qemuProcessPtr proc) { diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 37194e2501..c34ca52ef5 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -246,7 +246,7 @@ qemuProcessPtr qemuProcessNew(const char *binary, void qemuProcessFree(qemuProcessPtr proc); -int qemuProcessRun(qemuProcessPtr proc); +int qemuProcessStartQmp(qemuProcessPtr proc); void qemuProcessStopQmp(qemuProcessPtr proc); -- 2.17.1

Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 1d96a43206..758c8bed05 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8173,6 +8173,9 @@ qemuProcessLaunchQmp(qemuProcessPtr proc) int status = 0; int ret = -1; + VIR_DEBUG("proc=%p, emulator=%s", + proc, NULLSTR(proc->binary)); + if (proc->forceTCG) machine = "none,accel=tcg"; else -- 2.17.1

qemuMonitor code lives in qemuConnectMonitorQmp rather than in qemuProcessNew and qemuProcessLaunchQmp. This is consistent with existing structure in qemu_process.c where qemuConnectMonitor function contains monitor code for domain process activation. Simple code moves in this patch. Improvements in later patch. Only intended functional change in this patch is we don't move (include) code to initiate process stop on failure to create monitor. As comments in qemuProcessStartQmp say... Client must always call qemuProcessStop and qemuProcessFree, even in error cases. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 758c8bed05..f109e6e19b 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8133,10 +8133,6 @@ qemuProcessNew(const char *binary, virPidFileForceCleanupPath(proc->pidfile); - proc->config.type = VIR_DOMAIN_CHR_TYPE_UNIX; - proc->config.data.nix.path = proc->monpath; - proc->config.data.nix.listen = false; - return proc; error: @@ -8168,7 +8164,6 @@ qemuProcessInitQmp(qemuProcessPtr proc) static int qemuProcessLaunchQmp(qemuProcessPtr proc) { - virDomainXMLOptionPtr xmlopt = NULL; const char *machine; int status = 0; int ret = -1; @@ -8223,26 +8218,10 @@ qemuProcessLaunchQmp(qemuProcessPtr proc) goto ignore; } - if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) || - !(proc->vm = virDomainObjNew(xmlopt))) - goto cleanup; - - proc->vm->pid = proc->pid; - - if (!(proc->mon = qemuMonitorOpen(proc->vm, &proc->config, true, true, - 0, &callbacks, NULL))) - goto ignore; - - virObjectLock(proc->mon); - ignore: ret = 0; cleanup: - if (!proc->mon) - qemuProcessStopQmp(proc); - virObjectUnref(xmlopt); - return ret; } @@ -8253,13 +8232,33 @@ static int qemuConnectMonitorQmp(qemuProcessPtr proc) { int ret = -1; + virDomainXMLOptionPtr xmlopt = NULL; VIR_DEBUG("proc=%p, emulator=%s, proc->pid=%lld", proc, NULLSTR(proc->binary), (long long) proc->pid); + proc->config.type = VIR_DOMAIN_CHR_TYPE_UNIX; + proc->config.data.nix.path = proc->monpath; + proc->config.data.nix.listen = false; + + if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) || + !(proc->vm = virDomainObjNew(xmlopt))) + goto cleanup; + + proc->vm->pid = proc->pid; + + if (!(proc->mon = qemuMonitorOpen(proc->vm, &proc->config, true, true, + 0, &callbacks, NULL))) + goto ignore; + + virObjectLock(proc->mon); + + ignore: ret = 0; + cleanup: VIR_DEBUG("ret=%i", ret); + virObjectUnref(xmlopt); return ret; } -- 2.17.1

Store libDir path in the qemuProcess struct in anticipation of moving path construction code into qemuProcessInitQmp function. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 8 +++++--- src/qemu/qemu_process.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index f109e6e19b..804ec998af 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8085,6 +8085,7 @@ qemuProcessFree(qemuProcessPtr proc) qemuProcessStopQmp(proc); VIR_FREE(proc->binary); + VIR_FREE(proc->libDir); VIR_FREE(proc->monpath); VIR_FREE(proc->monarg); VIR_FREE(proc->pidfile); @@ -8105,7 +8106,8 @@ qemuProcessNew(const char *binary, if (VIR_ALLOC(proc) < 0) goto error; - if (VIR_STRDUP(proc->binary, binary) < 0) + if (VIR_STRDUP(proc->binary, binary) < 0 || + VIR_STRDUP(proc->libDir, libDir) < 0) goto error; proc->forceTCG = forceTCG; @@ -8116,7 +8118,7 @@ qemuProcessNew(const char *binary, /* the ".sock" sufix is important to avoid a possible clash with a qemu * domain called "capabilities" */ - if (virAsprintf(&proc->monpath, "%s/%s", libDir, + if (virAsprintf(&proc->monpath, "%s/%s", proc->libDir, "capabilities.monitor.sock") < 0) goto error; if (virAsprintf(&proc->monarg, "unix:%s,server,nowait", proc->monpath) < 0) @@ -8128,7 +8130,7 @@ qemuProcessNew(const char *binary, * -daemonize we need QEMU to be allowed to create them, rather * than libvirtd. So we're using libDir which QEMU can write to */ - if (virAsprintf(&proc->pidfile, "%s/%s", libDir, "capabilities.pidfile") < 0) + if (virAsprintf(&proc->pidfile, "%s/%s", proc->libDir, "capabilities.pidfile") < 0) goto error; virPidFileForceCleanupPath(proc->pidfile); diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index c34ca52ef5..1b8f743861 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -218,6 +218,7 @@ typedef struct _qemuProcess qemuProcess; typedef qemuProcess *qemuProcessPtr; struct _qemuProcess { char *binary; + char *libDir; uid_t runUid; gid_t runGid; char *qmperr; /* qemu process stderr */ -- 2.17.1

Move code for setting paths and prepping file system from qemuProcessNew to qemuProcessInitQmp. This keeps qemuProcessNew limited to structure initialization and most closely mirrors pattern established in qemuProcessInit within qemuProcessInitQmp. The patch is a non-functional, cut / paste change, however goto is now "cleanup" rather than "error". Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 42 +++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 804ec998af..70b0b61aef 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8115,26 +8115,6 @@ qemuProcessNew(const char *binary, proc->runUid = runUid; proc->runGid = runGid; - /* the ".sock" sufix is important to avoid a possible clash with a qemu - * domain called "capabilities" - */ - if (virAsprintf(&proc->monpath, "%s/%s", proc->libDir, - "capabilities.monitor.sock") < 0) - goto error; - if (virAsprintf(&proc->monarg, "unix:%s,server,nowait", proc->monpath) < 0) - goto error; - - /* ".pidfile" suffix is used rather than ".pid" to avoid a possible clash - * with a qemu domain called "capabilities" - * Normally we'd use runDir for pid files, but because we're using - * -daemonize we need QEMU to be allowed to create them, rather - * than libvirtd. So we're using libDir which QEMU can write to - */ - if (virAsprintf(&proc->pidfile, "%s/%s", proc->libDir, "capabilities.pidfile") < 0) - goto error; - - virPidFileForceCleanupPath(proc->pidfile); - return proc; error: @@ -8154,8 +8134,30 @@ qemuProcessInitQmp(qemuProcessPtr proc) "emulator=%s", proc->binary); + /* the ".sock" sufix is important to avoid a possible clash with a qemu + * domain called "capabilities" + */ + if (virAsprintf(&proc->monpath, "%s/%s", proc->libDir, + "capabilities.monitor.sock") < 0) + goto cleanup; + + if (virAsprintf(&proc->monarg, "unix:%s,server,nowait", proc->monpath) < 0) + goto cleanup; + + /* ".pidfile" suffix is used rather than ".pid" to avoid a possible clash + * with a qemu domain called "capabilities" + * Normally we'd use runDir for pid files, but because we're using + * -daemonize we need QEMU to be allowed to create them, rather + * than libvirtd. So we're using libDir which QEMU can write to + */ + if (virAsprintf(&proc->pidfile, "%s/%s", proc->libDir, "capabilities.pidfile") < 0) + goto cleanup; + + virPidFileForceCleanupPath(proc->pidfile); + ret = 0; + cleanup: VIR_DEBUG("ret=%i", ret); return ret; } -- 2.17.1

The monitor config data is removed from the qemuProcess struct. The monitor config data can be initialized immediately before call to qemuMonitorOpen and does not need to be maintained after the call because qemuMonitorOpen copies any strings it needs. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 9 +++++---- src/qemu/qemu_process.h | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 70b0b61aef..70ca82dd55 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8237,13 +8237,14 @@ qemuConnectMonitorQmp(qemuProcessPtr proc) { int ret = -1; virDomainXMLOptionPtr xmlopt = NULL; + virDomainChrSourceDef monConfig; VIR_DEBUG("proc=%p, emulator=%s, proc->pid=%lld", proc, NULLSTR(proc->binary), (long long) proc->pid); - proc->config.type = VIR_DOMAIN_CHR_TYPE_UNIX; - proc->config.data.nix.path = proc->monpath; - proc->config.data.nix.listen = false; + monConfig.type = VIR_DOMAIN_CHR_TYPE_UNIX; + monConfig.data.nix.path = proc->monpath; + monConfig.data.nix.listen = false; if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) || !(proc->vm = virDomainObjNew(xmlopt))) @@ -8251,7 +8252,7 @@ qemuConnectMonitorQmp(qemuProcessPtr proc) proc->vm->pid = proc->pid; - if (!(proc->mon = qemuMonitorOpen(proc->vm, &proc->config, true, true, + if (!(proc->mon = qemuMonitorOpen(proc->vm, &monConfig, true, true, 0, &callbacks, NULL))) goto ignore; diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 1b8f743861..d1541d5407 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -227,7 +227,6 @@ struct _qemuProcess { char *pidfile; virCommandPtr cmd; qemuMonitorPtr mon; - virDomainChrSourceDef config; pid_t pid; virDomainObjPtr vm; bool forceTCG; -- 2.17.1

Gracefully handle case when proc activation failed prior to calling. Consistent with the existing code for qemuConnectMonitor (for domains) in qemu_process.c... - Handle qemMonitorOpen failure with INFO message and NULL ptr - Identify parameters passed to qemuMonitorOpen Monitor callbacks will be removed in future patch so we prep for passing NULL for the callback pointer. Set proc->mon to NULL then use VIR_STEAL_PTR if successful to be consistent with other functions. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 70ca82dd55..af6b20713a 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8236,25 +8236,48 @@ static int qemuConnectMonitorQmp(qemuProcessPtr proc) { int ret = -1; + qemuMonitorPtr mon = NULL; + unsigned long long timeout = 0; + bool retry = true; + bool enableJson = true; + virQEMUDriverPtr driver = NULL; + qemuMonitorCallbacksPtr monCallbacks = &callbacks; virDomainXMLOptionPtr xmlopt = NULL; virDomainChrSourceDef monConfig; VIR_DEBUG("proc=%p, emulator=%s, proc->pid=%lld", proc, NULLSTR(proc->binary), (long long) proc->pid); + if (!proc || !proc->pid) + goto ignore; + + proc->mon = NULL; + monConfig.type = VIR_DOMAIN_CHR_TYPE_UNIX; monConfig.data.nix.path = proc->monpath; monConfig.data.nix.listen = false; + /* Create a NULL Domain object for qemuMonitor */ if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL, NULL)) || !(proc->vm = virDomainObjNew(xmlopt))) goto cleanup; proc->vm->pid = proc->pid; - if (!(proc->mon = qemuMonitorOpen(proc->vm, &monConfig, true, true, - 0, &callbacks, NULL))) + mon = qemuMonitorOpen(proc->vm, + &monConfig, + enableJson, + retry, + timeout, + monCallbacks, + driver); + + if (!mon) { + VIR_INFO("Failed to connect monitor to emulator %s", proc->binary); goto ignore; + } + + VIR_STEAL_PTR(proc->mon, mon); virObjectLock(proc->mon); -- 2.17.1

qemuProcessNew is one of the 4 public functions used to create and manage a qemu process for QMP command exchanges outside of domain operations. Add descriptive comment block, Debug statement and make source consistent with the cleanup / VIR_STEAL_PTR format used elsewhere. No functional changes are made. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index af6b20713a..104ed58cea 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8094,6 +8094,18 @@ qemuProcessFree(qemuProcessPtr proc) } +/** + * qemuProcessNew: + * @binary: Qemu binary + * @libDir: Directory for process and connection artifacts + * @runUid: UserId for Qemu Process + * @runGid: GroupId for Qemu Process + * @forceTCG: Force TCG mode if true + * + * Allocate and initialize domain structure encapsulating + * QEMU Process state and monitor connection to QEMU + * for completing QMP Queries. + */ qemuProcessPtr qemuProcessNew(const char *binary, const char *libDir, @@ -8101,25 +8113,29 @@ qemuProcessNew(const char *binary, gid_t runGid, bool forceTCG) { + qemuProcessPtr ret = NULL; qemuProcessPtr proc = NULL; + VIR_DEBUG("exec=%s, libDir=%s, runUid=%u, runGid=%u, forceTCG=%d", + NULLSTR(binary), NULLSTR(libDir), runUid, runGid, forceTCG); + if (VIR_ALLOC(proc) < 0) - goto error; + goto cleanup; if (VIR_STRDUP(proc->binary, binary) < 0 || VIR_STRDUP(proc->libDir, libDir) < 0) - goto error; + goto cleanup; proc->forceTCG = forceTCG; proc->runUid = runUid; proc->runGid = runGid; - return proc; + VIR_STEAL_PTR(ret, proc); - error: + cleanup: qemuProcessFree(proc); - return NULL; + return ret; } -- 2.17.1

qemuProcessStopQmp is one of the 4 public functions used to crate and manage a Qemu process for QMP command exchanges. Add comment header and debug message. Other minor code formatting cleanup. No change in functionality is intended. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 104ed58cea..cb2902be02 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8360,14 +8360,27 @@ qemuProcessStartQmp(qemuProcessPtr proc) goto cleanup; } - -void -qemuProcessStopQmp(qemuProcessPtr proc) +/** + * qemuProcessStop: + * @proc: Stores Process and Connection State + * + * Stop Monitor Connection and QEMU Process + */ +void qemuProcessStopQmp(qemuProcessPtr proc) { - if (proc->mon) - virObjectUnlock(proc->mon); - qemuMonitorClose(proc->mon); - proc->mon = NULL; + qemuMonitorPtr mon = NULL; + + if (!proc) + return; + + VIR_DEBUG("Shutting down proc=%p emulator=%s mon=%p pid=%lld", + proc, proc->binary, proc->mon, (long long)proc->pid); + + if ((mon = QEMU_PROCESS_MONITOR(proc))) { + virObjectUnlock(mon); + qemuMonitorClose(mon); + proc->mon = NULL; + } virCommandAbort(proc->cmd); virCommandFree(proc->cmd); @@ -8388,7 +8401,9 @@ qemuProcessStopQmp(qemuProcessPtr proc) virStrerror(errno, ebuf, sizeof(ebuf))); } + if (proc->pidfile) unlink(proc->pidfile); + proc->pid = 0; } -- 2.17.1

Catch execution paths where qemuProcessFree is called before qemuProcessStopQmp then report error and force stop before proceeding. Also added public function header and debug message. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index cb2902be02..9d3ce4eb6d 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8075,15 +8075,28 @@ static qemuMonitorCallbacks callbacks = { }; - - +/** + * qemuProcessFree: + * @proc: Stores Process and Connection State + * + * Free process data structure. + */ void qemuProcessFree(qemuProcessPtr proc) { + VIR_DEBUG("proc=%p, proc->mon=%p", proc, (proc ? proc->mon : NULL)); + if (!proc) return; - qemuProcessStopQmp(proc); + /* This should never be non-NULL if we get here, but just in case... */ + if (proc->mon || proc->pid) { + VIR_ERROR(_("Unexpected QEMU still active during process free" + " emulator: %s, pid: %lld, mon: %p"), + NULLSTR(proc->binary), (long long) proc->pid, proc->mon); + qemuProcessStopQmp(proc); + } + VIR_FREE(proc->binary); VIR_FREE(proc->libDir); VIR_FREE(proc->monpath); -- 2.17.1

Qemu process code for capababilities doesn't use monitor callbacks and defines empty callback functions. Allow NULL to be passed to qemuMonitorOpen for callbacks and remove the empty functions from the QMP process code. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_monitor.c | 4 ++-- src/qemu/qemu_process.c | 14 +------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 4c0c2decf7..2071c6e846 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -813,12 +813,12 @@ qemuMonitorOpenInternal(virDomainObjPtr vm, { qemuMonitorPtr mon; - if (!cb->eofNotify) { + if (cb && !cb->eofNotify) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("EOF notify callback must be supplied")); return NULL; } - if (!cb->errorNotify) { + if (cb && !cb->errorNotify) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Error notify callback must be supplied")); return NULL; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 9d3ce4eb6d..f545fc3b33 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8063,18 +8063,6 @@ qemuProcessReconnectAll(virQEMUDriverPtr driver) } -static void virQEMUCapsMonitorNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED, - virDomainObjPtr vm ATTRIBUTE_UNUSED, - void *opaque ATTRIBUTE_UNUSED) -{ -} - -static qemuMonitorCallbacks callbacks = { - .eofNotify = virQEMUCapsMonitorNotify, - .errorNotify = virQEMUCapsMonitorNotify, -}; - - /** * qemuProcessFree: * @proc: Stores Process and Connection State @@ -8270,7 +8258,7 @@ qemuConnectMonitorQmp(qemuProcessPtr proc) bool retry = true; bool enableJson = true; virQEMUDriverPtr driver = NULL; - qemuMonitorCallbacksPtr monCallbacks = &callbacks; + qemuMonitorCallbacksPtr monCallbacks = NULL; virDomainXMLOptionPtr xmlopt = NULL; virDomainChrSourceDef monConfig; -- 2.17.1

qemuProcessStartQmp starts a QEMU process and monitor connection that can be used by multiple functions possibly for multiple QMP commands. The QMP exchange to exit capabilities negotiation mode and enter command mode can only be performed once after the monitor connection is established. Move responsibility for entering QMP command mode into the qemuProcess code so multiple functions can issue QMP commands in arbitrary orders. This also simplifies the functions using the connection provided by qemuProcessStartQmp to issue QMP commands. Test code now needs to call qemuMonitorSetCapabilities to send the message to switch to command mode because the test code does not use the qemuProcess command that internally calls qemuMonitorSetCapabilities. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 14 -------------- src/qemu/qemu_process.c | 8 ++++++++ tests/qemucapabilitiestest.c | 7 +++++++ 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 5cbc726bb9..dd7c07f6e2 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -4068,13 +4068,6 @@ virQEMUCapsInitQMPMonitor(virQEMUCapsPtr qemuCaps, /* @mon is supposed to be locked by callee */ - if (qemuMonitorSetCapabilities(mon) < 0) { - VIR_DEBUG("Failed to set monitor capabilities %s", - virGetLastErrorMessage()); - ret = 0; - goto cleanup; - } - if (qemuMonitorGetVersion(mon, &major, &minor, µ, &package) < 0) { @@ -4248,13 +4241,6 @@ virQEMUCapsInitQMPMonitorTCG(virQEMUCapsPtr qemuCaps ATTRIBUTE_UNUSED, { int ret = -1; - if (qemuMonitorSetCapabilities(mon) < 0) { - VIR_DEBUG("Failed to set monitor capabilities %s", - virGetLastErrorMessage()); - ret = 0; - goto cleanup; - } - if (virQEMUCapsProbeQMPCPUDefinitions(qemuCaps, mon, true) < 0) goto cleanup; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index f545fc3b33..1bb11b2089 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8298,6 +8298,14 @@ qemuConnectMonitorQmp(qemuProcessPtr proc) virObjectLock(proc->mon); + /* Exit capabilities negotiation mode and enter QEMU command mode + * by issuing qmp_capabilities command to QEMU */ + if (qemuMonitorSetCapabilities(proc->mon) < 0) { + VIR_DEBUG("Failed to set monitor capabilities %s", + virGetLastErrorMessage()); + goto ignore; + } + ignore: ret = 0; diff --git a/tests/qemucapabilitiestest.c b/tests/qemucapabilitiestest.c index 8fe5a55e1d..ea4671739b 100644 --- a/tests/qemucapabilitiestest.c +++ b/tests/qemucapabilitiestest.c @@ -58,6 +58,9 @@ testQemuCaps(const void *opaque) if (!(mon = qemuMonitorTestNewFromFileFull(repliesFile, &data->driver, NULL))) goto cleanup; + if (qemuMonitorSetCapabilities(qemuMonitorTestGetMonitor(mon)) < 0) + goto cleanup; + if (!(capsActual = virQEMUCapsNew()) || virQEMUCapsInitQMPMonitor(capsActual, qemuMonitorTestGetMonitor(mon)) < 0) @@ -65,6 +68,10 @@ testQemuCaps(const void *opaque) if (virQEMUCapsGet(capsActual, QEMU_CAPS_KVM)) { qemuMonitorResetCommandID(qemuMonitorTestGetMonitor(mon)); + + if (qemuMonitorSetCapabilities(qemuMonitorTestGetMonitor(mon)) < 0) + goto cleanup; + if (virQEMUCapsInitQMPMonitorTCG(capsActual, qemuMonitorTestGetMonitor(mon)) < 0) goto cleanup; -- 2.17.1

Multiple QEMU processes for QMP commands can operate concurrently. Use a unique directory under libDir for each QEMU processes to avoid pidfile and unix socket collision between processes. The pid file name is changed from "capabilities.pidfile" to "qmp.pid" because we no longer need to avoid a possible clash with a qemu domain called "capabilities" now that the processes artifacts are stored in their own unique temporary directories. "Capabilities" was changed to "qmp" in the pid file name because these processes are no longer specific to the capabilities usecase and are more generic in terms of being used for any general purpose QMP message exchanges with a QEMU process that is not associated with a domain. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 26 ++++++++++++++++---------- src/qemu/qemu_process.h | 1 + 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 1bb11b2089..08522a1580 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8087,6 +8087,7 @@ qemuProcessFree(qemuProcessPtr proc) VIR_FREE(proc->binary); VIR_FREE(proc->libDir); + VIR_FREE(proc->uniqDir); VIR_FREE(proc->monpath); VIR_FREE(proc->monarg); VIR_FREE(proc->pidfile); @@ -8145,33 +8146,33 @@ qemuProcessNew(const char *binary, static int qemuProcessInitQmp(qemuProcessPtr proc) { + char *template = NULL; int ret = -1; VIR_DEBUG("Beginning VM startup process" "emulator=%s", proc->binary); - /* the ".sock" sufix is important to avoid a possible clash with a qemu - * domain called "capabilities" - */ - if (virAsprintf(&proc->monpath, "%s/%s", proc->libDir, - "capabilities.monitor.sock") < 0) + if (virAsprintf(&template, "%s/qemu.XXXXXX", proc->libDir) < 0) + goto cleanup; + + proc->uniqDir = mkdtemp(template); + + if (virAsprintf(&proc->monpath, "%s/%s", proc->uniqDir, + "qmp.monitor") < 0) goto cleanup; if (virAsprintf(&proc->monarg, "unix:%s,server,nowait", proc->monpath) < 0) goto cleanup; - /* ".pidfile" suffix is used rather than ".pid" to avoid a possible clash - * with a qemu domain called "capabilities" + /* * Normally we'd use runDir for pid files, but because we're using * -daemonize we need QEMU to be allowed to create them, rather * than libvirtd. So we're using libDir which QEMU can write to */ - if (virAsprintf(&proc->pidfile, "%s/%s", proc->libDir, "capabilities.pidfile") < 0) + if (virAsprintf(&proc->pidfile, "%s/%s", proc->uniqDir, "qmp.pid") < 0) goto cleanup; - virPidFileForceCleanupPath(proc->pidfile); - ret = 0; cleanup: @@ -8415,4 +8416,9 @@ void qemuProcessStopQmp(qemuProcessPtr proc) unlink(proc->pidfile); proc->pid = 0; + + + if (proc->uniqDir) + rmdir(proc->uniqDir); + } diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index d1541d5407..f66fc0c82c 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -225,6 +225,7 @@ struct _qemuProcess { char *monarg; char *monpath; char *pidfile; + char *uniqDir; virCommandPtr cmd; qemuMonitorPtr mon; pid_t pid; -- 2.17.1

Locking the monitor object immediately after call to qemuMonitorOpen doesn't make sense now that we have expanded the QEMU process code to cover more than the original capabilities usecase. Removing the monitor lock makes the qemuConnectMonitorQmp code consistent with the qemuConnectMonitor code used to establish the monitor when QEMU process is started for domains. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_process.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 08522a1580..6bd3da97ca 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -8297,8 +8297,6 @@ qemuConnectMonitorQmp(qemuProcessPtr proc) VIR_STEAL_PTR(proc->mon, mon); - virObjectLock(proc->mon); - /* Exit capabilities negotiation mode and enter QEMU command mode * by issuing qmp_capabilities command to QEMU */ if (qemuMonitorSetCapabilities(proc->mon) < 0) { -- 2.17.1

Move existing code to convert between cpu model info structures (qemuMonitorCPUModelInfoPtr into virCPUDef) into a reusable function. The new function is used in this and future patches. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 84 ++++++++++++++++++++++++++---------- src/qemu/qemu_capabilities.h | 3 ++ 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index dd7c07f6e2..dcd6ffb876 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2797,7 +2797,8 @@ virQEMUCapsInitCPUModelS390(virQEMUCapsPtr qemuCaps, virCPUDefPtr cpu, bool migratable) { - size_t i; + virCPUDefPtr tmp = NULL; + int ret = -1; if (!modelInfo) { if (type == VIR_DOMAIN_VIRT_KVM) { @@ -2810,32 +2811,18 @@ virQEMUCapsInitCPUModelS390(virQEMUCapsPtr qemuCaps, return 2; } - if (VIR_STRDUP(cpu->model, modelInfo->name) < 0 || - VIR_ALLOC_N(cpu->features, modelInfo->nprops) < 0) - return -1; - - cpu->nfeatures_max = modelInfo->nprops; - cpu->nfeatures = 0; - - for (i = 0; i < modelInfo->nprops; i++) { - virCPUFeatureDefPtr feature = cpu->features + cpu->nfeatures; - qemuMonitorCPUPropertyPtr prop = modelInfo->props + i; + if (!(tmp = virQEMUCapsCPUModelInfoToCPUDef(migratable, modelInfo))) + goto cleanup; - if (prop->type != QEMU_MONITOR_CPU_PROPERTY_BOOLEAN) - continue; + /* Free original then copy over model, vendor, vendor_id and features */ + virCPUDefStealModel(cpu, tmp, true); - if (VIR_STRDUP(feature->name, prop->name) < 0) - return -1; + ret = 0; - if (!prop->value.boolean || - (migratable && prop->migratable == VIR_TRISTATE_BOOL_NO)) - feature->policy = VIR_CPU_FEATURE_DISABLE; - else - feature->policy = VIR_CPU_FEATURE_REQUIRE; - cpu->nfeatures++; - } + cleanup: + virCPUDefFree(tmp); - return 0; + return ret; } @@ -3633,6 +3620,57 @@ virQEMUCapsLoadCache(virArch hostArch, } +/* qemuMonitorCPUModelInfo name => virCPUDef model + * qemuMonitorCPUModelInfo boolean properties => virCPUDef features + * + * migratable true: mark non-migratable features as disabled + * false: allow all features as required + */ +virCPUDefPtr +virQEMUCapsCPUModelInfoToCPUDef(bool migratable, qemuMonitorCPUModelInfoPtr model) +{ + virCPUDefPtr cpu = NULL; + virCPUDefPtr ret = NULL; + size_t i; + + if (!model || VIR_ALLOC(cpu) < 0) + goto cleanup; + + VIR_DEBUG("model->name= %s", NULLSTR(model->name)); + + if (VIR_STRDUP(cpu->model, model->name) < 0 || + VIR_ALLOC_N(cpu->features, model->nprops) < 0) + goto cleanup; + + cpu->nfeatures_max = model->nprops; + cpu->nfeatures = 0; + + for (i = 0; i < model->nprops; i++) { + virCPUFeatureDefPtr feature = cpu->features + cpu->nfeatures; + qemuMonitorCPUPropertyPtr prop = model->props + i; + + if (prop->type != QEMU_MONITOR_CPU_PROPERTY_BOOLEAN) + continue; + + if (VIR_STRDUP(feature->name, prop->name) < 0) + goto cleanup; + + if (!prop->value.boolean || + (migratable && prop->migratable == VIR_TRISTATE_BOOL_NO)) + feature->policy = VIR_CPU_FEATURE_DISABLE; + else + feature->policy = VIR_CPU_FEATURE_REQUIRE; + + cpu->nfeatures++; + } + + VIR_STEAL_PTR(ret, cpu); + + cleanup: + virCPUDefFree(cpu); + return ret; +} + static void virQEMUCapsFormatHostCPUModelInfo(virQEMUCapsPtr qemuCaps, virBufferPtr buf, diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 6bb9a2c8f0..a377d7b912 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -572,6 +572,9 @@ int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, void virQEMUCapsFilterByMachineType(virQEMUCapsPtr qemuCaps, const char *machineType); +virCPUDefPtr virQEMUCapsCPUModelInfoToCPUDef(bool migratable, + qemuMonitorCPUModelInfoPtr model); + virFileCachePtr virQEMUCapsCacheNew(const char *libDir, const char *cacheDir, uid_t uid, -- 2.17.1

Create public function to convert virCPUDef data structure into qemuMonitorCPUModelInfoPtr data structure. There was no existing code to reuse to create this function so this new virQEMUCapsCPUModelInfoFromCPUDef function was based on reversing the action of the existing virQEMUCapsCPUModelInfoToCPUDef function. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_capabilities.c | 46 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_capabilities.h | 1 + 2 files changed, 47 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index dcd6ffb876..54b94c4dda 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -3620,6 +3620,51 @@ virQEMUCapsLoadCache(virArch hostArch, } +/* virCPUDef model => qemuMonitorCPUModelInfo name + * virCPUDef features => qemuMonitorCPUModelInfo boolean properties */ +qemuMonitorCPUModelInfoPtr +virQEMUCapsCPUModelInfoFromCPUDef(const virCPUDef *cpuDef) +{ + size_t i; + qemuMonitorCPUModelInfoPtr cpuModel = NULL; + qemuMonitorCPUModelInfoPtr ret = NULL; + + if (!cpuDef || (VIR_ALLOC(cpuModel) < 0)) + goto cleanup; + + VIR_DEBUG("cpuDef->model = %s", NULLSTR(cpuDef->model)); + + if (VIR_STRDUP(cpuModel->name, cpuDef->model) < 0 || + VIR_ALLOC_N(cpuModel->props, cpuDef->nfeatures) < 0) + goto cleanup; + + cpuModel->nprops = 0; + + for (i = 0; i < cpuDef->nfeatures; i++) { + qemuMonitorCPUPropertyPtr prop = &(cpuModel->props[cpuModel->nprops]); + virCPUFeatureDefPtr feature = &(cpuDef->features[i]); + + if (!(feature->name) || + VIR_STRDUP(prop->name, feature->name) < 0) + goto cleanup; + + prop->type = QEMU_MONITOR_CPU_PROPERTY_BOOLEAN; + + prop->value.boolean = feature->policy == -1 || /* policy undefined */ + feature->policy == VIR_CPU_FEATURE_FORCE || + feature->policy == VIR_CPU_FEATURE_REQUIRE; + + cpuModel->nprops++; + } + + VIR_STEAL_PTR(ret, cpuModel); + + cleanup: + qemuMonitorCPUModelInfoFree(cpuModel); + return ret; +} + + /* qemuMonitorCPUModelInfo name => virCPUDef model * qemuMonitorCPUModelInfo boolean properties => virCPUDef features * @@ -3671,6 +3716,7 @@ virQEMUCapsCPUModelInfoToCPUDef(bool migratable, qemuMonitorCPUModelInfoPtr mode return ret; } + static void virQEMUCapsFormatHostCPUModelInfo(virQEMUCapsPtr qemuCaps, virBufferPtr buf, diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index a377d7b912..ea5e021ca6 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -572,6 +572,7 @@ int virQEMUCapsGetMachineTypesCaps(virQEMUCapsPtr qemuCaps, void virQEMUCapsFilterByMachineType(virQEMUCapsPtr qemuCaps, const char *machineType); +qemuMonitorCPUModelInfoPtr virQEMUCapsCPUModelInfoFromCPUDef(const virCPUDef *cpuDef); virCPUDefPtr virQEMUCapsCPUModelInfoToCPUDef(bool migratable, qemuMonitorCPUModelInfoPtr model); -- 2.17.1

Introduce monitor functions to use QEMU to compute baseline cpu from an input of two cpu models. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_monitor.c | 12 ++++++++ src/qemu/qemu_monitor.h | 6 ++++ src/qemu/qemu_monitor_json.c | 60 ++++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 6 ++++ 4 files changed, 84 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 2071c6e846..edbaee1a53 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4495,3 +4495,15 @@ qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon, virHashFree(info); return ret; } + + +int +qemuMonitorGetCPUModelBaseline(qemuMonitorPtr mon, + qemuMonitorCPUModelInfoPtr model_a, + qemuMonitorCPUModelInfoPtr model_b, + qemuMonitorCPUModelInfoPtr *model_baseline) +{ + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONGetCPUModelBaseline(mon, model_a, model_b, model_baseline); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index d3efd37099..d46e9378ea 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1196,4 +1196,10 @@ struct _qemuMonitorPRManagerInfo { int qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon, virHashTablePtr *retinfo); +int qemuMonitorGetCPUModelBaseline(qemuMonitorPtr mon, + qemuMonitorCPUModelInfoPtr model_a, + qemuMonitorCPUModelInfoPtr model_b, + qemuMonitorCPUModelInfoPtr *model_baseline) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); + #endif /* QEMU_MONITOR_H */ diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 2eabfdac70..84da721f8d 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8464,3 +8464,63 @@ qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon, return ret; } + + +int +qemuMonitorJSONGetCPUModelBaseline(qemuMonitorPtr mon, + qemuMonitorCPUModelInfoPtr model_a, + qemuMonitorCPUModelInfoPtr model_b, + qemuMonitorCPUModelInfoPtr *model_baseline) +{ + int ret = -1; + virJSONValuePtr cmd = NULL; + virJSONValuePtr reply = NULL; + virJSONValuePtr data = NULL; + virJSONValuePtr modela = NULL; + virJSONValuePtr modelb = NULL; + virJSONValuePtr cpu_model = NULL; + + *model_baseline = NULL; + + if (!(modela = qemuMonitorJSONBuildCPUModelInfoToJSON(model_a)) || + !(modelb = qemuMonitorJSONBuildCPUModelInfoToJSON(model_b))) + goto cleanup; + + if (!(cmd = qemuMonitorJSONMakeCommand("query-cpu-model-baseline", + "a:modela", &modela, + "a:modelb", &modelb, + NULL))) + goto cleanup; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_OBJECT) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("QEMU doesn't support baseline or recognize model %s or %s"), + model_a->name, + model_b->name); + goto cleanup; + } + + data = virJSONValueObjectGetObject(reply, "return"); + + if (!(cpu_model = virJSONValueObjectGetObject(data, "model"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("query-cpu-model-baseline reply data was missing 'model'")); + goto cleanup; + } + + if (!(*model_baseline = qemuMonitorJSONBuildCPUModelInfoFromJSON(cpu_model))) + goto cleanup; + + ret = 0; + + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + virJSONValueFree(modela); + virJSONValueFree(modelb); + + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 2d5679094e..117a4a6cd0 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -577,4 +577,10 @@ int qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon, virHashTablePtr info) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int qemuMonitorJSONGetCPUModelBaseline(qemuMonitorPtr mon, + qemuMonitorCPUModelInfoPtr model_a, + qemuMonitorCPUModelInfoPtr model_b, + qemuMonitorCPUModelInfoPtr *model_baseline) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); + #endif /* QEMU_MONITOR_JSON_H */ -- 2.17.1

Simple cut/paste operations within function qemuConnectBaselineHypervisorCPU to group together code specific to computing baseline using only libvirt utility functions. This is done in anticipation of creating new utility functions for 1) baseline using libvirt utilities (this code) 2) baseline using qemu qmp command (future) Future patches are easier to follow if the code for using libvirt is consolidated. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_driver.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a52e2495d5..83f5fe0db0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13425,7 +13425,6 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, virQEMUCapsPtr qemuCaps = NULL; virArch arch; virDomainVirtType virttype; - virDomainCapsCPUModelsPtr cpuModels; bool migratable; virCPUDefPtr cpu = NULL; char *cpustr = NULL; @@ -13437,8 +13436,6 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, if (virConnectBaselineHypervisorCPUEnsureACL(conn) < 0) goto cleanup; - migratable = !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE); - if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_AUTO))) goto cleanup; @@ -13451,17 +13448,21 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, if (!qemuCaps) goto cleanup; - if (!(cpuModels = virQEMUCapsGetCPUDefinitions(qemuCaps, virttype)) || - cpuModels->nmodels == 0) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, - _("QEMU '%s' does not support any CPU models for " - "virttype '%s'"), - virQEMUCapsGetBinary(qemuCaps), - virDomainVirtTypeToString(virttype)); - goto cleanup; - } - if (ARCH_IS_X86(arch)) { + migratable = !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE); + + virDomainCapsCPUModelsPtr cpuModels; + + if (!(cpuModels = virQEMUCapsGetCPUDefinitions(qemuCaps, virttype)) || + cpuModels->nmodels == 0) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("QEMU '%s' does not support any CPU models for " + "virttype '%s'"), + virQEMUCapsGetBinary(qemuCaps), + virDomainVirtTypeToString(virttype)); + goto cleanup; + } + int rc = virQEMUCapsGetCPUFeatures(qemuCaps, virttype, migratable, &features); if (rc < 0) -- 2.17.1

Create utility function encapsulating code to calculate hypervisor baseline cpu using the local libvirt utility functions. Similar function encapsulating code to calculating hypervisor baseline using QEMU QMP messages will be introduced in later commit. Patch is a cut and paste of existing code into a utility function wrapper. s/cpu/*baseline/ (change output variable name ) and initialize variable "rc" are the only code changes. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_driver.c | 78 ++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 83f5fe0db0..54f7b8b26d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13410,6 +13410,55 @@ qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, } +static int +qemuConnectBaselineHypervisorCPUViaLibvirt( + virQEMUCapsPtr qemuCaps, + bool migratable, + virDomainVirtType virttype, + virArch arch, + virCPUDefPtr *cpus, + unsigned int ncpus, + virCPUDefPtr *baseline) +{ + char **features = NULL; + int ret = -1; + int rc = -1; + virDomainCapsCPUModelsPtr cpuModels; + + *baseline = NULL; + + if (!(cpuModels = virQEMUCapsGetCPUDefinitions(qemuCaps, virttype)) || + cpuModels->nmodels == 0) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("QEMU '%s' does not support any CPU models for " + "virttype '%s'"), + virQEMUCapsGetBinary(qemuCaps), + virDomainVirtTypeToString(virttype)); + goto cleanup; + } + + rc = virQEMUCapsGetCPUFeatures(qemuCaps, virttype, + migratable, &features); + if (rc < 0) + goto cleanup; + if (features && rc == 0) { + /* We got only migratable features from QEMU if we asked for them, + * no further filtering in virCPUBaseline is desired. */ + migratable = false; + } + + if (!(*baseline = virCPUBaseline(arch, cpus, ncpus, cpuModels, + (const char **)features, migratable))) + goto cleanup; + + ret = 0; + + cleanup: + virStringListFree(features); + return ret; +} + + static char * qemuConnectBaselineHypervisorCPU(virConnectPtr conn, const char *emulator, @@ -13428,7 +13477,6 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, bool migratable; virCPUDefPtr cpu = NULL; char *cpustr = NULL; - char **features = NULL; virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL); @@ -13451,30 +13499,9 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, if (ARCH_IS_X86(arch)) { migratable = !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE); - virDomainCapsCPUModelsPtr cpuModels; - - if (!(cpuModels = virQEMUCapsGetCPUDefinitions(qemuCaps, virttype)) || - cpuModels->nmodels == 0) { - virReportError(VIR_ERR_OPERATION_UNSUPPORTED, - _("QEMU '%s' does not support any CPU models for " - "virttype '%s'"), - virQEMUCapsGetBinary(qemuCaps), - virDomainVirtTypeToString(virttype)); - goto cleanup; - } - - int rc = virQEMUCapsGetCPUFeatures(qemuCaps, virttype, - migratable, &features); - if (rc < 0) - goto cleanup; - if (features && rc == 0) { - /* We got only migratable features from QEMU if we asked for them, - * no further filtering in virCPUBaseline is desired. */ - migratable = false; - } - - if (!(cpu = virCPUBaseline(arch, cpus, ncpus, cpuModels, - (const char **)features, migratable))) + if (qemuConnectBaselineHypervisorCPUViaLibvirt(qemuCaps, migratable, + virttype, arch, + cpus, ncpus, &cpu) < 0) goto cleanup; } else { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, @@ -13495,7 +13522,6 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, virCPUDefListFree(cpus); virCPUDefFree(cpu); virObjectUnref(qemuCaps); - virStringListFree(features); return cpustr; } -- 2.17.1

Hypervisor baseline cpu can be computed locally using libvirt utility functions or remotely using QEMU QMP commands. Likewise, cpu feature expansion can be computed locally using libvirt utility functions or remotely using QEMU QMP commands. This patch identifies using libvirt as a distinct case in the hypervisor baseline logic and triggers that case when the X86 architecture is being baselined. There is one functionality change introduced by this patch. Local libvirt functions are only used for feature expansion when the local utility functions are used for CPU baseline and an error is generated when no method is available to expand cpu featues. The useQEMU option will be introduced in a future patch for using QEMU to compute baseline rather than using libvirt. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_driver.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 54f7b8b26d..632b756c89 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13477,6 +13477,7 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, bool migratable; virCPUDefPtr cpu = NULL; char *cpustr = NULL; + bool useLibvirt = false; virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL); @@ -13496,7 +13497,9 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, if (!qemuCaps) goto cleanup; - if (ARCH_IS_X86(arch)) { + useLibvirt = ARCH_IS_X86(arch); + + if (useLibvirt) { migratable = !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE); if (qemuConnectBaselineHypervisorCPUViaLibvirt(qemuCaps, migratable, @@ -13512,9 +13515,17 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, cpu->fallback = VIR_CPU_FALLBACK_FORBID; - if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) && - virCPUExpandFeatures(arch, cpu) < 0) - goto cleanup; + if (flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) { + if (useLibvirt && virCPUExpandFeatures(arch, cpu) < 0) { + goto cleanup; + } else { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("expand features while " + "computing baseline hypervisor CPU is not supported " + "for arch %s"), virArchToString(arch)); + goto cleanup; + } + } cpustr = virCPUDefFormat(cpu, NULL); -- 2.17.1

Add capability to calculate hypervisor baseline using QMP message exchanges with QEMU in addition to existing capability to calculate baseline using libvirt utility functions. A new utility function encapsulates the core logic for interacting with QEMU using QMP baseline messages. The QMP messages only allow two cpu models to be evaluated at a time so a sequence of QMP baseline messages must be used to include all the models in the baseline when more than 2 cpu models are input. A QEMU process must be started prior to sending the series of QEMU messages to compute baseline. The QEMU process is started and maintained in the main hypervisor baseline function and only a pointer to the QEMU process monitor is passed to the baseline utility function. The QEMU process is maintained in the main hypervisor baseline function because the process will also be used for feature expansion (via QEMU) in a later patch. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_driver.c | 100 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 632b756c89..8b5c3e1fb5 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13410,6 +13410,78 @@ qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED, } +/* in: + * cpus[0]->model = "z14"; + * cpus[0]->features[0].name = "xxx"; + * cpus[0]->features[1].name = "yyy"; + * *** + * cpus[n]->model = "z13"; + * cpus[n]->features[0].name = "xxx"; + * cpus[n]->features[1].name = "yyy"; + * + * out: + * *baseline->model = "z13-base"; + * *baseline->features[0].name = "yyy"; + */ +static int +qemuConnectBaselineHypervisorCPUViaQEMU(qemuMonitorPtr mon, + virCPUDefPtr *cpus, + virCPUDefPtr *baseline) +{ + qemuMonitorCPUModelInfoPtr model_baseline = NULL; + qemuMonitorCPUModelInfoPtr new_model_baseline = NULL; + qemuMonitorCPUModelInfoPtr next_model = NULL; + bool migratable = true; + int ret = -1; + size_t i; + + *baseline = NULL; + + if (!cpus || !cpus[0]) { + virReportError(VIR_ERR_INVALID_ARG, "%s", _("no cpus")); + goto cleanup; + } + + for (i = 0; cpus[i]; i++) { /* cpus terminated by NULL element */ + virCPUDefPtr cpu = cpus[i]; + + VIR_DEBUG("cpu[%lu]->model = %s", i, NULLSTR(cpu->model)); + + if (!(next_model = virQEMUCapsCPUModelInfoFromCPUDef(cpu))) + goto cleanup; + + if (i == 0) { + model_baseline = next_model; + continue; + } + + if (qemuMonitorGetCPUModelBaseline(mon, model_baseline, + next_model, &new_model_baseline) < 0) + goto cleanup; + + qemuMonitorCPUModelInfoFree(model_baseline); + qemuMonitorCPUModelInfoFree(next_model); + + next_model = NULL; + + model_baseline = new_model_baseline; + } + + if (!(*baseline = virQEMUCapsCPUModelInfoToCPUDef(migratable, model_baseline))) + goto cleanup; + + VIR_DEBUG("baseline->model = %s", (*baseline)->model); + + ret = 0; + + cleanup: + qemuMonitorCPUModelInfoFree(model_baseline); + qemuMonitorCPUModelInfoFree(next_model); + + return ret; +} + + static int qemuConnectBaselineHypervisorCPUViaLibvirt( virQEMUCapsPtr qemuCaps, @@ -13478,6 +13550,12 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, virCPUDefPtr cpu = NULL; char *cpustr = NULL; bool useLibvirt = false; + bool useQemu = false; + bool forceTCG = false; + qemuMonitorCPUModelInfoPtr modelInfo = NULL; + qemuMonitorCPUModelInfoPtr expansion = NULL; + qemuProcessPtr proc = NULL; + qemuMonitorPtr mon = NULL; virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES | VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL); @@ -13498,6 +13576,7 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, goto cleanup; useLibvirt = ARCH_IS_X86(arch); + useQemu = ARCH_IS_S390(arch); if (useLibvirt) { migratable = !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE); @@ -13506,6 +13585,23 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, virttype, arch, cpus, ncpus, &cpu) < 0) goto cleanup; + + } else if (useQemu) { + const char *binary = virQEMUCapsGetBinary(qemuCaps); + virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); + + if (!(proc = qemuProcessNew(binary, cfg->libDir, + cfg->user, cfg->group, forceTCG))) + goto cleanup; + + if (qemuProcessStartQmp(proc) < 0) + goto cleanup; + + mon = QEMU_PROCESS_MONITOR(proc); + + if ((qemuConnectBaselineHypervisorCPUViaQEMU(mon, cpus, &cpu) < 0) || !cpu) + goto cleanup; + } else { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("computing baseline hypervisor CPU is not supported " @@ -13533,6 +13629,10 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, virCPUDefListFree(cpus); virCPUDefFree(cpu); virObjectUnref(qemuCaps); + qemuMonitorCPUModelInfoFree(modelInfo); + qemuMonitorCPUModelInfoFree(expansion); + qemuProcessStopQmp(proc); + qemuProcessFree(proc); return cpustr; } -- 2.17.1

Support using QEMU to do feature expansion when also using QEMU to compute hypervisor baseline. A QEMU process is already created to send the QMP messages to baseline using QEMU. The same QEMU process is used for the CPU feature expansion. QEMU only returns migratable features when expanding CPU model in architectures where QEMU is used for baseline so no attempt is made to ask for non-migratable features in expansions when using QEMU for baseline. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_driver.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8b5c3e1fb5..73707cce46 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13614,6 +13614,27 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, if (flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) { if (useLibvirt && virCPUExpandFeatures(arch, cpu) < 0) { goto cleanup; + } else if (useQemu && + virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION)) { + + if (!(modelInfo = virQEMUCapsCPUModelInfoFromCPUDef(cpu))) + goto cleanup; + + virCPUDefFree(cpu); + cpu = NULL; + + /* QEMU can only include migratable features + for all archs that use QEMU for baseline calculation */ + migratable = true; + + if (qemuMonitorGetCPUModelExpansion(mon, + QEMU_MONITOR_CPU_MODEL_EXPANSION_FULL, + migratable, modelInfo, &expansion) < 0) + goto cleanup; + + if (!(cpu = virQEMUCapsCPUModelInfoToCPUDef(migratable, expansion))) + goto cleanup; + } else { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("expand features while " -- 2.17.1

Hypervisor baseline has an expansion mode where the cpu property / feature list is fully expanded to list all supported (true) features. The output (expanded) cpu model should not list properties that are false (unsupported.) QEMU expansion output enumerates both true (supported) and false (unsupported) properties. This patch removes the false (unsupported) entries from the output cpu property list. This change makes the expanded output consistent when both the internal libvirt utility functions and QEMU QMP commands are used to expand the property list. qemu_monitor: Introduce removal of true/false CPUModelInfo props A utility function is created to squash CPU properties list in qemuMonitorCPUmodelInfo structure by removing boolean properties of matching value. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_driver.c | 4 ++++ src/qemu/qemu_monitor.c | 30 ++++++++++++++++++++++++++++++ src/qemu/qemu_monitor.h | 4 ++++ 3 files changed, 38 insertions(+) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 73707cce46..604c21d311 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13632,6 +13632,10 @@ qemuConnectBaselineHypervisorCPU(virConnectPtr conn, migratable, modelInfo, &expansion) < 0) goto cleanup; + /* Expansion enumerates all features + * Baselines output enumerates only in-model (true) features */ + qemuMonitorCPUModelInfoRemovePropByBoolValue(expansion, false); + if (!(cpu = virQEMUCapsCPUModelInfoToCPUDef(migratable, expansion))) goto cleanup; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index edbaee1a53..12feb034fd 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3785,6 +3785,36 @@ qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig) } +/* Squash CPU Model Info property list + * removing props of type boolean matching value */ +void +qemuMonitorCPUModelInfoRemovePropByBoolValue(qemuMonitorCPUModelInfoPtr model, + bool value) +{ + qemuMonitorCPUPropertyPtr src; + qemuMonitorCPUPropertyPtr dst; + size_t i; + size_t dst_nprops = 0; + + for (i = 0; i < model->nprops; i++) { + src = &(model->props[i]); + dst = &(model->props[dst_nprops]); + + if (src->type == QEMU_MONITOR_CPU_PROPERTY_BOOLEAN && + src->value.boolean == value) + continue; + + *dst = *src; + + dst_nprops++; + } + + model->nprops = dst_nprops; + + ignore_value(VIR_REALLOC_N_QUIET(model->props, dst_nprops)); +} + + int qemuMonitorCPUModelInfoBoolPropAdd(qemuMonitorCPUModelInfoPtr model, const char *prop_name, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index d46e9378ea..f6052ab852 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1053,6 +1053,10 @@ int qemuMonitorCPUModelInfoBoolPropAdd(qemuMonitorCPUModelInfoPtr model, bool prop_value) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +void qemuMonitorCPUModelInfoRemovePropByBoolValue(qemuMonitorCPUModelInfoPtr model, + bool value) + ATTRIBUTE_NONNULL(1); + int qemuMonitorGetCommands(qemuMonitorPtr mon, char ***commands); int qemuMonitorGetEvents(qemuMonitorPtr mon, -- 2.17.1

QEMU only returns migratable props when expanding model unless explicitly told to also include non-migratable props. Props will be marked migratable when we are certain QEMU returned only migratable props resulting in consistent information and expansion output for s390 that is consistent with x86. After this change, immediately default prop->migratable = _YES for all props when we know QEMU only included migratable props in CPU Model. Set model->migratability = true when we have set prop->migratable. Signed-off-by: Chris Venteicher <cventeic@redhat.com> --- src/qemu/qemu_monitor.c | 53 ++++++++++++++- src/qemu/qemu_monitor.h | 7 +- .../caps_2.10.0.s390x.xml | 60 ++++++++--------- .../caps_2.11.0.s390x.xml | 58 ++++++++--------- .../caps_2.12.0.s390x.xml | 56 ++++++++-------- .../qemucapabilitiesdata/caps_2.8.0.s390x.xml | 32 +++++----- .../qemucapabilitiesdata/caps_2.9.0.s390x.xml | 34 +++++----- .../qemucapabilitiesdata/caps_3.0.0.s390x.xml | 64 +++++++++---------- 8 files changed, 210 insertions(+), 154 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 12feb034fd..845cb929a6 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3682,12 +3682,31 @@ qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon, qemuMonitorCPUModelInfoPtr *expansion ) { + int ret = -1; + qemuMonitorCPUModelInfoPtr tmp; + VIR_DEBUG("type=%d model_name=%s migratable=%d", type, input->name, migratable); + *expansion = NULL; + QEMU_CHECK_MONITOR(mon); - return qemuMonitorJSONGetCPUModelExpansion(mon, type, migratable, input, expansion); + if ((ret = qemuMonitorJSONGetCPUModelExpansion(mon, type, migratable, input, &tmp)) < 0) + goto cleanup; + + if (migratable) { + /* Only migratable props were included in expanded CPU model */ + *expansion = qemuMonitorCPUModelInfoCopyDefaultMigratable(tmp); + } else { + VIR_STEAL_PTR(*expansion, tmp); + } + + ret = 0; + + cleanup: + qemuMonitorCPUModelInfoFree(tmp); + return ret; } @@ -3785,6 +3804,38 @@ qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig) } +qemuMonitorCPUModelInfoPtr +qemuMonitorCPUModelInfoCopyDefaultMigratable(const qemuMonitorCPUModelInfo *orig) +{ + qemuMonitorCPUModelInfoPtr ret = NULL; + qemuMonitorCPUModelInfoPtr tmp = NULL; + qemuMonitorCPUPropertyPtr prop = NULL; + size_t i; + + if (!(tmp = qemuMonitorCPUModelInfoCopy(orig))) + goto cleanup; + + for (i = 0; i < tmp->nprops; i++) { + prop = tmp->props + i; + + /* Default prop thats in cpu model (true) to migratable (_YES) + * unless prop already explicitly set not migratable (_NO) + */ + if (prop->type == QEMU_MONITOR_CPU_PROPERTY_BOOLEAN && + prop->value.boolean && + prop->migratable != VIR_TRISTATE_BOOL_NO) + prop->migratable = VIR_TRISTATE_BOOL_YES; + } + + tmp->migratability = true; /* prop->migratable = YES/NO for all CPU props */ + + VIR_STEAL_PTR(ret, tmp); + + cleanup: + return ret; +} + + /* Squash CPU Model Info property list * removing props of type boolean matching value */ void diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index f6052ab852..9216f45f59 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1025,7 +1025,7 @@ struct _qemuMonitorCPUModelInfo { char *name; size_t nprops; qemuMonitorCPUPropertyPtr props; - bool migratability; + bool migratability; /* true if prop->migratable is YES/NO for all CPU props */ }; typedef enum { @@ -1048,6 +1048,11 @@ qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoNew(const char *name); qemuMonitorCPUModelInfoPtr qemuMonitorCPUModelInfoCopy(const qemuMonitorCPUModelInfo *orig); +qemuMonitorCPUModelInfoPtr +qemuMonitorCPUModelInfoCopyDefaultMigratable(const qemuMonitorCPUModelInfo *orig) + ATTRIBUTE_NONNULL(1); + + int qemuMonitorCPUModelInfoBoolPropAdd(qemuMonitorCPUModelInfoPtr model, const char *prop_name, bool prop_value) diff --git a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml index e000aac384..391bee4f06 100644 --- a/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.10.0.s390x.xml @@ -118,36 +118,36 @@ <microcodeVersion>306247</microcodeVersion> <package></package> <arch>s390x</arch> - <hostCPU type='kvm' model='z14-base' migratability='no'> - <property name='aen' type='boolean' value='true'/> - <property name='cmmnt' type='boolean' value='true'/> - <property name='aefsi' type='boolean' value='true'/> - <property name='mepoch' type='boolean' value='true'/> - <property name='msa8' type='boolean' value='true'/> - <property name='msa7' type='boolean' value='true'/> - <property name='msa6' type='boolean' value='true'/> - <property name='msa5' type='boolean' value='true'/> - <property name='msa4' type='boolean' value='true'/> - <property name='msa3' type='boolean' value='true'/> - <property name='msa2' type='boolean' value='true'/> - <property name='msa1' type='boolean' value='true'/> - <property name='sthyi' type='boolean' value='true'/> - <property name='edat' type='boolean' value='true'/> - <property name='ri' type='boolean' value='true'/> - <property name='edat2' type='boolean' value='true'/> - <property name='vx' type='boolean' value='true'/> - <property name='ipter' type='boolean' value='true'/> - <property name='vxeh' type='boolean' value='true'/> - <property name='vxpd' type='boolean' value='true'/> - <property name='esop' type='boolean' value='true'/> - <property name='iep' type='boolean' value='true'/> - <property name='cte' type='boolean' value='true'/> - <property name='ais' type='boolean' value='true'/> - <property name='gs' type='boolean' value='true'/> - <property name='zpci' type='boolean' value='true'/> - <property name='sea_esop2' type='boolean' value='true'/> - <property name='te' type='boolean' value='true'/> - <property name='cmm' type='boolean' value='true'/> + <hostCPU type='kvm' model='z14-base' migratability='yes'> + <property name='aen' type='boolean' value='true' migratable='yes'/> + <property name='cmmnt' type='boolean' value='true' migratable='yes'/> + <property name='aefsi' type='boolean' value='true' migratable='yes'/> + <property name='mepoch' type='boolean' value='true' migratable='yes'/> + <property name='msa8' type='boolean' value='true' migratable='yes'/> + <property name='msa7' type='boolean' value='true' migratable='yes'/> + <property name='msa6' type='boolean' value='true' migratable='yes'/> + <property name='msa5' type='boolean' value='true' migratable='yes'/> + <property name='msa4' type='boolean' value='true' migratable='yes'/> + <property name='msa3' type='boolean' value='true' migratable='yes'/> + <property name='msa2' type='boolean' value='true' migratable='yes'/> + <property name='msa1' type='boolean' value='true' migratable='yes'/> + <property name='sthyi' type='boolean' value='true' migratable='yes'/> + <property name='edat' type='boolean' value='true' migratable='yes'/> + <property name='ri' type='boolean' value='true' migratable='yes'/> + <property name='edat2' type='boolean' value='true' migratable='yes'/> + <property name='vx' type='boolean' value='true' migratable='yes'/> + <property name='ipter' type='boolean' value='true' migratable='yes'/> + <property name='vxeh' type='boolean' value='true' migratable='yes'/> + <property name='vxpd' type='boolean' value='true' migratable='yes'/> + <property name='esop' type='boolean' value='true' migratable='yes'/> + <property name='iep' type='boolean' value='true' migratable='yes'/> + <property name='cte' type='boolean' value='true' migratable='yes'/> + <property name='ais' type='boolean' value='true' migratable='yes'/> + <property name='gs' type='boolean' value='true' migratable='yes'/> + <property name='zpci' type='boolean' value='true' migratable='yes'/> + <property name='sea_esop2' type='boolean' value='true' migratable='yes'/> + <property name='te' type='boolean' value='true' migratable='yes'/> + <property name='cmm' type='boolean' value='true' migratable='yes'/> </hostCPU> <cpu type='kvm' name='z10EC-base' usable='yes'/> <cpu type='kvm' name='z9EC-base' usable='yes'/> diff --git a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml index 4eb8a39d94..d63f56be7d 100644 --- a/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.11.0.s390x.xml @@ -125,35 +125,35 @@ <microcodeVersion>345099</microcodeVersion> <package></package> <arch>s390x</arch> - <hostCPU type='kvm' model='z14-base' migratability='no'> - <property name='aen' type='boolean' value='true'/> - <property name='cmmnt' type='boolean' value='true'/> - <property name='aefsi' type='boolean' value='true'/> - <property name='mepoch' type='boolean' value='true'/> - <property name='msa8' type='boolean' value='true'/> - <property name='msa7' type='boolean' value='true'/> - <property name='msa6' type='boolean' value='true'/> - <property name='msa5' type='boolean' value='true'/> - <property name='msa4' type='boolean' value='true'/> - <property name='msa3' type='boolean' value='true'/> - <property name='msa2' type='boolean' value='true'/> - <property name='msa1' type='boolean' value='true'/> - <property name='sthyi' type='boolean' value='true'/> - <property name='edat' type='boolean' value='true'/> - <property name='ri' type='boolean' value='true'/> - <property name='edat2' type='boolean' value='true'/> - <property name='vx' type='boolean' value='true'/> - <property name='ipter' type='boolean' value='true'/> - <property name='vxeh' type='boolean' value='true'/> - <property name='vxpd' type='boolean' value='true'/> - <property name='esop' type='boolean' value='true'/> - <property name='iep' type='boolean' value='true'/> - <property name='cte' type='boolean' value='true'/> - <property name='gs' type='boolean' value='true'/> - <property name='zpci' type='boolean' value='true'/> - <property name='sea_esop2' type='boolean' value='true'/> - <property name='te' type='boolean' value='true'/> - <property name='cmm' type='boolean' value='true'/> + <hostCPU type='kvm' model='z14-base' migratability='yes'> + <property name='aen' type='boolean' value='true' migratable='yes'/> + <property name='cmmnt' type='boolean' value='true' migratable='yes'/> + <property name='aefsi' type='boolean' value='true' migratable='yes'/> + <property name='mepoch' type='boolean' value='true' migratable='yes'/> + <property name='msa8' type='boolean' value='true' migratable='yes'/> + <property name='msa7' type='boolean' value='true' migratable='yes'/> + <property name='msa6' type='boolean' value='true' migratable='yes'/> + <property name='msa5' type='boolean' value='true' migratable='yes'/> + <property name='msa4' type='boolean' value='true' migratable='yes'/> + <property name='msa3' type='boolean' value='true' migratable='yes'/> + <property name='msa2' type='boolean' value='true' migratable='yes'/> + <property name='msa1' type='boolean' value='true' migratable='yes'/> + <property name='sthyi' type='boolean' value='true' migratable='yes'/> + <property name='edat' type='boolean' value='true' migratable='yes'/> + <property name='ri' type='boolean' value='true' migratable='yes'/> + <property name='edat2' type='boolean' value='true' migratable='yes'/> + <property name='vx' type='boolean' value='true' migratable='yes'/> + <property name='ipter' type='boolean' value='true' migratable='yes'/> + <property name='vxeh' type='boolean' value='true' migratable='yes'/> + <property name='vxpd' type='boolean' value='true' migratable='yes'/> + <property name='esop' type='boolean' value='true' migratable='yes'/> + <property name='iep' type='boolean' value='true' migratable='yes'/> + <property name='cte' type='boolean' value='true' migratable='yes'/> + <property name='gs' type='boolean' value='true' migratable='yes'/> + <property name='zpci' type='boolean' value='true' migratable='yes'/> + <property name='sea_esop2' type='boolean' value='true' migratable='yes'/> + <property name='te' type='boolean' value='true' migratable='yes'/> + <property name='cmm' type='boolean' value='true' migratable='yes'/> </hostCPU> <cpu type='kvm' name='z890.2' usable='yes'/> <cpu type='kvm' name='z990.4' usable='yes'/> diff --git a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml index 79320d5229..ea3bce232e 100644 --- a/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.12.0.s390x.xml @@ -133,34 +133,34 @@ <microcodeVersion>374287</microcodeVersion> <package></package> <arch>s390x</arch> - <hostCPU type='kvm' model='z14-base' migratability='no'> - <property name='aen' type='boolean' value='true'/> - <property name='aefsi' type='boolean' value='true'/> - <property name='msa8' type='boolean' value='true'/> - <property name='msa7' type='boolean' value='true'/> - <property name='msa6' type='boolean' value='true'/> - <property name='msa5' type='boolean' value='true'/> - <property name='msa4' type='boolean' value='true'/> - <property name='msa3' type='boolean' value='true'/> - <property name='msa2' type='boolean' value='true'/> - <property name='msa1' type='boolean' value='true'/> - <property name='sthyi' type='boolean' value='true'/> - <property name='edat' type='boolean' value='true'/> - <property name='ri' type='boolean' value='true'/> - <property name='edat2' type='boolean' value='true'/> - <property name='vx' type='boolean' value='true'/> - <property name='ipter' type='boolean' value='true'/> - <property name='vxeh' type='boolean' value='true'/> - <property name='vxpd' type='boolean' value='true'/> - <property name='esop' type='boolean' value='true'/> - <property name='iep' type='boolean' value='true'/> - <property name='cte' type='boolean' value='true'/> - <property name='gs' type='boolean' value='true'/> - <property name='ppa15' type='boolean' value='true'/> - <property name='zpci' type='boolean' value='true'/> - <property name='sea_esop2' type='boolean' value='true'/> - <property name='te' type='boolean' value='true'/> - <property name='cmm' type='boolean' value='true'/> + <hostCPU type='kvm' model='z14-base' migratability='yes'> + <property name='aen' type='boolean' value='true' migratable='yes'/> + <property name='aefsi' type='boolean' value='true' migratable='yes'/> + <property name='msa8' type='boolean' value='true' migratable='yes'/> + <property name='msa7' type='boolean' value='true' migratable='yes'/> + <property name='msa6' type='boolean' value='true' migratable='yes'/> + <property name='msa5' type='boolean' value='true' migratable='yes'/> + <property name='msa4' type='boolean' value='true' migratable='yes'/> + <property name='msa3' type='boolean' value='true' migratable='yes'/> + <property name='msa2' type='boolean' value='true' migratable='yes'/> + <property name='msa1' type='boolean' value='true' migratable='yes'/> + <property name='sthyi' type='boolean' value='true' migratable='yes'/> + <property name='edat' type='boolean' value='true' migratable='yes'/> + <property name='ri' type='boolean' value='true' migratable='yes'/> + <property name='edat2' type='boolean' value='true' migratable='yes'/> + <property name='vx' type='boolean' value='true' migratable='yes'/> + <property name='ipter' type='boolean' value='true' migratable='yes'/> + <property name='vxeh' type='boolean' value='true' migratable='yes'/> + <property name='vxpd' type='boolean' value='true' migratable='yes'/> + <property name='esop' type='boolean' value='true' migratable='yes'/> + <property name='iep' type='boolean' value='true' migratable='yes'/> + <property name='cte' type='boolean' value='true' migratable='yes'/> + <property name='gs' type='boolean' value='true' migratable='yes'/> + <property name='ppa15' type='boolean' value='true' migratable='yes'/> + <property name='zpci' type='boolean' value='true' migratable='yes'/> + <property name='sea_esop2' type='boolean' value='true' migratable='yes'/> + <property name='te' type='boolean' value='true' migratable='yes'/> + <property name='cmm' type='boolean' value='true' migratable='yes'/> </hostCPU> <cpu type='kvm' name='z890.2' usable='yes'/> <cpu type='kvm' name='z990.4' usable='yes'/> diff --git a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml index b010f731a5..858bc49918 100644 --- a/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.8.0.s390x.xml @@ -108,22 +108,22 @@ <microcodeVersion>244554</microcodeVersion> <package></package> <arch>s390x</arch> - <hostCPU type='kvm' model='zEC12.2-base' migratability='no'> - <property name='aefsi' type='boolean' value='true'/> - <property name='msa5' type='boolean' value='true'/> - <property name='msa4' type='boolean' value='true'/> - <property name='msa3' type='boolean' value='true'/> - <property name='msa2' type='boolean' value='true'/> - <property name='msa1' type='boolean' value='true'/> - <property name='sthyi' type='boolean' value='true'/> - <property name='edat' type='boolean' value='true'/> - <property name='ri' type='boolean' value='true'/> - <property name='edat2' type='boolean' value='true'/> - <property name='ipter' type='boolean' value='true'/> - <property name='esop' type='boolean' value='true'/> - <property name='cte' type='boolean' value='true'/> - <property name='te' type='boolean' value='true'/> - <property name='cmm' type='boolean' value='true'/> + <hostCPU type='kvm' model='zEC12.2-base' migratability='yes'> + <property name='aefsi' type='boolean' value='true' migratable='yes'/> + <property name='msa5' type='boolean' value='true' migratable='yes'/> + <property name='msa4' type='boolean' value='true' migratable='yes'/> + <property name='msa3' type='boolean' value='true' migratable='yes'/> + <property name='msa2' type='boolean' value='true' migratable='yes'/> + <property name='msa1' type='boolean' value='true' migratable='yes'/> + <property name='sthyi' type='boolean' value='true' migratable='yes'/> + <property name='edat' type='boolean' value='true' migratable='yes'/> + <property name='ri' type='boolean' value='true' migratable='yes'/> + <property name='edat2' type='boolean' value='true' migratable='yes'/> + <property name='ipter' type='boolean' value='true' migratable='yes'/> + <property name='esop' type='boolean' value='true' migratable='yes'/> + <property name='cte' type='boolean' value='true' migratable='yes'/> + <property name='te' type='boolean' value='true' migratable='yes'/> + <property name='cmm' type='boolean' value='true' migratable='yes'/> </hostCPU> <cpu type='kvm' name='z10EC-base'/> <cpu type='kvm' name='z9EC-base'/> diff --git a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml index 5a4371ab83..621036c914 100644 --- a/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_2.9.0.s390x.xml @@ -112,23 +112,23 @@ <microcodeVersion>267973</microcodeVersion> <package></package> <arch>s390x</arch> - <hostCPU type='kvm' model='z13.2-base' migratability='no'> - <property name='aefsi' type='boolean' value='true'/> - <property name='msa5' type='boolean' value='true'/> - <property name='msa4' type='boolean' value='true'/> - <property name='msa3' type='boolean' value='true'/> - <property name='msa2' type='boolean' value='true'/> - <property name='msa1' type='boolean' value='true'/> - <property name='sthyi' type='boolean' value='true'/> - <property name='edat' type='boolean' value='true'/> - <property name='ri' type='boolean' value='true'/> - <property name='edat2' type='boolean' value='true'/> - <property name='vx' type='boolean' value='true'/> - <property name='ipter' type='boolean' value='true'/> - <property name='esop' type='boolean' value='true'/> - <property name='cte' type='boolean' value='true'/> - <property name='te' type='boolean' value='true'/> - <property name='cmm' type='boolean' value='true'/> + <hostCPU type='kvm' model='z13.2-base' migratability='yes'> + <property name='aefsi' type='boolean' value='true' migratable='yes'/> + <property name='msa5' type='boolean' value='true' migratable='yes'/> + <property name='msa4' type='boolean' value='true' migratable='yes'/> + <property name='msa3' type='boolean' value='true' migratable='yes'/> + <property name='msa2' type='boolean' value='true' migratable='yes'/> + <property name='msa1' type='boolean' value='true' migratable='yes'/> + <property name='sthyi' type='boolean' value='true' migratable='yes'/> + <property name='edat' type='boolean' value='true' migratable='yes'/> + <property name='ri' type='boolean' value='true' migratable='yes'/> + <property name='edat2' type='boolean' value='true' migratable='yes'/> + <property name='vx' type='boolean' value='true' migratable='yes'/> + <property name='ipter' type='boolean' value='true' migratable='yes'/> + <property name='esop' type='boolean' value='true' migratable='yes'/> + <property name='cte' type='boolean' value='true' migratable='yes'/> + <property name='te' type='boolean' value='true' migratable='yes'/> + <property name='cmm' type='boolean' value='true' migratable='yes'/> </hostCPU> <cpu type='kvm' name='z10EC-base'/> <cpu type='kvm' name='z9EC-base'/> diff --git a/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml b/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml index 3b5f9818a5..7bb42d211c 100644 --- a/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml +++ b/tests/qemucapabilitiesdata/caps_3.0.0.s390x.xml @@ -135,38 +135,38 @@ <microcodeVersion>387601</microcodeVersion> <package></package> <arch>s390x</arch> - <hostCPU type='kvm' model='z14-base' migratability='no'> - <property name='aen' type='boolean' value='true'/> - <property name='cmmnt' type='boolean' value='true'/> - <property name='aefsi' type='boolean' value='true'/> - <property name='mepoch' type='boolean' value='true'/> - <property name='msa8' type='boolean' value='true'/> - <property name='msa7' type='boolean' value='true'/> - <property name='msa6' type='boolean' value='true'/> - <property name='msa5' type='boolean' value='true'/> - <property name='msa4' type='boolean' value='true'/> - <property name='msa3' type='boolean' value='true'/> - <property name='msa2' type='boolean' value='true'/> - <property name='msa1' type='boolean' value='true'/> - <property name='sthyi' type='boolean' value='true'/> - <property name='edat' type='boolean' value='true'/> - <property name='ri' type='boolean' value='true'/> - <property name='edat2' type='boolean' value='true'/> - <property name='vx' type='boolean' value='true'/> - <property name='ipter' type='boolean' value='true'/> - <property name='mepochptff' type='boolean' value='true'/> - <property name='vxeh' type='boolean' value='true'/> - <property name='vxpd' type='boolean' value='true'/> - <property name='esop' type='boolean' value='true'/> - <property name='iep' type='boolean' value='true'/> - <property name='cte' type='boolean' value='true'/> - <property name='bpb' type='boolean' value='true'/> - <property name='gs' type='boolean' value='true'/> - <property name='ppa15' type='boolean' value='true'/> - <property name='zpci' type='boolean' value='true'/> - <property name='sea_esop2' type='boolean' value='true'/> - <property name='te' type='boolean' value='true'/> - <property name='cmm' type='boolean' value='true'/> + <hostCPU type='kvm' model='z14-base' migratability='yes'> + <property name='aen' type='boolean' value='true' migratable='yes'/> + <property name='cmmnt' type='boolean' value='true' migratable='yes'/> + <property name='aefsi' type='boolean' value='true' migratable='yes'/> + <property name='mepoch' type='boolean' value='true' migratable='yes'/> + <property name='msa8' type='boolean' value='true' migratable='yes'/> + <property name='msa7' type='boolean' value='true' migratable='yes'/> + <property name='msa6' type='boolean' value='true' migratable='yes'/> + <property name='msa5' type='boolean' value='true' migratable='yes'/> + <property name='msa4' type='boolean' value='true' migratable='yes'/> + <property name='msa3' type='boolean' value='true' migratable='yes'/> + <property name='msa2' type='boolean' value='true' migratable='yes'/> + <property name='msa1' type='boolean' value='true' migratable='yes'/> + <property name='sthyi' type='boolean' value='true' migratable='yes'/> + <property name='edat' type='boolean' value='true' migratable='yes'/> + <property name='ri' type='boolean' value='true' migratable='yes'/> + <property name='edat2' type='boolean' value='true' migratable='yes'/> + <property name='vx' type='boolean' value='true' migratable='yes'/> + <property name='ipter' type='boolean' value='true' migratable='yes'/> + <property name='mepochptff' type='boolean' value='true' migratable='yes'/> + <property name='vxeh' type='boolean' value='true' migratable='yes'/> + <property name='vxpd' type='boolean' value='true' migratable='yes'/> + <property name='esop' type='boolean' value='true' migratable='yes'/> + <property name='iep' type='boolean' value='true' migratable='yes'/> + <property name='cte' type='boolean' value='true' migratable='yes'/> + <property name='bpb' type='boolean' value='true' migratable='yes'/> + <property name='gs' type='boolean' value='true' migratable='yes'/> + <property name='ppa15' type='boolean' value='true' migratable='yes'/> + <property name='zpci' type='boolean' value='true' migratable='yes'/> + <property name='sea_esop2' type='boolean' value='true' migratable='yes'/> + <property name='te' type='boolean' value='true' migratable='yes'/> + <property name='cmm' type='boolean' value='true' migratable='yes'/> </hostCPU> <cpu type='kvm' name='z890.2' usable='yes'/> <cpu type='kvm' name='z990.4' usable='yes'/> -- 2.17.1

Quoting Chris Venteicher (2018-11-02 22:13:01)
Some architectures (S390) depend on QEMU to compute baseline CPU model and expand a models feature set.
Interacting with QEMU requires starting the QEMU process and completing one or more query-cpu-model-baseline QMP exchanges with QEMU in addition to a query-cpu-model-expansion QMP exchange to expand all features in the model.
See "s390x CPU models: exposing features" patch set on Qemu-devel for discussion of QEMU aspects.
This is part of resolution of: https://bugzilla.redhat.com/show_bug.cgi?id=1511999
Version 4 attempts to address all issues from V1,2,3 including making the QEMU process activation for QMP Queries generic (not specific to capabilities) and moving that code from qemu_capabilities to qemu_process.
Version 4 greatly expands the number of patches to make the set easier to review.
The patches to do hypervisor baseline using QEMU are primarily in qemu_driver.c
Patches 1-2 create the cpumodel to/from Json conversion code. Patches 3-4 modify the cpu expansion interface. Patches 28-36 are the actual baseline changes.
The patches to make the process code generic (not capabilities specific) are mostly in qemu_process.c
Patches 5 -> 27 move the process code from qemu_capabilities to qemu_process. A lot of these are code move or rename patches so the patches with real implementation changes are easy to identify. I might have ended up with too many patches though. Want to mention... the whole "process" block could be moved to it's own series if that would be easier to review.
Many of the patches are cut / paste of existing code. The patches that change functionality are as modular and minimal as possible to make reviewing easier.
I attempted to make the new qemu_process functions consistent with the existing domain activation qemu_process functions.
A thread safe library function creates a unique directory under libDir for each QEMU process (for QMP messaging) to decouple processes in terms of sockets and file system footprint.
The last patch is based on past discussion of QEMU cpu expansion only returning migratable features except for one x86 case where non-migratable features are explicitly requested. The patch records that features are migratable based on QEMU only returning migratable features. The main result is the CPU xml for S390 CPU's contains the same migratability info the X86 currently does. The testcases were updated to reflect the change.
Every patch should compile independently if applied in sequence.
Thanks, Chris
Chris Venteicher (37): qemu_monitor: Introduce qemuMonitorCPUModelInfoNew qemu_monitor: Introduce qemuMonitorCPUModelInfo / JSON conversion qemu_capabilities: Introduce virQEMuCapsMigratablePropsDiff qemu_monitor: qemuMonitorGetCPUModelExpansion inputs and outputs CPUModelInfo qemu_process: Move process code from qemu_capabilities to qemu_process qemu_process: Use qemuProcess prefix qemu_process: Limit qemuProcessNew to const input strings qemu_process: Refer to proc not cmd in process code qemu_process: Use consistent name for stop process function qemu_capabilities: Stop QEMU process before freeing qemu_process: Use qemuProcess struct for a single process qemu_process: Persist stderr in qemuProcess struct qemu_capabilities: Detect caps probe failure by checking monitor ptr qemu_process: Introduce qemuProcessStartQmp qemu_process: Add debug message in qemuProcessLaunchQmp qemu_process: Collect monitor code in single function qemu_process: Store libDir in qemuProcess struct qemu_process: Setup paths within qemuProcessInitQmp qemu_process: Stop retaining Qemu Monitor config in qemuProcess qemu_process: Don't open monitor if process failed qemu_process: Cleanup qemuProcess alloc function qemu_process: Cleanup qemuProcessStopQmp function qemu_process: Catch process free before process stop qemu_monitor: Make monitor callbacks optional qemu_process: Enter QMP command mode when starting QEMU Process qemu_process: Use unique directories for QMP processes qemu_process: Stop locking QMP process monitor immediately qemu_capabilities: Introduce CPUModelInfo to virCPUDef function qemu_capabilities: Introduce virCPUDef to CPUModelInfo function qemu_monitor: Support query-cpu-model-baseline QMP command qemu_driver: Consolidate code to baseline using libvirt qemu_driver: Decouple code for baseline using libvirt qemu_driver: Identify using libvirt as a distinct way to compute baseline qemu_driver: Support baseline calculation using QEMU qemu_driver: Support feature expansion via QEMU when baselining cpu qemu_driver: Remove unsupported props in expanded hypervisor baseline output qemu_monitor: Default props to migratable when expanding cpu model
src/qemu/qemu_capabilities.c | 567 ++++++++---------- src/qemu/qemu_capabilities.h | 4 + src/qemu/qemu_driver.c | 219 ++++++- src/qemu/qemu_monitor.c | 184 +++++- src/qemu/qemu_monitor.h | 29 +- src/qemu/qemu_monitor_json.c | 226 +++++-- src/qemu/qemu_monitor_json.h | 12 +- src/qemu/qemu_process.c | 359 +++++++++++ src/qemu/qemu_process.h | 37 ++ tests/cputest.c | 11 +- .../caps_2.10.0.s390x.xml | 60 +- .../caps_2.11.0.s390x.xml | 58 +- .../caps_2.12.0.s390x.xml | 56 +- .../qemucapabilitiesdata/caps_2.8.0.s390x.xml | 32 +- .../qemucapabilitiesdata/caps_2.9.0.s390x.xml | 34 +- .../qemucapabilitiesdata/caps_3.0.0.s390x.xml | 64 +- tests/qemucapabilitiestest.c | 7 + 17 files changed, 1388 insertions(+), 571 deletions(-)
-- 2.17.1

Hi Chris, On 11/9/18 11:27 AM, Chris Venteicher wrote:
Quoting Chris Venteicher (2018-11-02 22:13:01)
Some architectures (S390) depend on QEMU to compute baseline CPU model and expand a models feature set.
Interacting with QEMU requires starting the QEMU process and completing one or more query-cpu-model-baseline QMP exchanges with QEMU in addition to a query-cpu-model-expansion QMP exchange to expand all features in the model.
See "s390x CPU models: exposing features" patch set on Qemu-devel for discussion of QEMU aspects.
This is part of resolution of: https://bugzilla.redhat.com/show_bug.cgi?id=1511999
Version 4 attempts to address all issues from V1,2,3 including making the QEMU process activation for QMP Queries generic (not specific to capabilities) and moving that code from qemu_capabilities to qemu_process.
Version 4 greatly expands the number of patches to make the set easier to review.
The patches to do hypervisor baseline using QEMU are primarily in qemu_driver.c
Patches 1-2 create the cpumodel to/from Json conversion code. Patches 3-4 modify the cpu expansion interface. Patches 28-36 are the actual baseline changes.
The patches to make the process code generic (not capabilities specific) are mostly in qemu_process.c
Patches 5 -> 27 move the process code from qemu_capabilities to qemu_process.
A lot of these are code move or rename patches so the patches with real implementation changes are easy to identify.
I might have ended up with too many patches though. Want to mention... the whole "process" block could be moved to it's own series if that would be easier to review.
I've been meaning to provide an in-depth review of these patches, but other things have been holding me up -- my apologies. At a quick glance, a lot of your patches involve a few short patches that don't necessarily provide much context on their own. A lot of patches in this series can definitely be merged. I think moving the "qemu process" code into its own series would be helpful. I would include something in the cover that they will benefit the hypervisor CPU baseline and comparison patches. If you feel confident with your qemu process patches, then you could also send your baseline patch series at the same time, and state that your baseline patches rely on your QEMU process patches (make sure to include a mailing list archive link in that header so reviewers can easily reference the other patch series). Also, make sure you CC the authors and contributors of the respective files that you touch. Most of them are listed at the top of the file. (I think Jiri might be interested in this series as well.) So let's start there. Repost your qemu_process code as it's own series, and I'd recommend tagging it with "RFC" (Request For Comments) instead of giving it a version number. This will prompt reviewers that you're mainly looking for areas of improvement and some guidance.
Many of the patches are cut / paste of existing code. The patches that change functionality are as modular and minimal as possible to make reviewing easier.
I attempted to make the new qemu_process functions consistent with the existing domain activation qemu_process functions.
A thread safe library function creates a unique directory under libDir for each QEMU process (for QMP messaging) to decouple processes in terms of sockets and file system footprint.
The last patch is based on past discussion of QEMU cpu expansion only returning migratable features except for one x86 case where non-migratable features are explicitly requested. The patch records that features are migratable based on QEMU only returning migratable features. The main result is the CPU xml for S390 CPU's contains the same migratability info the X86 currently does. The testcases were updated to reflect the change.
Every patch should compile independently if applied in sequence.
Thanks, Chris
Chris Venteicher (37): qemu_monitor: Introduce qemuMonitorCPUModelInfoNew qemu_monitor: Introduce qemuMonitorCPUModelInfo / JSON conversion qemu_capabilities: Introduce virQEMuCapsMigratablePropsDiff qemu_monitor: qemuMonitorGetCPUModelExpansion inputs and outputs CPUModelInfo qemu_process: Move process code from qemu_capabilities to qemu_process qemu_process: Use qemuProcess prefix qemu_process: Limit qemuProcessNew to const input strings qemu_process: Refer to proc not cmd in process code qemu_process: Use consistent name for stop process function qemu_capabilities: Stop QEMU process before freeing qemu_process: Use qemuProcess struct for a single process qemu_process: Persist stderr in qemuProcess struct qemu_capabilities: Detect caps probe failure by checking monitor ptr qemu_process: Introduce qemuProcessStartQmp qemu_process: Add debug message in qemuProcessLaunchQmp qemu_process: Collect monitor code in single function qemu_process: Store libDir in qemuProcess struct qemu_process: Setup paths within qemuProcessInitQmp qemu_process: Stop retaining Qemu Monitor config in qemuProcess qemu_process: Don't open monitor if process failed qemu_process: Cleanup qemuProcess alloc function qemu_process: Cleanup qemuProcessStopQmp function qemu_process: Catch process free before process stop qemu_monitor: Make monitor callbacks optional qemu_process: Enter QMP command mode when starting QEMU Process qemu_process: Use unique directories for QMP processes qemu_process: Stop locking QMP process monitor immediately qemu_capabilities: Introduce CPUModelInfo to virCPUDef function qemu_capabilities: Introduce virCPUDef to CPUModelInfo function qemu_monitor: Support query-cpu-model-baseline QMP command qemu_driver: Consolidate code to baseline using libvirt qemu_driver: Decouple code for baseline using libvirt qemu_driver: Identify using libvirt as a distinct way to compute baseline qemu_driver: Support baseline calculation using QEMU qemu_driver: Support feature expansion via QEMU when baselining cpu qemu_driver: Remove unsupported props in expanded hypervisor baseline output qemu_monitor: Default props to migratable when expanding cpu model
src/qemu/qemu_capabilities.c | 567 ++++++++---------- src/qemu/qemu_capabilities.h | 4 + src/qemu/qemu_driver.c | 219 ++++++- src/qemu/qemu_monitor.c | 184 +++++- src/qemu/qemu_monitor.h | 29 +- src/qemu/qemu_monitor_json.c | 226 +++++-- src/qemu/qemu_monitor_json.h | 12 +- src/qemu/qemu_process.c | 359 +++++++++++ src/qemu/qemu_process.h | 37 ++ tests/cputest.c | 11 +- .../caps_2.10.0.s390x.xml | 60 +- .../caps_2.11.0.s390x.xml | 58 +- .../caps_2.12.0.s390x.xml | 56 +- .../qemucapabilitiesdata/caps_2.8.0.s390x.xml | 32 +- .../qemucapabilitiesdata/caps_2.9.0.s390x.xml | 34 +- .../qemucapabilitiesdata/caps_3.0.0.s390x.xml | 64 +- tests/qemucapabilitiestest.c | 7 + 17 files changed, 1388 insertions(+), 571 deletions(-)
-- 2.17.1
-- Respectfully, - Collin Walling

Quoting Collin Walling (2018-11-09 10:44:41)
Hi Chris,
On 11/9/18 11:27 AM, Chris Venteicher wrote:
Quoting Chris Venteicher (2018-11-02 22:13:01)
Some architectures (S390) depend on QEMU to compute baseline CPU model and expand a models feature set.
Interacting with QEMU requires starting the QEMU process and completing one or more query-cpu-model-baseline QMP exchanges with QEMU in addition to a query-cpu-model-expansion QMP exchange to expand all features in the model.
See "s390x CPU models: exposing features" patch set on Qemu-devel for discussion of QEMU aspects.
This is part of resolution of: https://bugzilla.redhat.com/show_bug.cgi?id=1511999
Version 4 attempts to address all issues from V1,2,3 including making the QEMU process activation for QMP Queries generic (not specific to capabilities) and moving that code from qemu_capabilities to qemu_process.
Version 4 greatly expands the number of patches to make the set easier to review.
The patches to do hypervisor baseline using QEMU are primarily in qemu_driver.c
Patches 1-2 create the cpumodel to/from Json conversion code. Patches 3-4 modify the cpu expansion interface. Patches 28-36 are the actual baseline changes.
The patches to make the process code generic (not capabilities specific) are mostly in qemu_process.c
Patches 5 -> 27 move the process code from qemu_capabilities to qemu_process.
A lot of these are code move or rename patches so the patches with real implementation changes are easy to identify.
I might have ended up with too many patches though. Want to mention... the whole "process" block could be moved to it's own series if that would be easier to review.
I've been meaning to provide an in-depth review of these patches, but other things have been holding me up -- my apologies.
At a quick glance, a lot of your patches involve a few short patches that don't necessarily provide much context on their own. A lot of patches in this series can definitely be merged.
I think moving the "qemu process" code into its own series would be helpful. I would include something in the cover that they will benefit the hypervisor CPU baseline and comparison patches. If you feel confident with your qemu process patches, then you could also send your baseline patch series at the same time, and state that your baseline patches rely on your QEMU process patches (make sure to include a mailing list archive link in that header so reviewers can easily reference the other patch series).
Also, make sure you CC the authors and contributors of the respective files that you touch. Most of them are listed at the top of the file. (I think Jiri might be interested in this series as well.)
So let's start there. Repost your qemu_process code as it's own series, and I'd recommend tagging it with "RFC" (Request For Comments) instead of giving it a version number. This will prompt reviewers that you're mainly looking for areas of improvement and some guidance.
Thanks Collin, The process stuff has been resubmitted in this patch series: [PATCH RFC 00/22] Move process code to qemu_process The rest of this series can be resubmitted when the process changes are solid.
Many of the patches are cut / paste of existing code. The patches that change functionality are as modular and minimal as possible to make reviewing easier.
I attempted to make the new qemu_process functions consistent with the existing domain activation qemu_process functions.
A thread safe library function creates a unique directory under libDir for each QEMU process (for QMP messaging) to decouple processes in terms of sockets and file system footprint.
The last patch is based on past discussion of QEMU cpu expansion only returning migratable features except for one x86 case where non-migratable features are explicitly requested. The patch records that features are migratable based on QEMU only returning migratable features. The main result is the CPU xml for S390 CPU's contains the same migratability info the X86 currently does. The testcases were updated to reflect the change.
Every patch should compile independently if applied in sequence.
Thanks, Chris
Chris Venteicher (37): qemu_monitor: Introduce qemuMonitorCPUModelInfoNew qemu_monitor: Introduce qemuMonitorCPUModelInfo / JSON conversion qemu_capabilities: Introduce virQEMuCapsMigratablePropsDiff qemu_monitor: qemuMonitorGetCPUModelExpansion inputs and outputs CPUModelInfo qemu_process: Move process code from qemu_capabilities to qemu_process qemu_process: Use qemuProcess prefix qemu_process: Limit qemuProcessNew to const input strings qemu_process: Refer to proc not cmd in process code qemu_process: Use consistent name for stop process function qemu_capabilities: Stop QEMU process before freeing qemu_process: Use qemuProcess struct for a single process qemu_process: Persist stderr in qemuProcess struct qemu_capabilities: Detect caps probe failure by checking monitor ptr qemu_process: Introduce qemuProcessStartQmp qemu_process: Add debug message in qemuProcessLaunchQmp qemu_process: Collect monitor code in single function qemu_process: Store libDir in qemuProcess struct qemu_process: Setup paths within qemuProcessInitQmp qemu_process: Stop retaining Qemu Monitor config in qemuProcess qemu_process: Don't open monitor if process failed qemu_process: Cleanup qemuProcess alloc function qemu_process: Cleanup qemuProcessStopQmp function qemu_process: Catch process free before process stop qemu_monitor: Make monitor callbacks optional qemu_process: Enter QMP command mode when starting QEMU Process qemu_process: Use unique directories for QMP processes qemu_process: Stop locking QMP process monitor immediately qemu_capabilities: Introduce CPUModelInfo to virCPUDef function qemu_capabilities: Introduce virCPUDef to CPUModelInfo function qemu_monitor: Support query-cpu-model-baseline QMP command qemu_driver: Consolidate code to baseline using libvirt qemu_driver: Decouple code for baseline using libvirt qemu_driver: Identify using libvirt as a distinct way to compute baseline qemu_driver: Support baseline calculation using QEMU qemu_driver: Support feature expansion via QEMU when baselining cpu qemu_driver: Remove unsupported props in expanded hypervisor baseline output qemu_monitor: Default props to migratable when expanding cpu model
src/qemu/qemu_capabilities.c | 567 ++++++++---------- src/qemu/qemu_capabilities.h | 4 + src/qemu/qemu_driver.c | 219 ++++++- src/qemu/qemu_monitor.c | 184 +++++- src/qemu/qemu_monitor.h | 29 +- src/qemu/qemu_monitor_json.c | 226 +++++-- src/qemu/qemu_monitor_json.h | 12 +- src/qemu/qemu_process.c | 359 +++++++++++ src/qemu/qemu_process.h | 37 ++ tests/cputest.c | 11 +- .../caps_2.10.0.s390x.xml | 60 +- .../caps_2.11.0.s390x.xml | 58 +- .../caps_2.12.0.s390x.xml | 56 +- .../qemucapabilitiesdata/caps_2.8.0.s390x.xml | 32 +- .../qemucapabilitiesdata/caps_2.9.0.s390x.xml | 34 +- .../qemucapabilitiesdata/caps_3.0.0.s390x.xml | 64 +- tests/qemucapabilitiestest.c | 7 + 17 files changed, 1388 insertions(+), 571 deletions(-)
-- 2.17.1
-- Respectfully, - Collin Walling
participants (2)
-
Chris Venteicher
-
Collin Walling