[libvirt] [PATCH v3 07/17] qemu: Implement NVDIMM
Michal Privoznik
mprivozn at redhat.com
Wed Mar 15 16:19:44 UTC 2017
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 at redhat.com>
>> ---
>> 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
More information about the libvir-list
mailing list