]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Introduce NVDIMM memory model
authorMichal Privoznik <mprivozn@redhat.com>
Thu, 28 Jul 2016 16:54:18 +0000 (18:54 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Wed, 15 Mar 2017 12:30:58 +0000 (13:30 +0100)
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, NVDIMM will utilize the
existing <memory/> element that lives under <devices/> by adding
a new attribute 'nvdimm' to the existing @model and introduce a
new <path/> element for <source/> while reusing other fields. The
resulting XML would appear as:

    <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@redhat.com>
docs/formatdomain.html.in
docs/schemas/domaincommon.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/qemu/qemu_command.c
src/qemu/qemu_domain.c
tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.xml [new file with mode: 0644]
tests/qemuxml2xmloutdata/qemuxml2xmlout-memory-hotplug-nvdimm.xml [new symlink]
tests/qemuxml2xmltest.c

index 9a204f845c12f06c2a3fa6346d8d7d8a8c275c3b..0189920a84e7fa6e12a599c41431a9535a2cc922 100644 (file)
@@ -7092,7 +7092,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>
@@ -7117,6 +7116,15 @@ qemu-kvm -net nic,model=? /dev/null
       &lt;node&gt;1&lt;/node&gt;
     &lt;/target&gt;
   &lt;/memory&gt;
+  &lt;memory model='nvdimm'&gt;
+    &lt;source&gt;
+      &lt;path&gt;/tmp/nvdimm&lt;/path&gt;
+    &lt;/source&gt;
+    &lt;target&gt;
+      &lt;size unit='KiB'&gt;524288&lt;/size&gt;
+      &lt;node&gt;1&lt;/node&gt;
+    &lt;/target&gt;
+  &lt;/memory&gt;
 &lt;/devices&gt;
 ...
 </pre>
@@ -7124,28 +7132,48 @@ 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.2.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 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 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>
 
index 5e593285efd0d9cdc35b1e05a55e9fc015d14fa2..2f6a6db8e89eca50f7be4fe6f0c9a5a8d4be61b8 100644 (file)
       <attribute name="model">
         <choice>
           <value>dimm</value>
+          <value>nvdimm</value>
         </choice>
       </attribute>
       <interleave>
 
   <define name="memorydev-source">
     <element name="source">
-      <interleave>
-        <optional>
-          <element name="pagesize">
-            <ref name="scaledInteger"/>
-          </element>
-        </optional>
-        <optional>
-          <element name="nodemask">
-            <ref name="cpuset"/>
+      <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">
+            <ref name="absFilePath"/>
           </element>
-        </optional>
-      </interleave>
+        </group>
+      </choice>
     </element>
   </define>
 
index 88d419e27d46bdb7f70ce72fdcee2e501a699bb6..9713bfc40239234109dd4e4b8e6c7f958b62dad3 100644 (file)
@@ -859,8 +859,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",
@@ -2419,6 +2422,7 @@ void virDomainMemoryDefFree(virDomainMemoryDefPtr def)
     if (!def)
         return;
 
+    VIR_FREE(def->nvdimmPath);
     virBitmapFree(def->sourceNodes);
     virDomainDeviceInfoClear(&def->info);
     VIR_FREE(def);
@@ -13716,20 +13720,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->nvdimmPath = 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;
@@ -15134,12 +15154,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->nvdimmPath, mem->nvdimmPath))
+                continue;
+            break;
+
+        case VIR_DOMAIN_MEMORY_MODEL_NONE:
+        case VIR_DOMAIN_MEMORY_MODEL_LAST:
+            break;
+        }
 
         break;
     }
@@ -22532,22 +22565,34 @@ virDomainMemorySourceDefFormat(virBufferPtr buf,
     char *bitmap = NULL;
     int ret = -1;
 
-    if (!def->pagesize && !def->sourceNodes)
+    if (!def->pagesize && !def->sourceNodes && !def->nvdimmPath)
         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;
 
-    if (def->pagesize)
-        virBufferAsprintf(buf, "<pagesize unit='KiB'>%llu</pagesize>\n",
-                          def->pagesize);
+    case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+        virBufferEscapeString(buf, "<path>%s</path>\n", def->nvdimmPath);
+        break;
+
+    case VIR_DOMAIN_MEMORY_MODEL_NONE:
+    case VIR_DOMAIN_MEMORY_MODEL_LAST:
+        break;
+    }
 
     virBufferAdjustIndent(buf, -2);
     virBufferAddLit(buf, "</source>\n");
index b788a827102342d1d3b867987212b2c349d8bf11..2eff9f74a4f1bc265ae5d91469a8f61753dc7497 100644 (file)
@@ -1997,6 +1997,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;
@@ -2005,6 +2006,7 @@ struct _virDomainMemoryDef {
     /* source */
     virBitmapPtr sourceNodes;
     unsigned long long pagesize; /* kibibytes */
+    char *nvdimmPath;
 
     /* target */
     int model; /* virDomainMemoryModel */
index 16f5aa90983fd79ec2000ecdda953f6cbdf88fed..b52be4bb69cffab779e90deb728e95eec367a426 100644 (file)
@@ -3515,6 +3515,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;
index 07ce22417af8dbe747985160378f59a84f343f75..b34ba7efbd0e737b6efc861535097f22c5282042 100644 (file)
@@ -5967,6 +5967,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 (file)
index 0000000..1578db4
--- /dev/null
@@ -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 (symlink)
index 0000000..4cac477
--- /dev/null
@@ -0,0 +1 @@
+../qemuxml2argvdata/qemuxml2argv-memory-hotplug-nvdimm.xml
\ No newline at end of file
index 4353ad2456dc7a2efe066aba00e6536c5d6c3612..e1c341dd5c918a6acc110fef9a046ab41609ec75 100644 (file)
@@ -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);