We're going to introduce a number of optional, pSeries-specific features, so we want to have a dedicated sub-element to avoid cluttering the <domain><features> element. Along with the generic framework, we also introduce the first actual feature: HPT (Hash Page Table) tuning. This will replace the existing <hpt> feature later on, but right now they simply co-exist without interfering with each other. Signed-off-by: Andrea Bolognani <abologna@xxxxxxxxxx> --- docs/formatdomain.html.in | 20 +++++++++ docs/schemas/domaincommon.rng | 16 +++++++ src/conf/domain_conf.c | 102 ++++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 11 +++++ src/libvirt_private.syms | 2 + src/qemu/qemu_command.c | 93 ++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_domain.c | 7 +++ 7 files changed, 251 insertions(+) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index d272cc1ba..b2584fbb0 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1768,6 +1768,9 @@ <kvm> <hidden state='on'/> </kvm> + <pseries> + <hpt resizing='required'/> + </pseries> <pvspinlock state='on'/> <gic version='2'/> <ioapic driver='qemu'/> @@ -1904,6 +1907,23 @@ </tr> </table> </dd> + <dt><code>pseries</code></dt> + <dd>Various features to change the behavior of pSeries guests. + <table class="top_table"> + <tr> + <th>Feature</th> + <th>Description</th> + <th>Value</th> + <th>Since</th> + </tr> + <tr> + <td>hpt</td> + <td>Configure HPT (Hash Page Table)</td> + <td>resizing: enabled, disabled, required</td> + <td><span class="since">4.1.0 (QEMU 2.10)</span></td> + </tr> + </table> + </dd> <dt><code>pmu</code></dt> <dd>Depending on the <code>state</code> attribute (values <code>on</code>, <code>off</code>, default <code>on</code>) enable or disable the diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 75838b581..fead6e7cc 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4703,6 +4703,9 @@ <optional> <ref name="kvm"/> </optional> + <optional> + <ref name="pseries"/> + </optional> <optional> <element name="privnet"> <empty/> @@ -5526,6 +5529,19 @@ </element> </define> + <!-- Optional pSeries features --> + <define name="pseries"> + <element name="pseries"> + <interleave> + <optional> + <element name="hpt"> + <ref name="resizing"/> + </element> + </optional> + </interleave> + </element> + </define> + <!-- Optional capabilities features --> <define name="capabilities"> <element name="capabilities"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index a1c25060f..577a804df 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -152,6 +152,7 @@ VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST, "ioapic", "hpt", "vmcoreinfo", + "pseries", ); VIR_ENUM_IMPL(virDomainCapabilitiesPolicy, VIR_DOMAIN_CAPABILITIES_POLICY_LAST, @@ -173,6 +174,11 @@ VIR_ENUM_IMPL(virDomainHyperv, VIR_DOMAIN_HYPERV_LAST, VIR_ENUM_IMPL(virDomainKVM, VIR_DOMAIN_KVM_LAST, "hidden") +VIR_ENUM_IMPL(virDomainPSeries, + VIR_DOMAIN_PSERIES_LAST, + "hpt", +); + VIR_ENUM_IMPL(virDomainCapsFeature, VIR_DOMAIN_CAPS_FEATURE_LAST, "audit_control", "audit_write", @@ -18879,6 +18885,7 @@ virDomainDefParseXML(xmlDocPtr xml, case VIR_DOMAIN_FEATURE_HYPERV: case VIR_DOMAIN_FEATURE_VMCOREINFO: case VIR_DOMAIN_FEATURE_KVM: + case VIR_DOMAIN_FEATURE_PSERIES: def->features[val] = VIR_TRISTATE_SWITCH_ON; break; @@ -19114,6 +19121,54 @@ virDomainDefParseXML(xmlDocPtr xml, VIR_FREE(nodes); } + if (def->features[VIR_DOMAIN_FEATURE_PSERIES] == VIR_TRISTATE_SWITCH_ON) { + int feature; + int value; + + if ((n = virXPathNodeSet("./features/pseries/*", ctxt, &nodes)) < 0) + goto error; + + for (i = 0; i < n; i++) { + feature = virDomainPSeriesTypeFromString((const char *) nodes[i]->name); + + if (feature < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown '%s' pSeries feature"), + nodes[i]->name); + goto error; + } + + switch ((virDomainPSeries) feature) { + case VIR_DOMAIN_PSERIES_HPT: + if (!(tmp = virXMLPropString(nodes[i], "resizing"))) { + virReportError(VIR_ERR_XML_ERROR, + _("Missing '%s' attribute for " + "'%s' pSeries feature"), + "resizing", nodes[i]->name); + goto error; + } + + if ((value = virDomainHPTResizingTypeFromString(tmp)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Invalid value '%s' for '%s' " + "attribute of '%s' pSeries feature"), + tmp, "resizing", nodes[i]->name); + goto error; + } + + def->pseries_features[feature] = VIR_TRISTATE_SWITCH_ON; + def->pseries_hpt_resizing = value; + + VIR_FREE(tmp); + break; + + case VIR_DOMAIN_PSERIES_LAST: + break; + } + } + VIR_FREE(nodes); + } + if ((n = virXPathNodeSet("./features/capabilities/*", ctxt, &nodes)) < 0) goto error; @@ -21140,6 +21195,29 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src, } } + /* pSeries features */ + if (src->features[VIR_DOMAIN_FEATURE_PSERIES] == VIR_TRISTATE_SWITCH_ON) { + for (i = 0; i < VIR_DOMAIN_PSERIES_LAST; i++) { + switch ((virDomainPSeries) i) { + case VIR_DOMAIN_PSERIES_HPT: + if (src->pseries_features[i] != dst->pseries_features[i] || + src->pseries_hpt_resizing != dst->pseries_hpt_resizing) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("State of '%s' pSeries feature differs: " + "source: '%s', destination: '%s'"), + virDomainPSeriesTypeToString(i), + virDomainHPTResizingTypeToString(src->pseries_hpt_resizing), + virDomainHPTResizingTypeToString(dst->pseries_hpt_resizing)); + return false; + } + break; + + case VIR_DOMAIN_PSERIES_LAST: + break; + } + } + } + /* ioapic */ if (src->ioapic != dst->ioapic) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, @@ -26487,6 +26565,30 @@ virDomainDefFormatInternal(virDomainDefPtr def, virBufferAddLit(buf, "</kvm>\n"); break; + case VIR_DOMAIN_FEATURE_PSERIES: + if (def->features[i] != VIR_TRISTATE_SWITCH_ON) + break; + + virBufferAddLit(buf, "<pseries>\n"); + virBufferAdjustIndent(buf, 2); + for (j = 0; j < VIR_DOMAIN_PSERIES_LAST; j++) { + switch ((virDomainPSeries) j) { + case VIR_DOMAIN_PSERIES_HPT: + if (def->pseries_features[j] != VIR_TRISTATE_SWITCH_ON) + break; + + virBufferAsprintf(buf, "<hpt resizing='%s'/>\n", + virDomainHPTResizingTypeToString(def->pseries_hpt_resizing)); + break; + + case VIR_DOMAIN_PSERIES_LAST: + break; + } + } + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</pseries>\n"); + break; + case VIR_DOMAIN_FEATURE_CAPABILITIES: if (def->features[i] == VIR_DOMAIN_CAPABILITIES_POLICY_DEFAULT && !virDomainDefHasCapabilitiesFeatures(def)) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 6f7f96b3d..e4ae2a26c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1740,6 +1740,7 @@ typedef enum { VIR_DOMAIN_FEATURE_IOAPIC, VIR_DOMAIN_FEATURE_HPT, VIR_DOMAIN_FEATURE_VMCOREINFO, + VIR_DOMAIN_FEATURE_PSERIES, VIR_DOMAIN_FEATURE_LAST } virDomainFeature; @@ -1766,6 +1767,14 @@ typedef enum { VIR_DOMAIN_KVM_LAST } virDomainKVM; +typedef enum { + VIR_DOMAIN_PSERIES_HPT = 0, + + VIR_DOMAIN_PSERIES_LAST +} virDomainPSeries; + +VIR_ENUM_DECL(virDomainPSeries); + typedef enum { VIR_DOMAIN_CAPABILITIES_POLICY_DEFAULT = 0, VIR_DOMAIN_CAPABILITIES_POLICY_ALLOW, @@ -2346,11 +2355,13 @@ struct _virDomainDef { int apic_eoi; int hyperv_features[VIR_DOMAIN_HYPERV_LAST]; int kvm_features[VIR_DOMAIN_KVM_LAST]; + int pseries_features[VIR_DOMAIN_PSERIES_LAST]; unsigned int hyperv_spinlocks; virGICVersion gic_version; char *hyperv_vendor_id; virDomainIOAPIC ioapic; virDomainHPTResizing hpt_resizing; + virDomainHPTResizing pseries_hpt_resizing; /* These options are of type virTristateSwitch: ON = keep, OFF = drop */ int caps_features[VIR_DOMAIN_CAPS_FEATURE_LAST]; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index bc8cc1fba..ae9eecb5d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -484,6 +484,8 @@ virDomainPausedReasonTypeFromString; virDomainPausedReasonTypeToString; virDomainPMSuspendedReasonTypeFromString; virDomainPMSuspendedReasonTypeToString; +virDomainPSeriesTypeFromString; +virDomainPSeriesTypeToString; virDomainRedirdevBusTypeFromString; virDomainRedirdevBusTypeToString; virDomainRedirdevDefFind; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b8aede32d..a053b597c 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -7360,6 +7360,79 @@ qemuBuildNameCommandLine(virCommandPtr cmd, return 0; } +static int +virDomainPSeriesToQEMUCaps(int feature) +{ + switch ((virDomainPSeries) feature) { + case VIR_DOMAIN_PSERIES_HPT: + return QEMU_CAPS_MACHINE_PSERIES_RESIZE_HPT; + case VIR_DOMAIN_PSERIES_LAST: + break; + } + + return -1; +} + +static const char* +virDomainPSeriesToMachineOption(int feature) +{ + switch ((virDomainPSeries) feature) { + case VIR_DOMAIN_PSERIES_HPT: + return "resize-hpt"; + case VIR_DOMAIN_PSERIES_LAST: + break; + } + + return NULL; +} + +static int +qemuBuildMachineCommandLinePSeriesFeature(virBufferPtr buf, + virDomainPSeries feature, + const char *value, + virQEMUCapsPtr qemuCaps) +{ + const char *name = virDomainPSeriesTypeToString(feature); + const char *option = virDomainPSeriesToMachineOption(feature); + int cap; + int ret = -1; + + if (!option) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown QEMU option for '%s' pSeries feature"), + name); + goto cleanup; + } + + if (!value) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Invalid value for '%s' pSeries feature"), + name); + goto cleanup; + } + + if ((cap = virDomainPSeriesToQEMUCaps(feature)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Unknown QEMU capability for '%s' pSeries feature"), + name); + goto cleanup; + } + + if (!virQEMUCapsGet(qemuCaps, cap)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("'%s' pSeries feature not supported by this QEMU binary"), + name); + goto cleanup; + } + + virBufferAsprintf(buf, ",%s=%s", option, value); + + ret = 0; + + cleanup: + return ret; +} + static int qemuBuildMachineCommandLine(virCommandPtr cmd, virQEMUDriverConfigPtr cfg, @@ -7592,6 +7665,26 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, virBufferAsprintf(&buf, ",resize-hpt=%s", str); } + if (def->features[VIR_DOMAIN_FEATURE_PSERIES] == VIR_TRISTATE_SWITCH_ON) { + const char *value; + + for (i = 0; i < VIR_DOMAIN_PSERIES_LAST; i++) { + switch ((virDomainPSeries) i) { + case VIR_DOMAIN_PSERIES_HPT: + if (def->pseries_features[i] != VIR_TRISTATE_SWITCH_ON) + break; + + value = virDomainHPTResizingTypeToString(def->pseries_hpt_resizing); + if (qemuBuildMachineCommandLinePSeriesFeature(&buf, i, value, qemuCaps) < 0) + goto cleanup; + break; + + case VIR_DOMAIN_PSERIES_LAST: + goto cleanup; + } + } + } + if (cpu && cpu->model && cpu->mode == VIR_CPU_MODE_HOST_MODEL && qemuDomainIsPSeries(def) && diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 6b4bd3cca..edef3838e 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3125,6 +3125,13 @@ qemuDomainDefVerifyFeatures(const virDomainDef *def) return -1; } + if (def->features[VIR_DOMAIN_FEATURE_PSERIES] == VIR_TRISTATE_SWITCH_ON && + !qemuDomainIsPSeries(def)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("pSeries features are only supported for pSeries guests")); + return -1; + } + if (def->features[VIR_DOMAIN_FEATURE_HPT] == VIR_TRISTATE_SWITCH_ON && !qemuDomainIsPSeries(def)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, -- 2.14.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list