diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index d2344c894a..4388ad545f 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -1112,8 +1112,11 @@ NUMA Node Tuning
``memory``
The optional ``memory`` element specifies how to allocate memory for the
domain process on a NUMA host. It contains several optional attributes.
- Attribute ``mode`` is either 'interleave', 'strict', or 'preferred', defaults
- to 'strict'. Attribute ``nodeset`` specifies the NUMA nodes, using the same
+ Attribute ``mode`` is either 'interleave', 'strict', 'preferred', or
+ 'restrictive', defaults to 'strict'. The value 'restrictive' specifies
+ using system default policy and only cgroups is used to restrict the
+ memory nodes, and it requires setting mode to 'restrictive' in ``memnode``
+ elements. Attribute ``nodeset`` specifies the NUMA nodes, using the same
syntax as attribute ``cpuset`` of element ``vcpu``. Attribute ``placement`` (
:since:`since 0.9.12` ) can be used to indicate the memory placement mode for
domain process, its value can be either "static" or "auto", defaults to
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 99cd873832..20a43148b1 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -1107,6 +1107,7 @@
strict
preferred
interleave
+ restrictive
@@ -1139,6 +1140,7 @@
strict
preferred
interleave
+ restrictive
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index 03c119fe26..e99bfb7654 100644
--- a/include/libvirt/libvirt-domain.h
+++ b/include/libvirt/libvirt-domain.h
@@ -1527,6 +1527,7 @@ typedef enum {
VIR_DOMAIN_NUMATUNE_MEM_STRICT = 0,
VIR_DOMAIN_NUMATUNE_MEM_PREFERRED = 1,
VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE = 2,
+ VIR_DOMAIN_NUMATUNE_MEM_RESTRICTIVE = 3,
# ifdef VIR_ENUM_SENTINELS
VIR_DOMAIN_NUMATUNE_MEM_LAST /* This constant is subject to change */
diff --git a/src/conf/numa_conf.c b/src/conf/numa_conf.c
index e28c86284f..932af4a185 100644
--- a/src/conf/numa_conf.c
+++ b/src/conf/numa_conf.c
@@ -43,6 +43,7 @@ VIR_ENUM_IMPL(virDomainNumatuneMemMode,
"strict",
"preferred",
"interleave",
+ "restrictive",
);
VIR_ENUM_IMPL(virDomainNumatunePlacement,
@@ -230,6 +231,14 @@ virDomainNumatuneNodeParseXML(virDomainNuma *numa,
_("Invalid mode attribute in memnode element"));
goto cleanup;
}
+
+ if (numa->memory.mode == VIR_DOMAIN_NUMATUNE_MEM_RESTRICTIVE &&
+ mode != VIR_DOMAIN_NUMATUNE_MEM_RESTRICTIVE) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("'restrictive' mode is required in memnode element "
+ "when mode is 'restrictive' in memory element"));
+ goto cleanup;
+ }
VIR_FREE(tmp);
mem_node->mode = mode;
}
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 77d8e3f38c..6d40983ce1 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -175,6 +175,7 @@ VIR_ENUM_IMPL(qemuNumaPolicy,
"bind",
"preferred",
"interleave",
+ "restrictive",
);
VIR_ENUM_DECL(qemuAudioDriver);
diff --git a/src/util/virnuma.c b/src/util/virnuma.c
index 0c9599003a..31f65d8902 100644
--- a/src/util/virnuma.c
+++ b/src/util/virnuma.c
@@ -152,6 +152,9 @@ virNumaSetupMemoryPolicy(virDomainNumatuneMemMode mode,
numa_set_interleave_mask(&mask);
break;
+ case VIR_DOMAIN_NUMATUNE_MEM_RESTRICTIVE:
+ break;
+
case VIR_DOMAIN_NUMATUNE_MEM_LAST:
break;
}
diff --git a/tests/qemuxml2argvdata/numatune-memnode-invalid-mode.err b/tests/qemuxml2argvdata/numatune-memnode-invalid-mode.err
new file mode 100644
index 0000000000..180e64d1d8
--- /dev/null
+++ b/tests/qemuxml2argvdata/numatune-memnode-invalid-mode.err
@@ -0,0 +1 @@
+XML error: 'restrictive' mode is required in memnode element when mode is 'restrictive' in memory element
diff --git a/tests/qemuxml2argvdata/numatune-memnode-invalid-mode.xml b/tests/qemuxml2argvdata/numatune-memnode-invalid-mode.xml
new file mode 100644
index 0000000000..a7c18d4d50
--- /dev/null
+++ b/tests/qemuxml2argvdata/numatune-memnode-invalid-mode.xml
@@ -0,0 +1,33 @@
+
+ QEMUGuest
+ 9f4b6512-e73a-4a25-93e8-5307802821ce
+ 24682468
+ 24682468
+ 32
+
+
+
+
+
+
+ hvm
+
+
+
+
+ |
+ |
+ |
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
diff --git a/tests/qemuxml2argvdata/numatune-memnode-restrictive-mode.xml b/tests/qemuxml2argvdata/numatune-memnode-restrictive-mode.xml
new file mode 100644
index 0000000000..012c526460
--- /dev/null
+++ b/tests/qemuxml2argvdata/numatune-memnode-restrictive-mode.xml
@@ -0,0 +1,41 @@
+
+ QEMUGuest
+ 9f4b6512-e73a-4a25-93e8-5307802821ce
+ 24682468
+ 24682468
+ 32
+
+
+
+
+
+
+ hvm
+
+
+
+ qemu64
+
+ |
+ |
+ |
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 475a3dbdfc..e919bef986 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -2171,6 +2171,7 @@ mymain(void)
DO_TEST_PARSE_ERROR("numatune-memnode", NONE);
DO_TEST_CAPS_VER("numatune-memnode", "5.2.0");
DO_TEST_CAPS_LATEST("numatune-memnode");
+ DO_TEST_PARSE_ERROR("numatune-memnode-invalid-mode", NONE);
DO_TEST("numatune-memnode-no-memory",
QEMU_CAPS_NUMA,
diff --git a/tests/qemuxml2xmloutdata/numatune-memnode-restrictive-mode.x86_64-latest.xml b/tests/qemuxml2xmloutdata/numatune-memnode-restrictive-mode.x86_64-latest.xml
new file mode 120000
index 0000000000..df405a8a84
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/numatune-memnode-restrictive-mode.x86_64-latest.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/numatune-memnode-restrictive-mode.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index a5343cd6f8..32b68fcfb0 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -1125,6 +1125,7 @@ mymain(void)
DO_TEST("numatune-distances", QEMU_CAPS_NUMA, QEMU_CAPS_NUMA_DIST);
DO_TEST("numatune-no-vcpu", QEMU_CAPS_NUMA);
DO_TEST("numatune-hmat", QEMU_CAPS_NUMA_HMAT, QEMU_CAPS_OBJECT_MEMORY_RAM);
+ DO_TEST_CAPS_LATEST("numatune-memnode-restrictive-mode");
DO_TEST("bios-nvram", NONE);
DO_TEST("bios-nvram-os-interleave", NONE);