[PATCH v3 1/1] qemu: add support for max-ram-below-4g option

Zhiyong Ye yezhiyong at bytedance.com
Mon May 10 07:30:13 UTC 2021


The 'below4g' attribute added in 'memory' element can be used to specify
the low memory area, which allows to get a larger PCI I/O window below
4G when reduce it to a smaller value, and when raise value allows legacy
non-PAE guests to have as much memory as possible in the 32bit address
space below 4G. It does not share the 'unit' parameter with the actual
memory size and its unit defaults to "KiB".

Signed-off-by: Zhiyong Ye <yezhiyong at bytedance.com>
Signed-off-by: zhenwei pi <pizhenwei at bytedance.com>
Signed-off-by: zhangruien <zhangruien at bytedance.com>
---
 docs/formatdomain.rst                       | 10 ++++++--
 docs/schemas/domaincommon.rng               |  5 ++++
 src/conf/domain_conf.c                      | 15 ++++++++++++
 src/conf/domain_conf.h                      |  3 +++
 src/conf/domain_validate.c                  | 13 ++++++++++
 src/qemu/qemu_command.c                     |  4 ++++
 tests/qemuxml2argvdata/memory-below4g.args  | 29 ++++++++++++++++++++++
 tests/qemuxml2argvdata/memory-below4g.xml   | 26 ++++++++++++++++++++
 tests/qemuxml2argvtest.c                    |  1 +
 tests/qemuxml2xmloutdata/memory-below4g.xml | 37 +++++++++++++++++++++++++++++
 tests/qemuxml2xmltest.c                     |  1 +
 11 files changed, 142 insertions(+), 2 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/memory-below4g.args
 create mode 100644 tests/qemuxml2argvdata/memory-below4g.xml
 create mode 100644 tests/qemuxml2xmloutdata/memory-below4g.xml

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index fa5c14febc..a71a716f5b 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -940,8 +940,14 @@ Memory Allocation
    `NUMA <#elementsCPU>`__ is configured for the guest the ``memory`` element
    can be omitted. In the case of crash, optional attribute ``dumpCore`` can be
    used to control whether the guest memory should be included in the generated
-   coredump or not (values "on", "off"). ``unit`` :since:`since 0.9.11` ,
-   ``dumpCore`` :since:`since 0.10.2 (QEMU only)`
+   coredump or not (values "on", "off"). Besides, the optional ``below4g``
+   attribute can be used to specify the low memory area, which allows to get a
+   larger PCI I/O window below 4G when reduce it to a smaller value, and when
+   raise value allows legacy non-PAE guests to have as much memory as possible
+   in the 32bit address space below 4G. It does not share the ``unit`` parameter
+   with the actual memory size and its unit defaults to "KiB". ``unit`` :
+   since:`since 0.9.11` , ``dumpCore`` : since:`since 0.10.2 (QEMU only)`,
+   ``below4g`` :since:`since 7.3.0 (QEMU only)`.
 ``maxMemory``
    The run time maximum memory allocation of the guest. The initial memory
    specified by either the ``<memory>`` element or the NUMA cell size
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index a2e5c50c1d..8f2ac1ad33 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -643,6 +643,11 @@
               <ref name="virOnOff"/>
             </attribute>
           </optional>
+          <optional>
+            <attribute name="below4g">
+              <ref name="unsignedLong"/>
+            </attribute>
+          </optional>
         </element>
       </optional>
       <optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index e8632e4d73..c586d633d1 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -18922,6 +18922,10 @@ virDomainDefParseMemory(virDomainDef *def,
                              &def->mem.max_memory, false, false) < 0)
         goto error;
 
+    if (virDomainParseMemory("./memory[1]/@below4g", NULL, ctxt,
+                             &def->mem.max_ram_below_4g, false, true) < 0)
+        goto error;
+
     if (virXPathUInt("string(./maxMemory[1]/@slots)", ctxt, &def->mem.memory_slots) == -2) {
         virReportError(VIR_ERR_XML_ERROR, "%s",
                        _("Failed to parse memory slot count"));
@@ -21928,6 +21932,15 @@ virDomainMemtuneCheckABIStability(const virDomainDef *src,
         return false;
     }
 
+    if (src->mem.max_ram_below_4g != dst->mem.max_ram_below_4g) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Target domain maximum memory below the 4GiB boundary "
+                         "'%llu' doesn't match source '%llu'"),
+                       dst->mem.max_ram_below_4g,
+                       src->mem.max_ram_below_4g);
+        return false;
+    }
+
     return true;
 }
 
@@ -27980,6 +27993,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def,
     if (def->mem.dump_core)
         virBufferAsprintf(buf, " dumpCore='%s'",
                           virTristateSwitchTypeToString(def->mem.dump_core));
+    if (def->mem.max_ram_below_4g > 0)
+        virBufferAsprintf(buf, " below4g='%llu'", def->mem.max_ram_below_4g);
     virBufferAsprintf(buf, " unit='KiB'>%llu</memory>\n",
                       virDomainDefGetMemoryTotal(def));
 
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 2d5462bb55..12de9ec235 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2598,6 +2598,9 @@ struct _virDomainMemtune {
     unsigned long long max_memory; /* in kibibytes */
     unsigned int memory_slots; /* maximum count of RAM memory slots */
 
+    /* maximum memory below the 4GiB boundary (32bit boundary) */
+    unsigned long long max_ram_below_4g; /* in kibibytes */
+
     bool nosharepages;
     bool locked;
     int dump_core; /* enum virTristateSwitch */
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index 686b9e8d16..afa9e2e821 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -1384,6 +1384,19 @@ virDomainDefMemtuneValidate(const virDomainDef *def)
         }
     }
 
+    if (mem->max_ram_below_4g &&
+        mem->max_ram_below_4g < 1024) {
+        virReportError(VIR_ERR_XML_DETAIL, "%s",
+                       _("maximum memory size below the 4GiB boundary must be "
+                         "greater than or equal to 1MiB"));
+        return -1;
+    } else if (mem->max_ram_below_4g > 4 * 1024 * 1024) {
+        virReportError(VIR_ERR_XML_DETAIL, "%s",
+                       _("maximum memory size below the 4GiB boundary must be "
+                         "less than or equal to 4GiB"));
+        return -1;
+    }
+
     return 0;
 }
 
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index d6c5308ef0..3ab4ceefd5 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -6849,6 +6849,10 @@ qemuBuildMachineCommandLine(virCommand *cmd,
                           cfg->dumpGuestCore ? "on" : "off");
     }
 
+    if (def->mem.max_ram_below_4g > 0)
+        virBufferAsprintf(&buf, ",max-ram-below-4g=%llu",
+                          def->mem.max_ram_below_4g * 1024);
+
     if (def->mem.nosharepages)
         virBufferAddLit(&buf, ",mem-merge=off");
 
diff --git a/tests/qemuxml2argvdata/memory-below4g.args b/tests/qemuxml2argvdata/memory-below4g.args
new file mode 100644
index 0000000000..141e001802
--- /dev/null
+++ b/tests/qemuxml2argvdata/memory-below4g.args
@@ -0,0 +1,29 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/tmp/lib/domain--1-QEMUGuest1 \
+USER=test \
+LOGNAME=test \
+XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
+XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
+XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu-system-i386 \
+-name QEMUGuest1 \
+-S \
+-machine pc,accel=tcg,usb=off,dump-guest-core=off,max-ram-below-4g=112197632 \
+-m 214 \
+-realtime mlock=off \
+-smp 1,sockets=1,cores=1,threads=1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-display none \
+-no-user-config \
+-nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,server=on,wait=off \
+-mon chardev=charmonitor,id=monitor,mode=control \
+-rtc base=utc \
+-no-shutdown \
+-no-acpi \
+-usb \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \
+-device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2
diff --git a/tests/qemuxml2argvdata/memory-below4g.xml b/tests/qemuxml2argvdata/memory-below4g.xml
new file mode 100644
index 0000000000..a843ef72a2
--- /dev/null
+++ b/tests/qemuxml2argvdata/memory-below4g.xml
@@ -0,0 +1,26 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory below4g='109568' unit='MiB'>214</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <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-system-i386</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='usb' index='0'/>
+    <controller type='ide' index='0'/>
+    <memballoon model='virtio'/>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index a9dafe226e..131ebde9e4 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1055,6 +1055,7 @@ mymain(void)
     driver.config->dumpGuestCore = true;
     DO_TEST("machine-core-off", NONE);
     driver.config->dumpGuestCore = false;
+    DO_TEST("memory-below4g", NONE);
     DO_TEST("machine-smm-opt",
             QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE,
             QEMU_CAPS_DEVICE_PCI_BRIDGE,
diff --git a/tests/qemuxml2xmloutdata/memory-below4g.xml b/tests/qemuxml2xmloutdata/memory-below4g.xml
new file mode 100644
index 0000000000..716071f3d3
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/memory-below4g.xml
@@ -0,0 +1,37 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory below4g='109568' unit='KiB'>219136</memory>
+  <currentMemory unit='KiB'>219136</currentMemory>
+  <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-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='usb' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='ide' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </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='0x02' function='0x0'/>
+    </memballoon>
+  </devices>
+</domain>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 7af6f90aee..7a139489c3 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -220,6 +220,7 @@ mymain(void)
     DO_TEST_CAPS_LATEST("genid-auto");
     DO_TEST("machine-core-on", NONE);
     DO_TEST("machine-core-off", NONE);
+    DO_TEST("memory-below4g", NONE);
     DO_TEST("machine-loadparm-multiple-disks-nets-s390", NONE);
     DO_TEST("default-kvm-host-arch", NONE);
     DO_TEST("default-qemu-host-arch", NONE);
-- 
2.11.0




More information about the libvir-list mailing list