Using the 'uuid' element for ppc64 NVDIMM memory added in the
previous patch, use it in qemuBuildMemoryDeviceStr() to pass
it over to QEMU.
Another ppc64 restriction is the necessity of a mem->labelsize,
given than ppc64 only support label-area backed NVDIMMs.
Finally, we don't want ppc64 NVDIMMs to align up due to the
high risk of going beyond the end of file with a 256MiB
increment that the user didn't predict. Align it down
instead. If target size is less than the minimum of
256MiB + labelsize, error out since QEMU will error out
if we attempt to round it up to the minimum.
Signed-off-by: Daniel Henrique Barboza <danielhb413(a)gmail.com>
---
src/conf/domain_conf.c | 7 +++
src/qemu/qemu_command.c | 7 +++
src/qemu/qemu_domain.c | 63 +++++++++++++++++--
src/qemu/qemu_domain.h | 4 +-
src/qemu/qemu_hotplug.c | 6 +-
.../memory-hotplug-nvdimm-ppc64.args | 32 ++++++++++
...ory-hotplug-nvdimm-ppc64.ppc64-latest.args | 36 +++++++++++
.../memory-hotplug-nvdimm-ppc64.xml | 5 +-
tests/qemuxml2argvtest.c | 1 +
.../memory-hotplug-nvdimm-ppc64.xml | 5 +-
10 files changed, 156 insertions(+), 10 deletions(-)
create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.args
create mode 100644 tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.ppc64-latest.args
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 43643b93a1..cee85a7cad 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -16674,6 +16674,13 @@ virDomainMemoryDefParseXML(virDomainXMLOptionPtr xmlopt,
if (virDomainMemoryTargetDefParseXML(node, ctxt, def) < 0)
goto error;
+ if (def->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM &&
+ ARCH_IS_PPC64(dom->os.arch) && def->labelsize == 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("label size is required for NVDIMM device"));
+ goto error;
+ }
+
if (virDomainDeviceInfoParseXML(xmlopt, memdevNode,
&def->info, flags) < 0)
goto error;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 9790c92cf8..7a546970e7 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3678,6 +3678,13 @@ qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem,
if (mem->labelsize)
virBufferAsprintf(&buf, "label-size=%llu,", mem->labelsize *
1024);
+ if (virUUIDIsValid(mem->uuid)) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ virUUIDFormat(mem->uuid, uuidstr);
+ virBufferAsprintf(&buf, "uuid=%s,", uuidstr);
+ }
+
if (mem->readonly) {
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_NVDIMM_UNARMED)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 9cff36cb77..78dd643a5e 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -12614,6 +12614,46 @@ qemuDomainGetMemoryModuleSizeAlignment(const virDomainDef *def,
}
+static int
+qemuDomainNVDimmAlignSizePseries(virDomainDefPtr def,
+ virDomainMemoryDefPtr mem)
+{
+ /* For NVDIMMs in ppc64 in we want to align down the guest
+ * visible space, instead of align up, to avoid writing
+ * beyond the end of file by adding a potential 256MiB
+ * to the user specified size.
+ *
+ * The label-size is mandatory for ppc64 as well, meaning that
+ * the guest visible space will be target_size-label_size.
+ *
+ * Finally, target_size must include label_size.
+ *
+ * The above can be summed up as follows:
+ *
+ * target_size = AlignDown(target_size - label_size) + label_size
+ */
+ unsigned long long ppc64AlignSize = qemuDomainGetMemorySizeAlignment(def);
+ unsigned long long guestArea = mem->size - mem->labelsize;
+
+ /* Align down guest_area. 256MiB is the minimum size. Error
+ * out if target_size is smaller than 256MiB + label_size,
+ * since aligning it up will cause QEMU errors. */
+ if (mem->size < (ppc64AlignSize + mem->labelsize)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("minimum target size for the NVDIMM "
+ "must be 256MB plus the label size"));
+ return -1;
+ }
+
+ guestArea = (guestArea/ppc64AlignSize) * ppc64AlignSize;
+ guestArea = MAX(guestArea, ppc64AlignSize);
+
+ mem->size = guestArea + mem->labelsize;
+
+ return 0;
+}
+
+
int
qemuDomainAlignMemorySizes(virDomainDefPtr def)
{
@@ -12660,8 +12700,15 @@ qemuDomainAlignMemorySizes(virDomainDefPtr def)
/* Align memory module sizes */
for (i = 0; i < def->nmems; i++) {
- align = qemuDomainGetMemoryModuleSizeAlignment(def, def->mems[i]);
- def->mems[i]->size = VIR_ROUND_UP(def->mems[i]->size, align);
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM &&
+ ARCH_IS_PPC64(def->os.arch)) {
+ if (qemuDomainNVDimmAlignSizePseries(def, def->mems[i]) < 0)
+ return -1;
+ } else {
+ align = qemuDomainGetMemoryModuleSizeAlignment(def, def->mems[i]);
+ def->mems[i]->size = VIR_ROUND_UP(def->mems[i]->size, align);
+ }
+
hotplugmem += def->mems[i]->size;
if (def->mems[i]->size > maxmemkb) {
@@ -12686,11 +12733,19 @@ qemuDomainAlignMemorySizes(virDomainDefPtr def)
* inplace. Default rounding is now to 1 MiB (qemu requires rouding to page,
* size so this should be safe).
*/
-void
+int
qemuDomainMemoryDeviceAlignSize(virDomainDefPtr def,
virDomainMemoryDefPtr mem)
{
- mem->size = VIR_ROUND_UP(mem->size, qemuDomainGetMemorySizeAlignment(def));
+ if (mem->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM &&
+ ARCH_IS_PPC64(def->os.arch)) {
+ return qemuDomainNVDimmAlignSizePseries(def, mem);
+ } else {
+ mem->size = VIR_ROUND_UP(mem->size,
+ qemuDomainGetMemorySizeAlignment(def));
+ }
+
+ return 0;
}
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index 0a49f6dea3..7151efa200 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -967,8 +967,8 @@ bool qemuDomainHasBlockjob(virDomainObjPtr vm, bool copy_only)
ATTRIBUTE_NONNULL(1);
int qemuDomainAlignMemorySizes(virDomainDefPtr def);
-void qemuDomainMemoryDeviceAlignSize(virDomainDefPtr def,
- virDomainMemoryDefPtr mem);
+int qemuDomainMemoryDeviceAlignSize(virDomainDefPtr def,
+ virDomainMemoryDefPtr mem);
virDomainChrDefPtr qemuFindAgentConfig(virDomainDefPtr def);
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index c17442aaeb..2b4db4f2f8 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2352,7 +2352,8 @@ qemuDomainAttachMemory(virQEMUDriverPtr driver,
int id;
int ret = -1;
- qemuDomainMemoryDeviceAlignSize(vm->def, mem);
+ if (qemuDomainMemoryDeviceAlignSize(vm->def, mem) < 0)
+ goto cleanup;
if (qemuDomainDefValidateMemoryHotplug(vm->def, priv->qemuCaps, mem) < 0)
goto cleanup;
@@ -5641,7 +5642,8 @@ qemuDomainDetachPrepMemory(virDomainObjPtr vm,
virDomainMemoryDefPtr mem;
int idx;
- qemuDomainMemoryDeviceAlignSize(vm->def, match);
+ if (qemuDomainMemoryDeviceAlignSize(vm->def, match) < 0)
+ return -1;
if ((idx = virDomainMemoryFindByDef(vm->def, match)) < 0) {
virReportError(VIR_ERR_DEVICE_MISSING,
diff --git a/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.args
b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.args
new file mode 100644
index 0000000000..92e6c538fb
--- /dev/null
+++ b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.args
@@ -0,0 +1,32 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/tmp/lib/domain--1-QEMUGuest1 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
+XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
+XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-ppc64 \
+-name QEMUGuest1 \
+-S \
+-machine pseries,accel=tcg,usb=off,dump-guest-core=off,nvdimm=on \
+-m size=1048576k,slots=16,maxmem=1099511627776k \
+-realtime mlock=off \
+-smp 2,sockets=2,cores=1,threads=1 \
+-numa node,nodeid=0,cpus=0-1,mem=1024 \
+-object memory-backend-file,id=memnvdimm0,prealloc=yes,mem-path=/tmp/nvdimm,\
+size=537001984 \
+-device nvdimm,node=0,label-size=131072,\
+uuid=49545eb3-75e1-2d0a-acdd-f0294406c99e,memdev=memnvdimm0,id=nvdimm0,slot=0 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
+server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-usb \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2
diff --git a/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.ppc64-latest.args
b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.ppc64-latest.args
new file mode 100644
index 0000000000..7f556a6668
--- /dev/null
+++ b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.ppc64-latest.args
@@ -0,0 +1,36 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/tmp/lib/domain--1-QEMUGuest1 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
+XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
+XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-ppc64 \
+-name guest=QEMUGuest1,debug-threads=on \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
+-machine pseries,accel=tcg,usb=off,dump-guest-core=off,nvdimm=on \
+-cpu POWER9 \
+-m size=1048576k,slots=16,maxmem=1099511627776k \
+-overcommit mem-lock=off \
+-smp 2,sockets=2,dies=1,cores=1,threads=1 \
+-numa node,nodeid=0,cpus=0-1,mem=1024 \
+-object memory-backend-file,id=memnvdimm0,prealloc=yes,mem-path=/tmp/nvdimm,\
+size=537001984 \
+-device nvdimm,node=0,label-size=131072,\
+uuid=49545eb3-75e1-2d0a-acdd-f0294406c99e,memdev=memnvdimm0,id=nvdimm0,slot=0 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,fd=1729,server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-boot strict=on \
+-device pci-ohci,id=usb,bus=pci.0,addr=0x1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \
+-msg timestamp=on
diff --git a/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.xml
b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.xml
index 59352d3c52..ae5a17d3c8 100644
--- a/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.xml
+++ b/tests/qemuxml2argvdata/memory-hotplug-nvdimm-ppc64.xml
@@ -38,8 +38,11 @@
<path>/tmp/nvdimm</path>
</source>
<target>
- <size unit='KiB'>523264</size>
+ <size unit='KiB'>550000</size>
<node>0</node>
+ <label>
+ <size unit='KiB'>128</size>
+ </label>
</target>
<address type='dimm' slot='0'/>
</memory>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index e81d1d7fa1..4d44286b5a 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -2791,6 +2791,7 @@ mymain(void)
DO_TEST_CAPS_LATEST("memory-hotplug-nvdimm-align");
DO_TEST_CAPS_LATEST("memory-hotplug-nvdimm-pmem");
DO_TEST_CAPS_LATEST("memory-hotplug-nvdimm-readonly");
+ DO_TEST_CAPS_ARCH_LATEST("memory-hotplug-nvdimm-ppc64",
"ppc64");
DO_TEST("machine-aeskeywrap-on-caps",
QEMU_CAPS_AES_KEY_WRAP,
diff --git a/tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-ppc64.xml
b/tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-ppc64.xml
index 59352d3c52..ae5a17d3c8 100644
--- a/tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-ppc64.xml
+++ b/tests/qemuxml2xmloutdata/memory-hotplug-nvdimm-ppc64.xml
@@ -38,8 +38,11 @@
<path>/tmp/nvdimm</path>
</source>
<target>
- <size unit='KiB'>523264</size>
+ <size unit='KiB'>550000</size>
<node>0</node>
+ <label>
+ <size unit='KiB'>128</size>
+ </label>
</target>
<address type='dimm' slot='0'/>
</memory>
--
2.25.1