On 03/14/2017 02:36 PM, John Ferlan wrote: > > > On 03/09/2017 11:06 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@xxxxxxxxxx> >> --- >> src/qemu/qemu_alias.c | 10 ++- >> src/qemu/qemu_command.c | 76 +++++++++++++++------- >> src/qemu/qemu_domain.c | 42 ++++++++---- >> .../qemuxml2argv-memory-hotplug-nvdimm.args | 26 ++++++++ >> tests/qemuxml2argvtest.c | 4 +- >> 5 files changed, 121 insertions(+), 37 deletions(-) >> create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.args >> > > [...] > >> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c >> index 07178f839..a66ce6645 100644 >> --- a/src/qemu/qemu_command.c >> +++ b/src/qemu/qemu_command.c >> @@ -3118,7 +3118,8 @@ qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps, > >> const long system_page_size = virGetSystemPageSizeKB(); >> virDomainMemoryAccess memAccess = VIR_DOMAIN_MEMORY_ACCESS_DEFAULT; >> size_t i; >> - char *mem_path = NULL; >> + char *memPath = NULL; >> + bool prealloc = false; >> virBitmapPtr nodemask = NULL; >> int ret = -1; >> virJSONValuePtr props = NULL; >> @@ -3199,26 +3200,31 @@ qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps, >> if (!(props = virJSONValueNewObject())) >> return -1; >> >> - if (pagesize || def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) { >> + if (pagesize || mem->nvdimmPath || >> + def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) { >> *backendType = "memory-backend-file"; >> >> - if (def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) { >> - /* we can have both pagesize and mem source, then check mem source first */ >> - if (virJSONValueObjectAdd(props, >> - "s:mem-path", cfg->memoryBackingDir, >> - NULL) < 0) >> + if (mem->nvdimmPath) { >> + if (VIR_STRDUP(memPath, mem->nvdimmPath) < 0) >> + goto cleanup; >> + prealloc = true; >> + } else if (def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) { >> + /* We can have both pagesize and mem source, >> + * then check mem source first. */ >> + if (VIR_STRDUP(memPath, cfg->memoryBackingDir) < 0) >> goto cleanup; >> } else { >> - if (qemuGetDomainHupageMemPath(def, cfg, pagesize, &mem_path) < 0) >> - goto cleanup; >> - >> - if (virJSONValueObjectAdd(props, >> - "b:prealloc", true, >> - "s:mem-path", mem_path, >> - NULL) < 0) >> + if (qemuGetDomainHupageMemPath(def, cfg, pagesize, &memPath) < 0) >> goto cleanup; >> + prealloc = true; >> } >> > > FWIW: In my v2 review I alluded to a double comma thing (e.g. code that > needs virQEMUBuildBufferEscapeComma)... This is what I was thinking > about, but IIRC it's only something for certain command line options and > not JSON object building... It is not needed for JSON build. > > > >> + if (virJSONValueObjectAdd(props, >> + "B:prealloc", prealloc, >> + "s:mem-path", memPath, >> + NULL) < 0) >> + goto cleanup; >> + >> switch (memAccess) { >> case VIR_DOMAIN_MEMORY_ACCESS_SHARED: >> if (virJSONValueObjectAdd(props, "b:share", true, NULL) < 0) >> @@ -3274,6 +3280,7 @@ qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps, >> >> /* If none of the following is requested... */ >> if (!needHugepage && !mem->sourceNodes && !nodeSpecified && >> + !mem->nvdimmPath && >> memAccess == VIR_DOMAIN_MEMORY_ACCESS_DEFAULT && >> def->mem.source != VIR_DOMAIN_MEMORY_SOURCE_FILE && !force) { >> /* report back that using the new backend is not necessary >> @@ -3303,8 +3310,7 @@ qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps, >> >> cleanup: >> virJSONValueFree(props); >> - VIR_FREE(mem_path); >> - >> + VIR_FREE(memPath); >> return ret; >> } > > [...] > >> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c >> index 66c0e5911..495242981 100644 >> --- a/src/qemu/qemu_domain.c >> +++ b/src/qemu/qemu_domain.c >> @@ -5919,6 +5919,7 @@ qemuDomainDefValidateMemoryHotplugDevice(const virDomainMemoryDef *mem, >> { >> switch ((virDomainMemoryModel) mem->model) { >> case VIR_DOMAIN_MEMORY_MODEL_DIMM: >> + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: >> if (mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM && >> mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) { >> virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", >> @@ -5951,11 +5952,6 @@ qemuDomainDefValidateMemoryHotplugDevice(const virDomainMemoryDef *mem, >> } >> break; >> >> - case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: >> - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", >> - _("nvdimm hotplug not supported yet")); >> - return -1; >> - >> case VIR_DOMAIN_MEMORY_MODEL_NONE: >> case VIR_DOMAIN_MEMORY_MODEL_LAST: >> return -1; >> @@ -5986,6 +5982,8 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def, >> unsigned int nmems = def->nmems; >> unsigned long long hotplugSpace; >> unsigned long long hotplugMemory = 0; >> + bool needPCDimmCap = false; >> + bool needNvdimmCap = false; > > needNVDimm could be used.... although I see no reason for these bool's > the way the rest is written. > >> size_t i; >> >> hotplugSpace = def->mem.max_memory - virDomainDefGetMemoryInitial(def); >> @@ -6009,12 +6007,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 >> @@ -6038,6 +6030,34 @@ qemuDomainDefValidateMemoryHotplug(const virDomainDef *def, >> for (i = 0; i < def->nmems; i++) { >> hotplugMemory += def->mems[i]->size; >> >> + switch ((virDomainMemoryModel) def->mems[i]->model) { >> + case VIR_DOMAIN_MEMORY_MODEL_DIMM: >> + needPCDimmCap = true; >> + break; >> + >> + case VIR_DOMAIN_MEMORY_MODEL_NVDIMM: >> + needNvdimmCap = true; >> + break; >> + >> + case VIR_DOMAIN_MEMORY_MODEL_NONE: >> + case VIR_DOMAIN_MEMORY_MODEL_LAST: >> + break; >> + } >> + >> + if (needPCDimmCap && >> + !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 (needNvdimmCap && >> + !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_NVDIMM)) { >> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", >> + _("nvdimm isn't supported by this QEMU binary")); >> + return -1; >> + } >> + > > Still inefficient as virQEMUCapsGet will get called each time through > the for loop as soon as need*Cap = true... Perhaps even moreso since > one or the other will be called both times for a single pass if there > both types of *Dimm defs are in the XML (once one or the other is seen). Oh, I am a giddy goat. This should have been: for () { switch() { case MODEL_DIM: needPCDimmCap = true; break; case MODEL_NVDIMM: needNvdimmCap = true; break; } } if (needPCDimmCap && !virQEMUCapsGet()) error; if (needNvdimmCap && !virQEMUCapsGet()) error; I am fixing it as such. Thanks. Michal -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list