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(a)redhat.com>
---
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