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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list