static int
-virDomainMemoryDefValidate(const virDomainMemoryDef *mem)
+virDomainMemoryDefValidate(const virDomainMemoryDef *mem,
+ const virDomainDef *def)
{
- if (mem->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM &&
- mem->discard == VIR_TRISTATE_BOOL_YES) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("discard is not supported for nvdimms"));
- return -1;
+ if (mem->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
+ if (mem->discard == VIR_TRISTATE_BOOL_YES) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("discard is not supported for nvdimms"));
+ return -1;
+ }
+
+ if (ARCH_IS_PPC64(def->os.arch) && mem->labelsize == 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("label size is required for NVDIMM device"));
+ return -1;
+ }
}
return 0;
return virDomainVideoDefValidate(dev->data.video, def);
case VIR_DOMAIN_DEVICE_MEMORY:
- return virDomainMemoryDefValidate(dev->data.memory);
+ return virDomainMemoryDefValidate(dev->data.memory, def);
case VIR_DOMAIN_DEVICE_VSOCK:
return virDomainVsockDefValidate(dev->data.vsock);
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",
}
+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)
{
/* 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) {
* 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;
}
ATTRIBUTE_NONNULL(1);
int qemuDomainAlignMemorySizes(virDomainDefPtr def);
-void qemuDomainMemoryDeviceAlignSize(virDomainDefPtr def,
- virDomainMemoryDefPtr mem);
+int qemuDomainMemoryDeviceAlignSize(virDomainDefPtr def,
+ virDomainMemoryDefPtr mem);
virDomainChrDefPtr qemuFindAgentConfig(virDomainDefPtr def);
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;
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,
--- /dev/null
+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
--- /dev/null
+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
<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>
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,
<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>