On 08/11/2016 09:26 AM, Michal Privoznik wrote:
So, majority of the code is just ready as-is. Well, with one
slight change: differentiate between dimm and nvdimm in places
like device alias generation, generating the command line and so
on.
Speaking of the command line, we also need to append 'nvdimm=on'
to the '-machine' argument so that the nvdimm feature is
advertised in the ACPI tables properly.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/qemu/qemu_alias.c | 12 ++-
src/qemu/qemu_command.c | 90 ++++++++++++++--------
src/qemu/qemu_command.h | 1 +
src/qemu/qemu_domain.c | 28 +++++--
src/qemu/qemu_hotplug.c | 2 +-
.../qemuxml2argv-hugepages-numa.args | 5 +-
.../qemuxml2argv-hugepages-pages.args | 24 +++---
.../qemuxml2argv-hugepages-pages2.args | 8 +-
.../qemuxml2argv-hugepages-pages3.args | 4 +-
.../qemuxml2argv-hugepages-shared.args | 22 +++---
.../qemuxml2argv-memory-hotplug-dimm-addr.args | 5 +-
.../qemuxml2argv-memory-hotplug-dimm.args | 5 +-
.../qemuxml2argv-memory-hotplug-nvdimm.args | 25 ++++++
tests/qemuxml2argvtest.c | 4 +-
14 files changed, 155 insertions(+), 80 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.args
diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index 0102c96..517dca1 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -339,13 +339,19 @@ qemuAssignDeviceMemoryAlias(virDomainDefPtr def,
size_t i;
int maxidx = 0;
int idx;
+ const char *prefix;
+
+ if (mem->model == VIR_DOMAIN_MEMORY_MODEL_DIMM)
+ prefix = "dimm";
+ else
+ prefix = "nvdimm";
for (i = 0; i < def->nmems; i++) {
- if ((idx = qemuDomainDeviceAliasIndex(&def->mems[i]->info,
"dimm")) >= maxidx)
+ if ((idx = qemuDomainDeviceAliasIndex(&def->mems[i]->info, prefix))
>= maxidx)
maxidx = idx + 1;
}
- if (virAsprintf(&mem->info.alias, "dimm%d", maxidx) < 0)
+ if (virAsprintf(&mem->info.alias, "%s%d", prefix, maxidx) < 0)
return -1;
return 0;
@@ -445,7 +451,7 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr
qemuCaps)
return -1;
}
for (i = 0; i < def->nmems; i++) {
- if (virAsprintf(&def->mems[i]->info.alias, "dimm%zu", i)
< 0)
+ if (qemuAssignDeviceMemoryAlias(def, def->mems[i]) < 0)
return -1;
}
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index a4cc87f..6b83d1c 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3061,6 +3061,7 @@ qemuBuildControllerDevCommandLine(virCommandPtr cmd,
* to, or -1 if NUMA is not used in the guest
* @hostNodes: map of host nodes to alloc the memory in, NULL for default
* @autoNodeset: fallback nodeset in case of automatic numa placement
+ * @memPath: request memory-backend-file with specific mem-path
* @def: domain definition object
* @qemuCaps: qemu capabilities object
* @cfg: qemu driver config object
@@ -3082,6 +3083,7 @@ qemuBuildMemoryBackendStr(unsigned long long size,
int guestNode,
virBitmapPtr userNodeset,
virBitmapPtr autoNodeset,
+ const char *memPath,
virDomainDefPtr def,
virQEMUCapsPtr qemuCaps,
virQEMUDriverConfigPtr cfg,
@@ -3173,35 +3175,42 @@ qemuBuildMemoryBackendStr(unsigned long long size,
if (!(props = virJSONValueNewObject()))
return -1;
- if (pagesize || hugepage) {
- if (pagesize) {
- /* Now lets see, if the huge page we want to use is even mounted
- * and ready to use */
- for (i = 0; i < cfg->nhugetlbfs; i++) {
- if (cfg->hugetlbfs[i].size == pagesize)
- break;
- }
+ if (memPath || pagesize || hugepage) {
+ if (pagesize || hugepage) {
+ if (pagesize) {
+ /* Now lets see, if the huge page we want to use is even mounted
+ * and ready to use */
+ for (i = 0; i < cfg->nhugetlbfs; i++) {
+ if (cfg->hugetlbfs[i].size == pagesize)
+ break;
+ }
- if (i == cfg->nhugetlbfs) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unable to find any usable hugetlbfs mount for
%llu KiB"),
- pagesize);
- goto cleanup;
- }
+ if (i == cfg->nhugetlbfs) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find any usable hugetlbfs mount for
%llu KiB"),
+ pagesize);
+ goto cleanup;
+ }
- if (!(mem_path = qemuGetHugepagePath(&cfg->hugetlbfs[i])))
- goto cleanup;
- } else {
- if (!(mem_path = qemuGetDefaultHugepath(cfg->hugetlbfs,
- cfg->nhugetlbfs)))
- goto cleanup;
+ if (!(mem_path = qemuGetHugepagePath(&cfg->hugetlbfs[i])))
+ goto cleanup;
+ } else {
+ if (!(mem_path = qemuGetDefaultHugepath(cfg->hugetlbfs,
+ cfg->nhugetlbfs)))
+ goto cleanup;
+ }
}
*backendType = "memory-backend-file";
if (virJSONValueObjectAdd(props,
+ "s:mem-path", memPath ? memPath : mem_path,
+ NULL) < 0)
+ goto cleanup;
+
+ if (!memPath && (pagesize || hugepage) &&
+ virJSONValueObjectAdd(props,
"b:prealloc", true,
- "s:mem-path", mem_path,
NULL) < 0)
goto cleanup;
Two trips through virJSONValueObjectAdd... IIRC a prior review of my
code noted it's an expensive trip into that code... Besides you're
switching the arguments resulting changes to all the dimm tests...
Perhaps this should just be an
if (memPath)
"s:mem-path", memPath
else
"b:prealloc"
"s:mem-path", mem_path
In fact rather than the excess of changes with indents, why not keep:
if (pagesize || hugepage) {
}
and replace the closing } with
} else if (memPath) {
}
I think that would be cleaner and more obvious that they're different.
@@ -3253,7 +3262,7 @@ qemuBuildMemoryBackendStr(unsigned long long size,
}
/* If none of the following is requested... */
- if (!pagesize && !userNodeset && !memAccess &&
!nodeSpecified && !force) {
+ if (!pagesize && !userNodeset && !memAccess &&
!nodeSpecified && !force && !memPath) {
/* report back that using the new backend is not necessary
* to achieve the desired configuration */
ret = 1;
@@ -3309,7 +3318,7 @@ qemuBuildMemoryCellBackendStr(virDomainDefPtr def,
goto cleanup;
if ((rc = qemuBuildMemoryBackendStr(memsize, 0, cell, NULL, auto_nodeset,
- def, qemuCaps, cfg, &backendType,
+ NULL, def, qemuCaps, cfg, &backendType,
&props, false)) < 0)
goto cleanup;
@@ -3351,7 +3360,7 @@ qemuBuildMemoryDimmBackendStr(virDomainMemoryDefPtr mem,
if (qemuBuildMemoryBackendStr(mem->size, mem->pagesize,
mem->targetNode, mem->sourceNodes,
auto_nodeset,
- def, qemuCaps, cfg,
+ mem->path, def, qemuCaps, cfg,
&backendType, &props, true) < 0)
goto cleanup;
@@ -3369,6 +3378,7 @@ char *
qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
+ const char *device;
if (!mem->info.alias) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -3377,8 +3387,15 @@ qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
}
switch ((virDomainMemoryModel) mem->model) {
+ case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
case VIR_DOMAIN_MEMORY_MODEL_DIMM:
- virBufferAddLit(&buf, "pc-dimm,");
+
+ if (mem->model == VIR_DOMAIN_MEMORY_MODEL_DIMM)
+ device = "pc-dimm";
+ else
+ device = "nvdimm";
+
+ virBufferAsprintf(&buf, "%s,", device);
if (mem->targetNode >= 0)
virBufferAsprintf(&buf, "node=%d,", mem->targetNode);
@@ -3393,12 +3410,6 @@ qemuBuildMemoryDeviceStr(virDomainMemoryDefPtr mem)
break;
- case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
- virReportError(VIR_ERR_NO_SUPPORT, "%s",
- _("nvdimm not supported yet"));
- return NULL;
- break;
-
case VIR_DOMAIN_MEMORY_MODEL_NONE:
case VIR_DOMAIN_MEMORY_MODEL_LAST:
break;
@@ -6938,6 +6949,7 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
bool obsoleteAccel = false;
+ size_t i;
int ret = -1;
/* This should *never* be NULL, since we always provide
@@ -6974,6 +6986,15 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
"with this QEMU binary"));
return -1;
}
+
+ for (i = 0; i < def->nmems; i++) {
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("nvdimm not is not available "
+ "with this QEMU binary"));
+ return -1;
+ }
+ }
} else {
virTristateSwitch vmport = def->features[VIR_DOMAIN_FEATURE_VMPORT];
virTristateSwitch smm = def->features[VIR_DOMAIN_FEATURE_SMM];
@@ -7070,6 +7091,13 @@ qemuBuildMachineCommandLine(virCommandPtr cmd,
}
}
+ for (i = 0; i < def->nmems; i++) {
+ if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
+ virBufferAddLit(&buf, ",nvdimm=on");
+ break;
+ }
+ }
+
So I know we check later on when building the NVDIMM command line for
the QEMU_CAPS_DEVICE_NVDIMM; however, should we also check here. Mostly
for completeness
virCommandAddArgBuffer(cmd, &buf);
}
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index dcf9ba6..003a5d7 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -118,6 +118,7 @@ int qemuBuildMemoryBackendStr(unsigned long long size,
int guestNode,
virBitmapPtr userNodeset,
virBitmapPtr autoNodeset,
+ const char *memPath,
virDomainDefPtr def,
virQEMUCapsPtr qemuCaps,
virQEMUDriverConfigPtr cfg,
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 28ee81d..6b049e7 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -5289,12 +5289,6 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def,
return 0;
}
- if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PC_DIMM)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
- _("memory hotplug isn't supported by this QEMU
binary"));
- return -1;
- }
-
if (!ARCH_IS_PPC64(def->os.arch)) {
/* due to guest support, qemu would silently enable NUMA with one node
* once the memory hotplug backend is enabled. To avoid possible
BTW: So the "if (nmems > def->mem.memory_slots) {" check is what got me
initially thinking about the "how this is used" query I brought up in
patch 1 for formatdomain.
@@ -5318,6 +5312,28 @@ qemuDomainDefValidateMemoryHotplug(const
virDomainDef *def,
for (i = 0; i < def->nmems; i++) {
hotplugMemory += def->mems[i]->size;
This to is where I started wondering "how" this was implemented and how
it looks to the guest. Does the guest believe it has "extra" memory?
Unlike a DIMM, I wouldn't expect the memory to be general purpose usage
for the guest and thus wonder if the value for NVDIMM should be included.
I seem to have this recollection of some other algorithm that makes sure
address space(s) used by multiple dimm's don't have overlaps; however,
that wouldn't be true for an nvdimm. Perhaps that answer will be in
later patches.
+ switch ((virDomainMemoryModel) def->mems[i]->model) {
+ case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_PC_DIMM)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("memory hotplug isn't supported by this QEMU
binary"));
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_NVDIMM)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("nvdimm isn't supported by this QEMU
binary"));
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_MEMORY_MODEL_NONE:
+ case VIR_DOMAIN_MEMORY_MODEL_LAST:
+ break;
+ }
+
Good thing there aren't 1000's of these things... That's a check every
time through the loop
John
/* already existing devices don't need to be checked on
hotplug */
if (!mem &&
qemuDomainDefValidateMemoryHotplugDevice(def->mems[i], def) < 0)
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 00e4a75..bf22b0a 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1878,7 +1878,7 @@ qemuDomainAttachMemory(virQEMUDriverPtr driver,
if (qemuBuildMemoryBackendStr(mem->size, mem->pagesize,
mem->targetNode, mem->sourceNodes, NULL,
- vm->def, priv->qemuCaps, cfg,
+ mem->path, vm->def, priv->qemuCaps, cfg,
&backendType, &props, true) < 0)
goto cleanup;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-numa.args
b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-numa.args
index 2eb006e..dd12751 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-numa.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-numa.args
@@ -13,9 +13,8 @@ QEMU_AUDIO_DRV=spice \
-mem-prealloc \
-mem-path /dev/hugepages2M/libvirt/qemu \
-numa node,nodeid=0,cpus=0-1,mem=1024 \
--object memory-backend-file,id=memdimm0,prealloc=yes,\
-mem-path=/dev/hugepages1G/libvirt/qemu,size=1073741824,host-nodes=1-3,\
-policy=bind \
+-object memory-backend-file,id=memdimm0,mem-path=/dev/hugepages1G/libvirt/qemu,\
+prealloc=yes,size=1073741824,host-nodes=1-3,policy=bind \
-device pc-dimm,node=0,memdev=memdimm0,id=dimm0 \
-uuid 63840878-0deb-4095-97e6-fc444d9bc9fa \
-nodefaults \
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages.args
b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages.args
index 9f0e696..2a196ab 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages.args
@@ -10,21 +10,21 @@ QEMU_AUDIO_DRV=none \
-M pc \
-m 4096 \
-smp 4,sockets=4,cores=1,threads=1 \
--object memory-backend-file,id=ram-node0,prealloc=yes,\
-mem-path=/dev/hugepages1G/libvirt/qemu,size=1073741824,host-nodes=0-3,\
-policy=bind \
+-object memory-backend-file,id=ram-node0,\
+mem-path=/dev/hugepages1G/libvirt/qemu,prealloc=yes,size=1073741824,\
+host-nodes=0-3,policy=bind \
-numa node,nodeid=0,cpus=0,memdev=ram-node0 \
--object memory-backend-file,id=ram-node1,prealloc=yes,\
-mem-path=/dev/hugepages2M/libvirt/qemu,size=1073741824,host-nodes=0-3,\
-policy=bind \
+-object memory-backend-file,id=ram-node1,\
+mem-path=/dev/hugepages2M/libvirt/qemu,prealloc=yes,size=1073741824,\
+host-nodes=0-3,policy=bind \
-numa node,nodeid=1,cpus=1,memdev=ram-node1 \
--object memory-backend-file,id=ram-node2,prealloc=yes,\
-mem-path=/dev/hugepages1G/libvirt/qemu,size=1073741824,host-nodes=0-3,\
-policy=bind \
+-object memory-backend-file,id=ram-node2,\
+mem-path=/dev/hugepages1G/libvirt/qemu,prealloc=yes,size=1073741824,\
+host-nodes=0-3,policy=bind \
-numa node,nodeid=2,cpus=2,memdev=ram-node2 \
--object memory-backend-file,id=ram-node3,prealloc=yes,\
-mem-path=/dev/hugepages1G/libvirt/qemu,size=1073741824,host-nodes=3,\
-policy=bind \
+-object memory-backend-file,id=ram-node3,\
+mem-path=/dev/hugepages1G/libvirt/qemu,prealloc=yes,size=1073741824,\
+host-nodes=3,policy=bind \
-numa node,nodeid=3,cpus=3,memdev=ram-node3 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-nographic \
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages2.args
b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages2.args
index 447bb52..30f87a8 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages2.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages2.args
@@ -10,11 +10,11 @@ QEMU_AUDIO_DRV=none \
-M pc \
-m 1024 \
-smp 2,sockets=2,cores=1,threads=1 \
--object memory-backend-file,id=ram-node0,prealloc=yes,\
-mem-path=/dev/hugepages2M/libvirt/qemu,size=268435456 \
+-object memory-backend-file,id=ram-node0,\
+mem-path=/dev/hugepages2M/libvirt/qemu,prealloc=yes,size=268435456 \
-numa node,nodeid=0,cpus=0,memdev=ram-node0 \
--object memory-backend-file,id=ram-node1,prealloc=yes,\
-mem-path=/dev/hugepages2M/libvirt/qemu,size=805306368 \
+-object memory-backend-file,id=ram-node1,\
+mem-path=/dev/hugepages2M/libvirt/qemu,prealloc=yes,size=805306368 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1 \
-uuid ef1bdff4-27f3-4e85-a807-5fb4d58463cc \
-nographic \
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages3.args
b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages3.args
index 57dd3fa..92045a0 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages3.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-pages3.args
@@ -12,8 +12,8 @@ QEMU_AUDIO_DRV=none \
-smp 2,sockets=2,cores=1,threads=1 \
-object memory-backend-ram,id=ram-node0,size=268435456 \
-numa node,nodeid=0,cpus=0,memdev=ram-node0 \
--object memory-backend-file,id=ram-node1,prealloc=yes,\
-mem-path=/dev/hugepages1G/libvirt/qemu,size=805306368 \
+-object memory-backend-file,id=ram-node1,\
+mem-path=/dev/hugepages1G/libvirt/qemu,prealloc=yes,size=805306368 \
-numa node,nodeid=1,cpus=1,memdev=ram-node1 \
-uuid ef1bdff4-27f3-4e85-a807-5fb4d58463cc \
-nographic \
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-shared.args
b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-shared.args
index f9fc218..aaa9e99 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-hugepages-shared.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-hugepages-shared.args
@@ -10,21 +10,21 @@ QEMU_AUDIO_DRV=none \
-M pc \
-m 4096 \
-smp 4,sockets=4,cores=1,threads=1 \
--object memory-backend-file,id=ram-node0,prealloc=yes,\
-mem-path=/dev/hugepages1G/libvirt/qemu,size=1073741824,host-nodes=0-3,\
-policy=bind \
+-object memory-backend-file,id=ram-node0,\
+mem-path=/dev/hugepages1G/libvirt/qemu,prealloc=yes,size=1073741824,\
+host-nodes=0-3,policy=bind \
-numa node,nodeid=0,cpus=0,memdev=ram-node0 \
--object memory-backend-file,id=ram-node1,prealloc=yes,\
-mem-path=/dev/hugepages2M/libvirt/qemu,share=yes,size=1073741824,\
+-object memory-backend-file,id=ram-node1,\
+mem-path=/dev/hugepages2M/libvirt/qemu,prealloc=yes,share=yes,size=1073741824,\
host-nodes=0-3,policy=bind \
-numa node,nodeid=1,cpus=1,memdev=ram-node1 \
--object memory-backend-file,id=ram-node2,prealloc=yes,\
-mem-path=/dev/hugepages1G/libvirt/qemu,share=no,size=1073741824,host-nodes=0-3,\
-policy=bind \
+-object memory-backend-file,id=ram-node2,\
+mem-path=/dev/hugepages1G/libvirt/qemu,prealloc=yes,share=no,size=1073741824,\
+host-nodes=0-3,policy=bind \
-numa node,nodeid=2,cpus=2,memdev=ram-node2 \
--object memory-backend-file,id=ram-node3,prealloc=yes,\
-mem-path=/dev/hugepages1G/libvirt/qemu,size=1073741824,host-nodes=3,\
-policy=bind \
+-object memory-backend-file,id=ram-node3,\
+mem-path=/dev/hugepages1G/libvirt/qemu,prealloc=yes,size=1073741824,\
+host-nodes=3,policy=bind \
-numa node,nodeid=3,cpus=3,memdev=ram-node3 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-nographic \
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm-addr.args
b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm-addr.args
index 1c881c6..ea46c82 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm-addr.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm-addr.args
@@ -11,9 +11,8 @@ QEMU_AUDIO_DRV=none \
-m size=219136k,slots=16,maxmem=1099511627776k \
-smp 2,sockets=2,cores=1,threads=1 \
-numa node,nodeid=0,cpus=0-1,mem=214 \
--object memory-backend-file,id=memdimm0,prealloc=yes,\
-mem-path=/dev/hugepages2M/libvirt/qemu,size=536870912,host-nodes=1-3,\
-policy=bind \
+-object memory-backend-file,id=memdimm0,mem-path=/dev/hugepages2M/libvirt/qemu,\
+prealloc=yes,size=536870912,host-nodes=1-3,policy=bind \
-device pc-dimm,node=0,memdev=memdimm0,id=dimm0,slot=0,addr=4294967296 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-nographic \
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.args
b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.args
index fa64fcf..dc58614 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.args
@@ -13,9 +13,8 @@ QEMU_AUDIO_DRV=none \
-numa node,nodeid=0,cpus=0-1,mem=214 \
-object memory-backend-ram,id=memdimm0,size=536870912 \
-device pc-dimm,node=0,memdev=memdimm0,id=dimm0 \
--object memory-backend-file,id=memdimm1,prealloc=yes,\
-mem-path=/dev/hugepages2M/libvirt/qemu,size=536870912,host-nodes=1-3,\
-policy=bind \
+-object memory-backend-file,id=memdimm1,mem-path=/dev/hugepages2M/libvirt/qemu,\
+prealloc=yes,size=536870912,host-nodes=1-3,policy=bind \
-device pc-dimm,node=0,memdev=memdimm1,id=dimm1 \
-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
-nographic \
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.args
b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.args
new file mode 100644
index 0000000..8cda774
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.args
@@ -0,0 +1,25 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest1 \
+-S \
+-machine pc,accel=tcg,nvdimm=on \
+-m size=219136k,slots=16,maxmem=1099511627776k \
+-smp 2,sockets=2,cores=1,threads=1 \
+-numa node,nodeid=0,cpus=0-1,mem=214 \
+-object memory-backend-file,id=memnvdimm0,mem-path=/tmp/nvdimm,size=536870912 \
+-device nvdimm,node=0,memdev=memnvdimm0,id=nvdimm0 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-usb \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index ad0693f..1995ccc 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1977,7 +1977,7 @@ mymain(void)
DO_TEST_FAILURE("memory-align-fail", NONE);
DO_TEST_FAILURE("memory-hotplug-nonuma", QEMU_CAPS_DEVICE_PC_DIMM);
- DO_TEST_FAILURE("memory-hotplug", NONE);
+ DO_TEST("memory-hotplug", NONE);
DO_TEST("memory-hotplug", QEMU_CAPS_DEVICE_PC_DIMM, QEMU_CAPS_NUMA);
DO_TEST("memory-hotplug-dimm", QEMU_CAPS_DEVICE_PC_DIMM, QEMU_CAPS_NUMA,
QEMU_CAPS_OBJECT_MEMORY_RAM, QEMU_CAPS_OBJECT_MEMORY_FILE);
@@ -1985,6 +1985,8 @@ mymain(void)
QEMU_CAPS_OBJECT_MEMORY_FILE);
DO_TEST("memory-hotplug-ppc64-nonuma", QEMU_CAPS_KVM,
QEMU_CAPS_DEVICE_PC_DIMM, QEMU_CAPS_NUMA,
QEMU_CAPS_OBJECT_MEMORY_RAM, QEMU_CAPS_OBJECT_MEMORY_FILE);
+ DO_TEST("memory-hotplug-nvdimm", QEMU_CAPS_MACHINE_OPT,
QEMU_CAPS_DEVICE_NVDIMM,
+ QEMU_CAPS_NUMA, QEMU_CAPS_OBJECT_MEMORY_RAM, QEMU_CAPS_OBJECT_MEMORY_FILE);
DO_TEST("machine-aeskeywrap-on-caps",
QEMU_CAPS_MACHINE_OPT, QEMU_CAPS_AES_KEY_WRAP,