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