[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