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@xxxxxxxxxx> --- src/qemu/qemu_capabilities.c | 125 ++++++++++++++++++++++++----------- src/qemu/qemu_monitor.c | 47 +++++++++++-- src/qemu/qemu_monitor.h | 5 +- src/qemu/qemu_monitor_json.c | 20 ++++-- src/qemu/qemu_monitor_json.h | 6 +- tests/cputest.c | 11 ++- 6 files changed, 156 insertions(+), 58 deletions(-) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index e60a4b369e..d38530ca80 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -2352,15 +2352,82 @@ virQEMUCapsProbeQMPCPUDefinitions(virQEMUCapsPtr qemuCaps, return 0; } +/* virQEMUCapsMigratablePropsDiff + * @migratable: migratable props=true, non-migratable & unsupported props=false + * @nonMigratable: migratable & non-migratable props = true, unsupported props = false + * @augmented: prop->migratable = VIR_TRISTATE_BOOL_{YES/NO} base on diff + * + * Use differences in Expanded CPUModelInfo inputs + * to augment with prop->migratable in CPUModelInfo output + */ +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 input; + qemuMonitorCPUModelInfoPtr migratable = NULL; qemuMonitorCPUModelInfoPtr nonMigratable = NULL; - virHashTablePtr hash = NULL; + qemuMonitorCPUModelInfoPtr augmented = NULL; const char *model; qemuMonitorCPUModelExpansionType type; virDomainVirtType virtType; @@ -2380,6 +2447,8 @@ 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 * preferred spelling, thus we need to do a full expansion on the result of @@ -2390,54 +2459,30 @@ virQEMUCapsProbeQMPHostCPU(virQEMUCapsPtr qemuCaps, else type = QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC; - if (qemuMonitorGetCPUModelExpansion(mon, type, model, true, &modelInfo) < 0) + if (!(input = qemuMonitorCPUModelInfoNew(model)) || + qemuMonitorGetCPUModelExpansion(mon, type, true, input, &migratable) < 0) goto cleanup; - /* Try to check migratability of each feature. */ - if (modelInfo && - qemuMonitorGetCPUModelExpansion(mon, type, model, false, - &nonMigratable) < 0) + if (!migratable) { + ret = 0; /* Qemu can't expand the model name, exit without error */ 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; - } - } + /* Try to check migratability of each feature. */ + if (qemuMonitorGetCPUModelExpansion(mon, type, false, input, &nonMigratable) < 0) + goto cleanup; - 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(input); + qemuMonitorCPUModelInfoFree(migratable); qemuMonitorCPUModelInfoFree(nonMigratable); - qemuMonitorCPUModelInfoFree(modelInfo); + qemuMonitorCPUModelInfoFree(augmented); return ret; } diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 801c072eff..c64b3ad38a 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3653,20 +3653,57 @@ qemuMonitorCPUDefInfoFree(qemuMonitorCPUDefInfoPtr cpu) } +/** + * qemuMonitorGetCPUModelExpansion: + * @mon: + * @type: qemuMonitorCPUModelExpansionType + * @migratable: Prompt QEMU to include non-migratable features for X86 models if false. + * @input: Non-expanded input model + * @expansion: Expanded output model (or NULL if QEMU rejects model / request) + * + * CPU property lists are computed from CPUModelInfo structures by 1) converting + * model->name into a property list using a static lookup table and 2) adding or + * removing properties in the resulting list from model->props. + * + * This function uses QEMU to identify a base model name that most closely + * matches the migratable CPU properties in the input CPU Model. + * + * This function also uses QEMU to enumerate model->props in various ways based + * on the qemuMonitorCPUModelExpansionType. + * + * full_input_props = LookupProps(input->name) then +/- input->props + * + * migratable_input_props = full_input_props - non_migratable_input_props + * + * base_model = FindClosestBaseModel(migratable_input_props) + * + * expansion->name = base_model->name + * + * @type == QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC + * expansion->props = props to +/- to base_model to approximate migratable_input_props + * + * @type == QEMU_MONITOR_CPU_MODEL_EXPANSION_FULL + * expansion->props = full_input_props + * + * @type == QEMU_MONITOR_CPU_MODEL_EXPANSION_STATIC_FULL + * expansion->props = migratable_input_props + * + * Returns 0 in case of success, -1 in case of failure + */ 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..4e6e220a8c 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -5600,12 +5600,17 @@ qemuMonitorJSONBuildCPUModelInfoFromJSON(virJSONValuePtr cpu_model) return ret; } + +/* return: + * -1 - Execution Failure + * 0 - Success + */ 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 +5618,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 +5690,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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list