[libvirt] [PATCHv2 05/11] qemu_monitor: CPUModelExpansion on both model name and properties
Jiri Denemark
jdenemar at redhat.com
Thu Jul 12 16:26:32 UTC 2018
On Mon, Jul 09, 2018 at 22:56:49 -0500, Chris Venteicher wrote:
> Send both model name and a set of features/properties to QEMU for
> expansion rather than just the model name.
>
> Required to expand name+props models of the form computed by baseline
> into fully expanded (all props/features listed) output.
This patch is doing too much at once and is quite hard to review.
> ---
> src/qemu/qemu_capabilities.c | 42 +++++++++++++++++-----
> src/qemu/qemu_monitor.c | 38 ++++++++++++++++----
> src/qemu/qemu_monitor.h | 5 ++-
> src/qemu/qemu_monitor_json.c | 69 ++++++++++++++++++++++++------------
> src/qemu/qemu_monitor_json.h | 7 ++--
> tests/cputest.c | 7 +++-
> 6 files changed, 122 insertions(+), 46 deletions(-)
>
> diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
> index 3d78e2e29b..72ab012a78 100644
> --- a/src/qemu/qemu_capabilities.c
> +++ b/src/qemu/qemu_capabilities.c
> @@ -2343,23 +2343,32 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps,
> qemuMonitorCPUModelInfoPtr modelInfo = NULL;
> qemuMonitorCPUModelInfoPtr nonMigratable = NULL;
> virHashTablePtr hash = NULL;
> - const char *model;
> + const char *model_name;
Why? If we really want to do this, it should go into a separate patch
explaining why it is needed.
> qemuMonitorCPUModelExpansionType type;
> virDomainVirtType virtType;
> virQEMUCapsHostCPUDataPtr cpuData;
> int ret = -1;
> + int err = -1;
We usually call such variable 'rc' and leave it uninitialized.
>
> if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION))
> return 0;
>
> if (tcg || !virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) {
> virtType = VIR_DOMAIN_VIRT_QEMU;
> - model = "max";
> + model_name = "max";
> } else {
> virtType = VIR_DOMAIN_VIRT_KVM;
> - model = "host";
> + model_name = "host";
> }
>
> + if ((VIR_ALLOC(modelInfo) < 0) ||
> + (VIR_ALLOC(nonMigratable) < 0))
> + goto cleanup;
> +
> + if ((qemuMonitorCPUModelInfoInit(model_name, modelInfo) < 0) ||
> + (qemuMonitorCPUModelInfoInit(model_name, nonMigratable) < 0))
> + goto cleanup;
Redundant parentheses. But anyway, VIR_ALLOC +
qemuMonitorCPUModelInfoInit combo should be replaced with a single
qemuMonitorCPUModelInfoNew function which would do both. As a bonus
point, you could never end up with a non-NULL modelInfo structure with
name == NULL.
> +
> cpuData = virQEMUCapsGetHostCPUData(qemuCaps, virtType);
>
> /* Some x86_64 features defined in cpu_map.xml use spelling which differ
> @@ -2372,16 +2381,31 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps,
> else
> type = QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC;
>
> - if (qemuMonitorGetCPUModelExpansion(mon, type, model, true, &modelInfo) < 0)
> + if ((err = qemuMonitorGetCPUModelExpansion(mon, type, true, modelInfo)) < 0)
> goto cleanup;
>
> - /* Try to check migratability of each feature. */
> - if (modelInfo &&
> - qemuMonitorGetCPUModelExpansion(mon, type, model, false,
> - &nonMigratable) < 0)
> + if (err == 1) {
> + ret = 0; /* Qemu can't do expansion 1, exit without error */
> + goto cleanup; /* We don't have info so don't update cpuData->info */
> + }
It's not very clear to me why qemuMonitorGetCPUModelExpansion needs to
report 1. A separate patch with an explanation would be better.
> +
> + if ((err = qemuMonitorGetCPUModelExpansion(mon, type, false, nonMigratable)) < 0)
> goto cleanup;
>
> - if (nonMigratable) {
> + /* Try to check migratability of each feature */
> + /* Expansion 1 sets migratable features true
> + * Expansion 2 sets migratable and non-migratable features true
> + * (non-migratable set true only in some archs like X86)
> + *
> + * If delta between Expansion 1 and 2 exists...
> + * - both migratable and non-migratable features set prop->value = true
> + * - migratable features set prop->migatable = VIR_TRISTATE_BOOL_YES
> + * - non-migratable features set prop->migatable = VIR_TRISTATE_BOOL_NO
> + */
> + if (err == 0) {
> + /* Expansion 2 succeded
> + * Qemu expanded both migratable and nonMigratable features */
This comment seems redundant. It's pretty clear from the code that both
expansions were successful at this point.
> +
> qemuMonitorCPUPropertyPtr prop;
> qemuMonitorCPUPropertyPtr nmProp;
> size_t i;
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index 2d9297c3a7..91b946c8b4 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -3619,20 +3619,46 @@ qemuMonitorCPUDefInfoFree(qemuMonitorCPUDefInfoPtr cpu)
> }
>
>
> +/*
> + * type static:
> + * Expand to static base model + delta property changes
> + * Returned model is invariant and migration safe
> + *
> + * model_info->name = base model name
> + * model_info->props = features to +/- to base model to achive model_name
> + *
> + * type full:
> + * Expand model to enumerate all properties
> + * Returned model isn't guaranteed to be invariant or migration safe.
> + *
> + * model_info->name = base model name
> + * model_info->props = features to +/- to empty set to achive model_name
> + *
> + * type static_full:
> + * Expand to static base model + delta property changes (pass 0)
> + * Expand model to enumerate all properties (pass 1)
> + * Returned model is invariant and migration safe
> + *
> + * model_info->name = base model name
> + * model_info->props = features to +/- to empty set to achive model_name
> + *
> + * migratable_only:
> + * true: QEMU excludes non-migratable features
> + * false: QEMU includes non-migratable features for some archs like X86
> + */
Function description in our public API format and using real
qemuMonitorCPUModelExpansionType values would be a lot better.
> int
> qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon,
> qemuMonitorCPUModelExpansionType type,
> - const char *model_name,
> - bool migratable,
> - qemuMonitorCPUModelInfoPtr *model_info)
> + bool migratable_only,
Why do you need to rename migratable as migratable_only? The migratable
bool selects whether the CPU model returned by QEMU has to be migratable
or not. In any case it would be a separate change.
> + qemuMonitorCPUModelInfoPtr model_info)
If you keep the double pointer there, you could remove some hacks and
comments to explain these hacks in the JSON monitor implementation. And
you wouldn't need to introduce qemuMonitorCPUModelInfoFreeContents.
> {
> VIR_DEBUG("type=%d model_name=%s migratable=%d",
> - type, model_name, migratable);
> + type, (model_info ? NULLSTR(model_info->name):"NULL"),
The function is not supposed to be called with model_info == NULL, the
check here is useless. Not to mention that if model_info was NULL,
qemuMonitorJSONGetCPUModelExpansion would segfault anyway.
And I believe the model_info->name can't be NULL either.
All this would of course change with the double pointer and additionally
this function should check a proper value was passed in.
> + migratable_only);
>
> QEMU_CHECK_MONITOR(mon);
>
> - return qemuMonitorJSONGetCPUModelExpansion(mon, type, model_name,
> - migratable, model_info);
> + return qemuMonitorJSONGetCPUModelExpansion(mon, type, migratable_only, model_info);
> }
>
>
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index 0b84a91fbc..6b4b527512 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -1016,9 +1016,8 @@ typedef enum {
>
> int qemuMonitorGetCPUModelExpansion(qemuMonitorPtr mon,
> qemuMonitorCPUModelExpansionType type,
> - const char *model_name,
> - bool migratable,
> - qemuMonitorCPUModelInfoPtr *model_info);
> + bool migratable_only,
> + qemuMonitorCPUModelInfoPtr model_info);
>
> void qemuMonitorCPUModelInfoFree(qemuMonitorCPUModelInfoPtr model_info);
> void qemuMonitorCPUModelInfoFreeContents(qemuMonitorCPUModelInfoPtr model_info);
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 90d43eee97..9b681f4592 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -5390,8 +5390,11 @@ qemuMonitorJSONBuildCPUModelInfoToJSON(qemuMonitorCPUModelInfoPtr model)
> }
> }
>
> - ignore_value(virJSONValueObjectCreate(&model_json, "s:name", model->name,
> - "a:props", &cpu_props, NULL));
> + if (model->nprops > 0)
> + ignore_value(virJSONValueObjectCreate(&model_json, "s:name", model->name,
> + "a:props", &cpu_props, NULL));
> + else
> + ignore_value(virJSONValueObjectCreate(&model_json, "s:name", model->name, NULL));
Just don't fill in cpu_props at all and then you can use "A:props" to
cover both cases. Anyway, this can be done in a separate patch.
>
> cleanup:
> virJSONValueFree(cpu_props);
> @@ -5440,38 +5443,52 @@ qemuMonitorJSONBuildCPUModelInfoFromJSON(virJSONValuePtr cpu_model)
> return model;
> }
>
> +
> +/* return:
> + * -1 - Execution Failure
> + * 0 - Success
> + * 1 - Qemu unable to do expansion leaving "model" unmodified
> + */
> int
> qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon,
> qemuMonitorCPUModelExpansionType type,
> - const char *model_name,
> - bool migratable,
> - qemuMonitorCPUModelInfoPtr *model_info)
> + bool migratable_only,
> + qemuMonitorCPUModelInfoPtr model)
> {
> int ret = -1;
> - virJSONValuePtr model = NULL;
> - virJSONValuePtr props = NULL;
> + virJSONValuePtr json_model = NULL;
> virJSONValuePtr cmd = NULL;
> virJSONValuePtr reply = NULL;
> virJSONValuePtr data;
> virJSONValuePtr cpu_model;
> + qemuMonitorCPUModelInfoPtr expanded_model = NULL;
> + qemuMonitorCPUModelInfoPtr model_info = NULL;
> const char *typeStr = "";
>
> - *model_info = NULL;
> + if (!(model_info = qemuMonitorCPUModelInfoCopy(model)))
> + return -1;
> +
> + qemuMonitorCPUModelInfoFreeContents(model);
We usually don't touch output parameters until we know the function
succeeded. Double pointer would let you comply with this.
>
> - if (!(model = virJSONValueNewObject()))
> - goto cleanup;
> + if (!migratable_only) {
> + /* Add property to input CPUModelInfo causing QEMU to include
> + * non-migratable properties for some architectures like X86 */
This comment doesn't really belong here. It's the caller's decision to
run this command with appropriate arguments for each architecture.
>
> - if (virJSONValueObjectAppendString(model, "name", model_name) < 0)
> - goto cleanup;
> + qemuMonitorCPUProperty prop;
> + prop.type = QEMU_MONITOR_CPU_PROPERTY_BOOLEAN;
> + prop.value.boolean = false;
> + prop.migratable = false;
> +
> + if (VIR_STRDUP(prop.name, "migratable") < 0)
> + goto cleanup;
>
> - if (!migratable) {
> - if (!(props = virJSONValueNewObject()) ||
> - virJSONValueObjectAppendBoolean(props, "migratable", false) < 0 ||
> - virJSONValueObjectAppend(model, "props", props) < 0)
> + if (VIR_APPEND_ELEMENT(model_info->props, model_info->nprops, prop) < 0)
You'd leak prop.name here.
> goto cleanup;
> - props = NULL;
> }
>
> + if (!(json_model = qemuMonitorJSONBuildCPUModelInfoToJSON(model_info)))
> + goto cleanup;
> +
> retry:
> switch (type) {
> case QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC:
> @@ -5486,7 +5503,7 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon,
>
> if (!(cmd = qemuMonitorJSONMakeCommand("query-cpu-model-expansion",
> "s:type", typeStr,
> - "a:model", &model,
> + "a:model", &json_model,
> NULL)))
> goto cleanup;
>
> @@ -5498,7 +5515,7 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon,
> * guest architecture or it is not supported in the host environment.
> */
> if (qemuMonitorJSONHasError(reply, "GenericError")) {
> - ret = 0;
> + ret = 1;
> goto cleanup;
> }
>
> @@ -5517,7 +5534,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);
> +
> + if (!(json_model = virJSONValueCopy(cpu_model)))
> goto cleanup;
>
> virJSONValueFree(cmd);
> @@ -5526,16 +5545,20 @@ qemuMonitorJSONGetCPUModelExpansion(qemuMonitorPtr mon,
> goto retry;
> }
>
> - if (!(*model_info = qemuMonitorJSONBuildCPUModelInfoFromJSON(cpu_model)))
> + if (!(expanded_model = qemuMonitorJSONBuildCPUModelInfoFromJSON(cpu_model)))
> goto cleanup;
>
> + *model = *expanded_model; /* overwrite contents */
> +
> ret = 0;
>
> cleanup:
> + VIR_FREE(expanded_model); /* Free structure but not reused contents */
> + qemuMonitorCPUModelInfoFreeContents(model_info);
> +
> virJSONValueFree(cmd);
> virJSONValueFree(reply);
> - virJSONValueFree(model);
> - virJSONValueFree(props);
> + virJSONValueFree(json_model);
> return ret;
> }
>
> diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
> index 73e1cb6ace..9950483c5c 100644
> --- a/src/qemu/qemu_monitor_json.h
> +++ b/src/qemu/qemu_monitor_json.h
> @@ -362,10 +362,9 @@ 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);
> + bool migratable_only,
> + qemuMonitorCPUModelInfoPtr model_info)
> + ATTRIBUTE_NONNULL(4);
>
> int qemuMonitorJSONGetCPUModelBaseline(qemuMonitorPtr mon,
> qemuMonitorCPUModelInfoPtr model_a,
> diff --git a/tests/cputest.c b/tests/cputest.c
> index baf2b3c648..27727aa29e 100644
> --- a/tests/cputest.c
> +++ b/tests/cputest.c
> @@ -495,9 +495,14 @@ cpuTestMakeQEMUCaps(const struct data *data)
> if (!(testMon = qemuMonitorTestNewFromFile(json, driver.xmlopt, true)))
> goto error;
>
> + if ((VIR_ALLOC(model) < 0) ||
> + (qemuMonitorCPUModelInfoInit("host", model) < 0))
> + goto cleanup;
> +
> +
One empty line would be enough.
> if (qemuMonitorGetCPUModelExpansion(qemuMonitorTestGetMonitor(testMon),
> QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC,
> - "host", true, &model) < 0)
> + true, model) < 0)
> goto error;
>
> if (!(qemuCaps = virQEMUCapsNew()))
Jirka
More information about the libvir-list
mailing list