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@xxxxxxxxx> --- 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