[PATCH v6 04/16] conf: Introduce virtio-mem <memory/> model

Michal Privoznik mprivozn at redhat.com
Tue Sep 21 13:51:20 UTC 2021


The virtio-mem is paravirtualized mechanism of adding/removing
memory to/from a VM. A virtio-mem-pci device is split into blocks
of equal size which are then exposed (all or only a requested
portion of them) to the guest kernel to use as regular memory.
Therefore, the device has two important attributes:

  1) block-size, which defines the size of a block
  2) requested-size, which defines how much memory (in bytes)
     is the device requested to expose to the guest.

The 'block-size' is configured on command line and immutable
throughout device's lifetime. The 'requested-size' can be set on
the command line too, but also is adjustable via monitor. In
fact, that is how management software places its requests to
change the memory allocation. If it wants to give more memory to
the guest it changes 'requested-size' to a bigger value, and if it
wants to shrink guest memory it changes the 'requested-size' to a
smaller value. Note, value of zero means that guest should
release all memory offered by the device. Of course, guest has to
cooperate. Therefore, there is a third attribute 'size' which is
read only and reflects how much memory the guest still has. This
can be different to 'requested-size', obviously. Because of name
clash, I've named it 'current' and it is dealt with in future
commits (it is a runtime information anyway).

In the backend, memory for virtio-mem is backed by usual objects:
memory-backend-{ram,file,memfd} and their size puts the cap on
the amount of memory that a virtio-mem device can offer to a
guest. But we are already able to express this info using <size/>
under <target/>.

Therefore, we need only two more elements to cover 'block-size'
and 'requested-size' attributes. This is the XML I've came up
with:

  <memory model='virtio-mem'>
    <source>
      <nodemask>1-3</nodemask>
      <pagesize unit='KiB'>2048</pagesize>
    </source>
    <target>
      <size unit='KiB'>2097152</size>
      <node>0</node>
      <block unit='KiB'>2048</block>
      <requested unit='KiB'>1048576</requested>
    </target>
    <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
  </memory>

I hope by now it is obvious that:

  1) 'requested-size' must be an integer multiple of
     'block-size', and
  2) virtio-mem-pci device goes onto PCI bus and thus needs PCI
     address.

Then there is a limitation that the minimal 'block-size' is
transparent huge page size (I'll leave this without explanation).

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 docs/formatdomain.rst                         | 38 +++++++++--
 docs/schemas/domaincommon.rng                 | 11 +++
 src/conf/domain_conf.c                        | 53 ++++++++++++++-
 src/conf/domain_conf.h                        |  3 +
 src/conf/domain_validate.c                    | 39 +++++++++++
 src/qemu/qemu_alias.c                         |  1 +
 src/qemu/qemu_command.c                       |  1 +
 src/qemu/qemu_domain.c                        | 10 +++
 src/qemu/qemu_domain_address.c                | 38 ++++++++---
 src/qemu/qemu_process.c                       |  2 +
 src/qemu/qemu_validate.c                      |  8 +++
 src/security/security_apparmor.c              |  1 +
 src/security/security_dac.c                   |  2 +
 src/security/security_selinux.c               |  2 +
 .../memory-hotplug-virtio-mem.xml             | 67 +++++++++++++++++++
 ...emory-hotplug-virtio-mem.x86_64-latest.xml |  1 +
 tests/qemuxml2xmltest.c                       |  1 +
 17 files changed, 261 insertions(+), 17 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/memory-hotplug-virtio-mem.xml
 create mode 120000 tests/qemuxml2xmloutdata/memory-hotplug-virtio-mem.x86_64-latest.xml

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index 0f5d833521..87fa8b617d 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -7792,6 +7792,18 @@ Example: usage of the memory devices
          <size unit='KiB'>524288</size>
        </target>
      </memory>
+     <memory model='virtio-mem'>
+       <source>
+         <nodemask>1-3</nodemask>
+         <pagesize unit='KiB'>2048</pagesize>
+       </source>
+       <target>
+         <size unit='KiB'>2097152</size>
+         <node>0</node>
+         <block unit='KiB'>2048</block>
+         <requested unit='KiB'>1048576</requested>
+       </target>
+     </memory>
    </devices>
    ...
 
@@ -7799,7 +7811,8 @@ Example: usage of the memory devices
    Provide ``dimm`` to add a virtual DIMM module to the guest. :since:`Since
    1.2.14` Provide ``nvdimm`` model that adds a Non-Volatile DIMM module.
    :since:`Since 3.2.0` Provide ``virtio-pmem`` model to add a paravirtualized
-   persistent memory device. :since:`Since 7.1.0`
+   persistent memory device. :since:`Since 7.1.0` Provide ``virtio-mem`` model
+   to add paravirtualized memory device. :since:`Since 7.4.0`
 
 ``access``
    An optional attribute ``access`` ( :since:`since 3.2.0` ) that provides
@@ -7822,10 +7835,11 @@ Example: usage of the memory devices
    allowed only for ``model='nvdimm'`` for pSeries guests. :since:`Since 6.2.0`
 
 ``source``
-   For model ``dimm`` 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 ``numatune`` are used. If ``dimm`` is
-   provided, then the following optional elements can be provided as well:
+   For model ``dimm`` and model ``virtio-mem`` 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 ``numatune``
+   are used. If the element is provided, then the following optional elements
+   can be provided:
 
    ``pagesize``
       This element can be used to override the default host page size used for
@@ -7864,7 +7878,8 @@ Example: usage of the memory devices
    added memory from the perspective of the guest.
 
    The mandatory ``size`` subelement configures the size of the added memory as
-   a scaled integer.
+   a scaled integer. For ``virtio-mem`` this represents the maximum possible
+   size exposed to the guest.
 
    The ``node`` subelement configures the guest NUMA node to attach the memory
    to. The element shall be used only if the guest has NUMA nodes configured.
@@ -7891,6 +7906,17 @@ Example: usage of the memory devices
       so other backend types should use the ``readonly`` element. :since:`Since
       5.0.0`
 
+   ``block``
+     For ``virtio-mem`` only.
+     The size of an individual block, granularity of division of memory block.
+     Must be power of two and at least equal to size of a transparent hugepage
+     (2MiB on x84_64). The default is hypervisor dependent.
+
+   ``requested``
+     For ``virtio-mem`` only.
+     The total size exposed to the guest. Must respect ``block`` granularity
+     and be smaller than or equal to ``size``.
+
 :anchor:`<a id="elementsIommu"/>`
 
 IOMMU devices
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index fdc04f90aa..9e7d74d43e 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -6600,6 +6600,7 @@
           <value>dimm</value>
           <value>nvdimm</value>
           <value>virtio-pmem</value>
+          <value>virtio-mem</value>
         </choice>
       </attribute>
       <optional>
@@ -6687,6 +6688,16 @@
             <ref name="unsignedInt"/>
           </element>
         </optional>
+        <optional>
+          <element name="block">
+            <ref name="scaledInteger"/>
+          </element>
+        </optional>
+        <optional>
+          <element name="requested">
+            <ref name="scaledInteger"/>
+          </element>
+        </optional>
         <optional>
           <element name="label">
             <element name="size">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 62b9720d0a..82d4d124ad 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1392,6 +1392,7 @@ VIR_ENUM_IMPL(virDomainMemoryModel,
               "dimm",
               "nvdimm",
               "virtio-pmem",
+              "virtio-mem",
 );
 
 VIR_ENUM_IMPL(virDomainShmemModel,
@@ -5494,6 +5495,7 @@ virDomainMemoryDefPostParse(virDomainMemoryDef *mem,
         }
         break;
 
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
@@ -14653,6 +14655,7 @@ virDomainMemorySourceDefParseXML(xmlNodePtr node,
 
     switch (def->model) {
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
         if (virDomainParseMemory("./pagesize", "./pagesize/@unit", ctxt,
                                  &def->pagesize, false, false) < 0)
             return -1;
@@ -14719,7 +14722,8 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node,
                              &def->size, true, false) < 0)
         return -1;
 
-    if (def->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
+    switch (def->model) {
+    case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
         if (virDomainParseMemory("./label/size", "./label/size/@unit", ctxt,
                                  &def->labelsize, false, false) < 0)
             return -1;
@@ -14738,6 +14742,23 @@ virDomainMemoryTargetDefParseXML(xmlNodePtr node,
 
         if (virXPathBoolean("boolean(./readonly)", ctxt))
             def->readonly = true;
+        break;
+
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+        if (virDomainParseMemory("./block", "./block/@unit", ctxt,
+                                 &def->blocksize, false, false) < 0)
+            return -1;
+
+        if (virDomainParseMemory("./requested", "./requested/@unit", ctxt,
+                                 &def->requestedsize, false, false) < 0)
+            return -1;
+        break;
+
+    case VIR_DOMAIN_MEMORY_MODEL_NONE:
+    case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
+    case VIR_DOMAIN_MEMORY_MODEL_LAST:
+        break;
     }
 
     return 0;
@@ -16494,11 +16515,14 @@ virDomainMemoryFindByDefInternal(virDomainDef *def,
         /* target info -> always present */
         if (tmp->model != mem->model ||
             tmp->targetNode != mem->targetNode ||
-            tmp->size != mem->size)
+            tmp->size != mem->size ||
+            tmp->blocksize != mem->blocksize ||
+            tmp->requestedsize != mem->requestedsize)
             continue;
 
         switch (mem->model) {
         case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+        case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
             /* source stuff -> match with device */
             if (tmp->pagesize != mem->pagesize)
                 continue;
@@ -21892,6 +21916,22 @@ virDomainMemoryDefCheckABIStability(virDomainMemoryDef *src,
         return false;
     }
 
+    if (src->blocksize != dst->blocksize) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target memory device block size '%llu' doesn't match "
+                         "source memory device block size '%llu'"),
+                       dst->blocksize, src->blocksize);
+        return false;
+    }
+
+    if (src->requestedsize != dst->requestedsize) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target memory device requested size '%llu' doesn't match "
+                         "source memory device requested size '%llu'"),
+                       dst->requestedsize, src->requestedsize);
+        return false;
+    }
+
     if (src->model == VIR_DOMAIN_MEMORY_MODEL_NVDIMM) {
         if (src->labelsize != dst->labelsize) {
             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -25800,6 +25840,7 @@ virDomainMemorySourceDefFormat(virBuffer *buf,
 
     switch (def->model) {
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
         if (def->sourceNodes) {
             if (!(bitmap = virBitmapFormat(def->sourceNodes)))
                 return -1;
@@ -25856,6 +25897,14 @@ virDomainMemoryTargetDefFormat(virBuffer *buf,
     if (def->readonly)
         virBufferAddLit(&childBuf, "<readonly/>\n");
 
+    if (def->blocksize) {
+        virBufferAsprintf(&childBuf, "<block unit='KiB'>%llu</block>\n",
+                          def->blocksize);
+
+        virBufferAsprintf(&childBuf, "<requested unit='KiB'>%llu</requested>\n",
+                          def->requestedsize);
+    }
+
     virXMLFormatElement(buf, "target", NULL, &childBuf);
 }
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 688a842660..8356d38dcb 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2473,6 +2473,7 @@ typedef enum {
     VIR_DOMAIN_MEMORY_MODEL_DIMM, /* dimm hotpluggable memory device */
     VIR_DOMAIN_MEMORY_MODEL_NVDIMM, /* nvdimm memory device */
     VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM, /* virtio-pmem memory device */
+    VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM, /* virtio-mem memory device */
 
     VIR_DOMAIN_MEMORY_MODEL_LAST
 } virDomainMemoryModel;
@@ -2493,6 +2494,8 @@ struct _virDomainMemoryDef {
     int targetNode;
     unsigned long long size; /* kibibytes */
     unsigned long long labelsize; /* kibibytes; valid only for NVDIMM */
+    unsigned long long blocksize; /* kibibytes; valid only for VIRTIO_MEM */
+    unsigned long long requestedsize; /* kibibytes; valid only for VIRTIO_MEM */
     bool readonly; /* valid only for NVDIMM */
 
     /* required for QEMU NVDIMM ppc64 support */
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index 1bc62c364d..f023d22f23 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -28,6 +28,7 @@
 #include "virlog.h"
 #include "virutil.h"
 #include "virstring.h"
+#include "virhostmem.h"
 
 #define VIR_FROM_THIS VIR_FROM_DOMAIN
 
@@ -1966,6 +1967,8 @@ static int
 virDomainMemoryDefValidate(const virDomainMemoryDef *mem,
                            const virDomainDef *def)
 {
+    unsigned long long thpSize;
+
     switch (mem->model) {
     case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
         if (!mem->nvdimmPath) {
@@ -2019,6 +2022,42 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem,
                            _("virtio-pmem does not support NUMA nodes"));
             return -1;
         }
+        break;
+
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+        if (mem->requestedsize > mem->size) {
+            virReportError(VIR_ERR_XML_DETAIL, "%s",
+                           _("requested size must be smaller than or equal to @size"));
+            return -1;
+        }
+
+        if (!VIR_IS_POW2(mem->blocksize)) {
+            virReportError(VIR_ERR_XML_DETAIL, "%s",
+                           _("block size must be a power of two"));
+            return -1;
+        }
+
+        if (virHostMemGetTHPSize(&thpSize) < 0) {
+            /* We failed to get THP size, fall back to a sane default. On
+             * almost every architecture the size will be 2MiB, except for some
+             * funky arches like sparc and m68k. Use 2MiB and refine later if
+             * somebody complains. */
+            thpSize = 2048;
+        }
+
+        if (mem->blocksize < thpSize) {
+            virReportError(VIR_ERR_XML_DETAIL,
+                           _("block size too small, must be at least %lluKiB"),
+                           thpSize);
+            return -1;
+        }
+
+        if (mem->requestedsize % mem->blocksize != 0) {
+            virReportError(VIR_ERR_XML_DETAIL, "%s",
+                           _("requested size must be an integer multiple of block size"));
+            return -1;
+        }
+        break;
 
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
         break;
diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index ed47fa335a..79e8953b2f 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -522,6 +522,7 @@ qemuAssignDeviceMemoryAlias(virDomainDef *def,
     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
         prefix = "virtiopmem";
         break;
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
     default:
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 3de37aa5c5..8beb3cdedc 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3320,6 +3320,7 @@ qemuBuildMemoryDeviceStr(const virDomainDef *def,
         device = "virtio-pmem-pci";
         break;
 
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
     default:
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 5de7461fb3..298f9b076d 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -9038,6 +9038,16 @@ qemuDomainDefValidateMemoryHotplugDevice(const virDomainMemoryDef *mem,
         needsNuma = false;
         break;
 
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+        if (mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
+            mem->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("only 'pci' addresses are supported for the %s device"),
+                           virDomainMemoryModelTypeToString(mem->model));
+            return -1;
+        }
+        break;
+
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         return -1;
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 392368bd38..c43ad23cf5 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -380,9 +380,18 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDef *def,
     }
 
     for (i = 0; i < def->nmems; i++) {
-        if (def->mems[i]->model == VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM &&
-            def->mems[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
-            def->mems[i]->info.type = type;
+        switch (def->mems[i]->model) {
+        case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
+        case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+            if (def->mems[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+                def->mems[i]->info.type = type;
+            break;
+        case VIR_DOMAIN_MEMORY_MODEL_NONE:
+        case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+        case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+        case VIR_DOMAIN_MEMORY_MODEL_LAST:
+            break;
+        }
     }
 
     if (type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
@@ -1010,6 +1019,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev,
     case VIR_DOMAIN_DEVICE_MEMORY:
         switch (dev->data.memory->model) {
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
+        case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
             return virtioFlags;
 
         case VIR_DOMAIN_MEMORY_MODEL_NONE:
@@ -2370,12 +2380,19 @@ qemuDomainAssignDevicePCISlots(virDomainDef *def,
     for (i = 0; i < def->nmems; i++) {
         virDomainMemoryDef *mem = def->mems[i];
 
-        if (mem->model != VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM ||
-            !virDeviceInfoPCIAddressIsWanted(&mem->info))
-            continue;
-
-        if (qemuDomainPCIAddressReserveNextAddr(addrs, &mem->info) < 0)
-            return -1;
+        switch (mem->model) {
+        case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
+        case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+            if (virDeviceInfoPCIAddressIsWanted(&mem->info) &&
+                qemuDomainPCIAddressReserveNextAddr(addrs, &mem->info) < 0)
+                return -1;
+            break;
+        case VIR_DOMAIN_MEMORY_MODEL_NONE:
+        case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+        case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
+        case VIR_DOMAIN_MEMORY_MODEL_LAST:
+            break;
+        }
     }
 
     return 0;
@@ -3034,6 +3051,7 @@ qemuDomainAssignMemoryDeviceSlot(virQEMUDriver *driver,
         break;
 
     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
         return qemuDomainEnsurePCIAddress(vm, &dev, driver);
         break;
 
@@ -3059,6 +3077,7 @@ qemuDomainReleaseMemoryDeviceSlot(virDomainObj *vm,
         break;
 
     case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
         qemuDomainReleaseDeviceAddress(vm, &mem->info);
         break;
 
@@ -3093,6 +3112,7 @@ qemuDomainAssignMemorySlots(virDomainDef *def)
             break;
 
         case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_PMEM:
+        case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
             /* handled in qemuDomainAssignPCIAddresses() */
             break;
         case VIR_DOMAIN_MEMORY_MODEL_NONE:
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 632cb817b9..07bd7e928a 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3791,6 +3791,7 @@ qemuProcessDomainMemoryDefNeedHugepagesPath(const virDomainMemoryDef *mem,
 {
     switch (mem->model) {
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
         return mem->pagesize && mem->pagesize != system_pagesize;
 
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
@@ -3859,6 +3860,7 @@ qemuProcessNeedMemoryBackingPath(virDomainDef *def,
     if (mem) {
         switch (mem->model) {
         case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+        case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
             if (mem->access != VIR_DOMAIN_MEMORY_ACCESS_DEFAULT) {
                 /* No need to check for access mode on the target node,
                  * it was checked for in the previous loop. */
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index 4fc344b493..444d9eff03 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -4964,6 +4964,14 @@ qemuValidateDomainDeviceDefMemory(virDomainMemoryDef *mem,
         }
         break;
 
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
+        if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_MEM_PCI)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                           _("virtio-mem isn't supported by this QEMU binary"));
+            return -1;
+        }
+        break;
+
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         break;
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index d942ea5005..2cc15ba6af 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -693,6 +693,7 @@ AppArmorSetMemoryLabel(virSecurityManager *mgr,
         return reload_profile(mgr, def, mem->nvdimmPath, true);
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         break;
     }
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 04b9ecf028..1733d63410 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -1849,6 +1849,7 @@ virSecurityDACRestoreMemoryLabel(virSecurityManager *mgr,
         break;
 
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
         ret = 0;
@@ -2033,6 +2034,7 @@ virSecurityDACSetMemoryLabel(virSecurityManager *mgr,
         break;
 
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
         ret = 0;
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 0e5ea0366d..cc72453329 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -1582,6 +1582,7 @@ virSecuritySELinuxSetMemoryLabel(virSecurityManager *mgr,
 
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         break;
     }
@@ -1609,6 +1610,7 @@ virSecuritySELinuxRestoreMemoryLabel(virSecurityManager *mgr,
         break;
 
     case VIR_DOMAIN_MEMORY_MODEL_DIMM:
+    case VIR_DOMAIN_MEMORY_MODEL_VIRTIO_MEM:
     case VIR_DOMAIN_MEMORY_MODEL_NONE:
     case VIR_DOMAIN_MEMORY_MODEL_LAST:
         ret = 0;
diff --git a/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.xml b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.xml
new file mode 100644
index 0000000000..c10528aad8
--- /dev/null
+++ b/tests/qemuxml2argvdata/memory-hotplug-virtio-mem.xml
@@ -0,0 +1,67 @@
+<domain type='kvm'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <maxMemory slots='16' unit='KiB'>1099511627776</maxMemory>
+  <memory unit='KiB'>8388608</memory>
+  <currentMemory unit='KiB'>8388608</currentMemory>
+  <vcpu placement='static' cpuset='0-1'>2</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu mode='custom' match='exact' check='none'>
+    <model fallback='forbid'>qemu64</model>
+    <topology sockets='2' dies='1' cores='1' threads='1'/>
+    <numa>
+      <cell id='0' cpus='0-1' memory='2095104' 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-system-i386</emulator>
+    <disk type='block' device='disk'>
+      <driver name='qemu' type='raw'/>
+      <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' model='piix3-uhci'>
+      <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'/>
+    <audio id='1' type='none'/>
+    <memballoon model='virtio'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </memballoon>
+    <memory model='virtio-mem'>
+      <target>
+        <size unit='KiB'>1048576</size>
+        <node>0</node>
+        <block unit='KiB'>2048</block>
+        <requested unit='KiB'>524288</requested>
+      </target>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
+    </memory>
+    <memory model='virtio-mem'>
+      <source>
+        <nodemask>1-3</nodemask>
+        <pagesize unit='KiB'>2048</pagesize>
+      </source>
+      <target>
+        <size unit='KiB'>2097152</size>
+        <node>0</node>
+        <block unit='KiB'>2048</block>
+        <requested unit='KiB'>1048576</requested>
+      </target>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </memory>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmloutdata/memory-hotplug-virtio-mem.x86_64-latest.xml b/tests/qemuxml2xmloutdata/memory-hotplug-virtio-mem.x86_64-latest.xml
new file mode 120000
index 0000000000..a9d298129c
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/memory-hotplug-virtio-mem.x86_64-latest.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/memory-hotplug-virtio-mem.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 59d1e24289..f264320f48 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -1214,6 +1214,7 @@ mymain(void)
                  QEMU_CAPS_DEVICE_NVDIMM,
                  QEMU_CAPS_LAST, ARG_END);
     DO_TEST_CAPS_LATEST("memory-hotplug-virtio-pmem");
+    DO_TEST_CAPS_LATEST("memory-hotplug-virtio-mem");
 
     DO_TEST_NOCAPS("net-udp");
 
-- 
2.32.0




More information about the libvir-list mailing list