QEMU introduced command line "-mem-merge=on|off" (defaults to on) to
enable/disable the memory merge (KSM) at guest startup. This exposes
it by new XML:
<memoryBacking>
<nosharepages/>
</memoryBacking>
The XML tag is same with what we used internally for old RHEL.
---
docs/formatdomain.html.in | 13 +++++++---
docs/schemas/domaincommon.rng | 5 ++++
src/conf/domain_conf.c | 20 ++++++++++-----
src/conf/domain_conf.h | 1 +
src/qemu/qemu_capabilities.c | 4 +++
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 11 ++++++++
.../qemuxml2argv-nosharepages.args | 4 +++
.../qemuxml2argvdata/qemuxml2argv-nosharepages.xml | 29 ++++++++++++++++++++++
tests/qemuxml2argvtest.c | 1 +
tests/qemuxml2xmltest.c | 1 +
11 files changed, 80 insertions(+), 10 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-nosharepages.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-nosharepages.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 0cc56d9..4350610 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -558,6 +558,7 @@
...
<memoryBacking>
<hugepages/>
+ <nosharepages/>
</memoryBacking>
...
</domain>
@@ -565,10 +566,14 @@
<dl>
<dt><code>memoryBacking</code></dt>
- <dd>The optional <code>memoryBacking</code> element, may have an
- <code>hugepages</code> element set within it. This tells the
- hypervisor that the guest should have its memory allocated using
- hugepages instead of the normal native page size.</dd>
+ <dd>The optional <code>memoryBacking</code> element has two
+ optional elements. The element <code>hugepages</code> tells
+ the hypervisor that the guest should have its memory allocated
+ using hugepages instead of the normal native page size. And the
+ optional element <code>nosharepages</code> tells the hypervisor
+ that share pages (memory merge, KSM) should be disabled on guest
+ startup.
+ </dd>
</dl>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 468c49c..a1e25ca 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -495,6 +495,11 @@
<empty/>
</element>
</optional>
+ <optional>
+ <element name="nosharepages">
+ <empty/>
+ </element>
+ </optional>
</element>
</optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 548368e..231cc41 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -10018,6 +10018,9 @@ virDomainDefParseXML(xmlDocPtr xml,
if ((node = virXPathNode("./memoryBacking/hugepages", ctxt)))
def->mem.hugepage_backed = true;
+ if ((node = virXPathNode("./memoryBacking/nosharepages", ctxt)))
+ def->mem.nosharepages = true;
+
/* Extract blkio cgroup tunables */
if (virXPathUInt("string(./blkiotune/weight)", ctxt,
&def->blkio.weight) < 0)
@@ -15263,12 +15266,17 @@ virDomainDefFormatInternal(virDomainDefPtr def,
def->mem.swap_hard_limit)
virBufferAddLit(buf, " </memtune>\n");
- if (def->mem.hugepage_backed) {
- virBufferStrcat(buf,
- " <memoryBacking>\n",
- " <hugepages/>\n",
- " </memoryBacking>\n", NULL);
- }
+ if (def->mem.hugepage_backed || def->mem.nosharepages)
+ virBufferAddLit(buf, " <memoryBacking>\n");
+
+ if (def->mem.hugepage_backed)
+ virBufferAddLit(buf, " <hugepages/>\n");
+
+ if (def->mem.nosharepages)
+ virBufferAddLit(buf, " <nosharepages/>\n");
+
+ if (def->mem.hugepage_backed || def->mem.nosharepages)
+ virBufferAddLit(buf, " </memoryBacking>\n");
virBufferAddLit(buf, " <vcpu");
virBufferAsprintf(buf, " placement='%s'",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index f1f01fa..0ba72d5 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1811,6 +1811,7 @@ struct _virDomainDef {
unsigned long long max_balloon; /* in kibibytes */
unsigned long long cur_balloon; /* in kibibytes */
bool hugepage_backed;
+ bool nosharepages;
int dump_core; /* enum virDomainMemDump */
unsigned long long hard_limit; /* in kibibytes */
unsigned long long soft_limit; /* in kibibytes */
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index d10c8aa..e5d89f9 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -220,6 +220,7 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
"machine-usb-opt",
"tpm-passthrough",
"tpm-tis",
+ "mem-merge",
);
struct _virQEMUCaps {
@@ -1082,6 +1083,9 @@ virQEMUCapsComputeCmdFlags(const char *help,
if (strstr(help, "-machine"))
virQEMUCapsSet(qemuCaps, QEMU_CAPS_MACHINE_OPT);
+ if (strstr(help, "-mem-merge"))
+ virQEMUCapsSet(qemuCaps, QEMU_CAPS_MEM_MERGE);
+
/* USB option is supported v1.3.0 onwards */
if (qemuCaps->version >= 1003000)
virQEMUCapsSet(qemuCaps, QEMU_CAPS_MACHINE_USB_OPT);
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 4e76799..55ffd35 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -178,6 +178,7 @@ enum virQEMUCapsFlags {
QEMU_CAPS_MACHINE_USB_OPT = 137, /* -machine xxx,usb=on/off */
QEMU_CAPS_DEVICE_TPM_PASSTHROUGH = 138, /* -tpmdev passthrough */
QEMU_CAPS_DEVICE_TPM_TIS = 139, /* -device tpm_tis */
+ QEMU_CAPS_MEM_MERGE = 140, /* Is -mem-merge available? */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 009d42d..bb0ccff 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -5993,6 +5993,17 @@ qemuBuildCommandLine(virConnectPtr conn,
virCommandAddArg(cmd, smp);
VIR_FREE(smp);
+ if (def->mem.nosharepages) {
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_MEM_MERGE)) {
+ virCommandAddArg(cmd, "-mem-merge=off");
+ } else {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("the QEMU binary %s does not support to "
+ "disable shared memory"), emulator);
+ goto error;
+ }
+ }
+
if (def->cpu && def->cpu->ncells)
if (qemuBuildNumaArgStr(def, cmd) < 0)
goto error;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-nosharepages.args
b/tests/qemuxml2argvdata/qemuxml2argv-nosharepages.args
new file mode 100644
index 0000000..f9ef1c1
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-nosharepages.args
@@ -0,0 +1,4 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu \
+-S -M pc -m 215 -smp 1 -mem-merge=off -nographic \
+-monitor unix:/tmp/test-monitor,server,nowait -no-acpi \
+-boot c -usb -hda /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-nosharepages.xml
b/tests/qemuxml2argvdata/qemuxml2argv-nosharepages.xml
new file mode 100644
index 0000000..57701a0
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-nosharepages.xml
@@ -0,0 +1,29 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219200</memory>
+ <currentMemory unit='KiB'>219200</currentMemory>
+ <memoryBacking>
+ <nosharepages/>
+ </memoryBacking>
+ <vcpu placement='static'>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <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'/>
+ <controller type='usb' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 4bf13f0..48aa07e 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -433,6 +433,7 @@ mymain(void)
DO_TEST("hyperv", NONE);
DO_TEST("hugepages", QEMU_CAPS_MEM_PATH);
+ DO_TEST("nosharepages", QEMU_CAPS_MEM_MERGE);
DO_TEST("disk-cdrom", NONE);
DO_TEST("disk-cdrom-empty", QEMU_CAPS_DRIVE);
DO_TEST("disk-cdrom-tray",
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 7434190..c16f866 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -157,6 +157,7 @@ mymain(void)
DO_TEST("hyperv");
DO_TEST("hugepages");
+ DO_TEST("nosharepages");
DO_TEST("disk-aio");
DO_TEST("disk-cdrom");
DO_TEST("disk-floppy");
--
1.8.1.4