[libvirt] [PATCH v2 02/14] Introduce NVDIMM memory model

Michal Privoznik mprivozn at redhat.com
Mon Feb 27 13:19:24 UTC 2017


NVDIMM is new type of memory introduced into QEMU 2.6. The idea
is that we have a Non-Volatile memory module that keeps the data
persistent across domain reboots.

At the domain XML level, we already have some representation of
'dimm' modules. Long story short, we have <memory/> element that
lives under <devices/>. Now, the element even has @model
attribute which we can use to introduce new memory type:

    <memory model='nvdimm'>
      <source>
        <path>/tmp/nvdimm</path>
      </source>
      <target>
        <size unit='KiB'>523264</size>
        <node>0</node>
      </target>
      <address type='dimm' slot='0'/>
    </memory>

So far, this is just a XML parser/formatter extension. QEMU
driver implementation is in the next commit.

For more info on NVDIMM visit the following web page:

    http://pmem.io/

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 docs/formatdomain.html.in                          | 55 ++++++++----
 docs/schemas/domaincommon.rng                      | 32 ++++---
 src/conf/domain_conf.c                             | 97 ++++++++++++++++------
 src/conf/domain_conf.h                             |  2 +
 src/qemu/qemu_command.c                            |  6 ++
 src/qemu/qemu_domain.c                             |  5 ++
 .../qemuxml2argv-memory-hotplug-nvdimm.xml         | 56 +++++++++++++
 .../qemuxml2xmlout-memory-hotplug-nvdimm.xml       |  1 +
 tests/qemuxml2xmltest.c                            |  1 +
 9 files changed, 204 insertions(+), 51 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.xml
 create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-memory-hotplug-nvdimm.xml

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 02ce7924c..b76905cdc 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -7007,7 +7007,6 @@ qemu-kvm -net nic,model=? /dev/null
         guests' memory resource needs.
 
         Some hypervisors may require NUMA configured for the guest.
-      <span class="since">Since 1.2.14</span>
     </p>
 
     <p>
@@ -7032,6 +7031,15 @@ qemu-kvm -net nic,model=? /dev/null
       <node>1</node>
     </target>
   </memory>
+  <memory model='nvdimm'>
+    <source>
+      <path>/tmp/nvdimm</path>
+    </source>
+    <target>
+      <size unit='KiB'>524288</size>
+      <node>1</node>
+    </target>
+  </memory>
 </devices>
 ...
 </pre>
@@ -7039,28 +7047,47 @@ qemu-kvm -net nic,model=? /dev/null
       <dt><code>model</code></dt>
       <dd>
         <p>
-          Currently only the <code>dimm</code> model is supported in order to
-          add a virtual DIMM module to the guest.
+          Provide <code>dimm</code> to add a virtual DIMM module to the guest.
+          <span class="since">Since 1.2.14</span>
+          Provide <code>nvdimm</code> model adds a Non-Volatile DIMM
+          module. <span class="since">Since 3.1.0</span>
         </p>
       </dd>
 
       <dt><code>source</code></dt>
       <dd>
         <p>
-          The optional source element allows to fine tune the source of the
-          memory used for the given memory device. If the element is not
-          provided defaults configured via <code>numatune</code> are used.
+          For model <code>dimm</code> this element is optional and allows to
+          fine tune the source of the memory used for the given memory device.
+          If the element is not provided defaults configured via
+          <code>numatune</code> are used. If <code>dimm</code> is provided,
+          then the following optional elements can be provided as well:
         </p>
-        <p>
-          <code>pagesize</code> can optionally be used to override the default
-          host page size used for backing the memory device.
 
-          The configured value must correspond to a page size supported by the
-          host.
-        </p>
+        <dl>
+          <dt><code>pagesize</code></dt>
+          <dd>
+            <p>
+              This element can optionally be used to override the default
+              host page size used for backing the memory device.
+              The configured value must correspond to a page size supported by the
+              host.
+            </p>
+          </dd>
+
+          <dt><code>nodemask</code></dt>
+          <dd>
+            <p>
+              This element can optionally be used to override the default
+              set of NUMA nodes where the memory would be allocated.
+            </p>
+          </dd>
+        </dl>
+
         <p>
-          <code>nodemask</code> can optionally be used to override the default
-          set of NUMA nodes where the memory would be allocated.
+          For model <code>nvdimm</code> this element is mandatory and has a
+          single child element <code>path</code> that represents a path
+          in the host that backs the nvdimm module in the guest.
         </p>
       </dd>
 
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index c64544ac4..fafd3e982 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4737,6 +4737,7 @@
       <attribute name="model">
         <choice>
           <value>dimm</value>
+          <value>nvdimm</value>
         </choice>
       </attribute>
       <interleave>
@@ -4756,18 +4757,27 @@
 
   <define name="memorydev-source">
     <element name="source">
-      <interleave>
-        <optional>
-          <element name="pagesize">
-            <ref name="scaledInteger"/>
+      <choice>
+        <group>
+          <interleave>
+            <optional>
+              <element name="pagesize">
+                <ref name="scaledInteger"/>
+              </element>
+            </optional>
+            <optional>
+              <element name="nodemask">
+                <ref name="cpuset"/>
+              </element>
+            </optional>
+          </interleave>
+        </group>
+        <group>
+          <element name="path">
+            <text/>
           </element>
-        </optional>
-        <optional>
-          <element name="nodemask">
-            <ref name="cpuset"/>
-          </element>
-        </optional>
-      </interleave>
+        </group>
+      </choice>
     </element>
   </define>
 
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 97d42fe99..4ffca7dc8 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -858,8 +858,11 @@ VIR_ENUM_DECL(virDomainBlockJob)
 VIR_ENUM_IMPL(virDomainBlockJob, VIR_DOMAIN_BLOCK_JOB_TYPE_LAST,
               "", "", "copy", "", "active-commit")
 
-VIR_ENUM_IMPL(virDomainMemoryModel, VIR_DOMAIN_MEMORY_MODEL_LAST,
-              "", "dimm")
+VIR_ENUM_IMPL(virDomainMemoryModel,
+              VIR_DOMAIN_MEMORY_MODEL_LAST,
+              "",
+              "dimm",
+              "nvdimm")
 
 VIR_ENUM_IMPL(virDomainShmemModel, VIR_DOMAIN_SHMEM_MODEL_LAST,
               "ivshmem",
@@ -2418,6 +2421,7 @@ void virDomainMemoryDefFree(virDomainMemoryDefPtr def)
     if (!def)
         return;
 
+    VIR_FREE(def->path);
     virBitmapFree(def->sourceNodes);
     virDomainDeviceInfoClear(&def->info);
     VIR_FREE(def);
@@ -13755,20 +13759,36 @@ virDomainMemorySourceDefParseXML(xmlNodePtr node,
     xmlNodePtr save = ctxt->node;
     ctxt->node = node;
 
-    if (virDomainParseMemory("./pagesize", "./pagesize/@unit", ctxt,
-                             &def->pagesize, false, false) < 0)
-        goto cleanup;
-
-    if ((nodemask = virXPathString("string(./nodemask)", ctxt))) {
-        if (virBitmapParse(nodemask, &def->sourceNodes,
-                           VIR_DOMAIN_CPUMASK_LEN) < 0)
+    switch ((virDomainMemoryModel) def->model) {
+    case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+        if (virDomainParseMemory("./pagesize", "./pagesize/@unit", ctxt,
+                                 &def->pagesize, false, false) < 0)
             goto cleanup;
 
-        if (virBitmapIsAllClear(def->sourceNodes)) {
-            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                           _("Invalid value of 'nodemask': %s"), nodemask);
+        if ((nodemask = virXPathString("string(./nodemask)", ctxt))) {
+            if (virBitmapParse(nodemask, &def->sourceNodes,
+                               VIR_DOMAIN_CPUMASK_LEN) < 0)
+                goto cleanup;
+
+            if (virBitmapIsAllClear(def->sourceNodes)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("Invalid value of 'nodemask': %s"), nodemask);
+                goto cleanup;
+            }
+        }
+        break;
+
+    case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+        if (!(def->path = virXPathString("string(./path)", ctxt))) {
+            virReportError(VIR_ERR_XML_DETAIL, "%s",
+                           _("path is required for model nvdimm'"));
             goto cleanup;
         }
+        break;
+
+    case VIR_DOMAIN_MEMORY_MODEL_NONE:
+    case VIR_DOMAIN_MEMORY_MODEL_LAST:
+        break;
     }
 
     ret = 0;
@@ -15173,12 +15193,25 @@ virDomainMemoryFindByDefInternal(virDomainDefPtr def,
             tmp->size != mem->size)
             continue;
 
-        /* source stuff -> match with device */
-        if (tmp->pagesize != mem->pagesize)
-            continue;
+        switch ((virDomainMemoryModel) mem->model) {
+        case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+            /* source stuff -> match with device */
+            if (tmp->pagesize != mem->pagesize)
+                continue;
 
-        if (!virBitmapEqual(tmp->sourceNodes, mem->sourceNodes))
-            continue;
+            if (!virBitmapEqual(tmp->sourceNodes, mem->sourceNodes))
+                continue;
+            break;
+
+        case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+            if (STRNEQ(tmp->path, mem->path))
+                continue;
+            break;
+
+        case VIR_DOMAIN_MEMORY_MODEL_NONE:
+        case VIR_DOMAIN_MEMORY_MODEL_LAST:
+            break;
+        }
 
         break;
     }
@@ -22571,23 +22604,35 @@ virDomainMemorySourceDefFormat(virBufferPtr buf,
     char *bitmap = NULL;
     int ret = -1;
 
-    if (!def->pagesize && !def->sourceNodes)
+    if (!def->pagesize && !def->sourceNodes && !def->path)
         return 0;
 
     virBufferAddLit(buf, "<source>\n");
     virBufferAdjustIndent(buf, 2);
 
-    if (def->sourceNodes) {
-        if (!(bitmap = virBitmapFormat(def->sourceNodes)))
-            goto cleanup;
+    switch ((virDomainMemoryModel) def->model) {
+    case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+        if (def->sourceNodes) {
+            if (!(bitmap = virBitmapFormat(def->sourceNodes)))
+                goto cleanup;
 
-        virBufferAsprintf(buf, "<nodemask>%s</nodemask>\n", bitmap);
+            virBufferAsprintf(buf, "<nodemask>%s</nodemask>\n", bitmap);
+        }
+
+        if (def->pagesize)
+            virBufferAsprintf(buf, "<pagesize unit='KiB'>%llu</pagesize>\n",
+                              def->pagesize);
+        break;
+
+    case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+        virBufferAsprintf(buf, "<path>%s</path>\n", def->path);
+        break;
+
+    case VIR_DOMAIN_MEMORY_MODEL_NONE:
+    case VIR_DOMAIN_MEMORY_MODEL_LAST:
+        break;
     }
 
-    if (def->pagesize)
-        virBufferAsprintf(buf, "<pagesize unit='KiB'>%llu</pagesize>\n",
-                          def->pagesize);
-
     virBufferAdjustIndent(buf, -2);
     virBufferAddLit(buf, "</source>\n");
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 1e53cc328..dc949d3c9 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1996,6 +1996,7 @@ struct _virDomainRNGDef {
 typedef enum {
     VIR_DOMAIN_MEMORY_MODEL_NONE,
     VIR_DOMAIN_MEMORY_MODEL_DIMM, /* dimm hotpluggable memory device */
+    VIR_DOMAIN_MEMORY_MODEL_NVDIMM, /* nvdimm memory device */
 
     VIR_DOMAIN_MEMORY_MODEL_LAST
 } virDomainMemoryModel;
@@ -2004,6 +2005,7 @@ struct _virDomainMemoryDef {
     /* source */
     virBitmapPtr sourceNodes;
     unsigned long long pagesize; /* kibibytes */
+    char *path;
 
     /* target */
     int model; /* virDomainMemoryModel */
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 7c52712d1..f628a9929 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3421,6 +3421,12 @@ 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;
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index c187214dc..5ec610564 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -5910,6 +5910,11 @@ 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;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.xml b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.xml
new file mode 100644
index 000000000..1578db453
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.xml
@@ -0,0 +1,56 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <maxMemory slots='16' unit='KiB'>1099511627776</maxMemory>
+  <memory unit='KiB'>1267710</memory>
+  <currentMemory unit='KiB'>1267710</currentMemory>
+  <vcpu placement='static' cpuset='0-1'>2</vcpu>
+  <os>
+    <type arch='i686' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <idmap>
+    <uid start='0' target='1000' count='10'/>
+    <gid start='0' target='1000' count='10'/>
+  </idmap>
+  <cpu>
+    <topology sockets='2' cores='1' threads='1'/>
+    <numa>
+      <cell id='0' cpus='0-1' memory='1048576' unit='KiB'/>
+    </numa>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu</emulator>
+    <disk type='block' device='disk'>
+      <source dev='/dev/HostVG/QEMUGuest1'/>
+      <target dev='hda' bus='ide'/>
+      <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+    </disk>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <controller type='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </memballoon>
+    <memory model='nvdimm'>
+      <source>
+        <path>/tmp/nvdimm</path>
+      </source>
+      <target>
+        <size unit='KiB'>523264</size>
+        <node>0</node>
+      </target>
+      <address type='dimm' slot='0'/>
+    </memory>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-memory-hotplug-nvdimm.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-memory-hotplug-nvdimm.xml
new file mode 120000
index 000000000..4cac477a9
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-memory-hotplug-nvdimm.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 4353ad245..e1c341dd5 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -1078,6 +1078,7 @@ mymain(void)
     DO_TEST("memory-hotplug", NONE);
     DO_TEST("memory-hotplug-nonuma", NONE);
     DO_TEST("memory-hotplug-dimm", NONE);
+    DO_TEST("memory-hotplug-nvdimm", NONE);
     DO_TEST("net-udp", NONE);
 
     DO_TEST("video-virtio-gpu-device", NONE);
-- 
2.11.0




More information about the libvir-list mailing list