[Kimchi-devel] [PATCH] Multiple changes in guest maxMemory management

Rodrigo Trujillo rodrigo.trujillo at linux.vnet.ibm.com
Tue Dec 8 16:15:26 UTC 2015


This patch includes 3 changes:
- Set max_memory limit to 1TB
- Set max_memory to 4*Memory
- Set memory "hard_limit" tag to (maxMemory + 1Gib)

All changes are related to issues found with memory in PCI passthrough
or during Live Migration tests.

Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo at linux.vnet.ibm.com>
---
 model/vms.py  | 98 ++++++++++++++++++++++++++++++++++-------------------------
 osinfo.py     | 11 ++++++-
 vmtemplate.py | 13 ++++++++
 3 files changed, 79 insertions(+), 43 deletions(-)

diff --git a/model/vms.py b/model/vms.py
index 4835adb..47dd0ce 100644
--- a/model/vms.py
+++ b/model/vms.py
@@ -57,6 +57,7 @@ from wok.plugins.kimchi.model.utils import get_ascii_nonascii_name, get_vm_name
 from wok.plugins.kimchi.model.utils import get_metadata_node
 from wok.plugins.kimchi.model.utils import remove_metadata_node
 from wok.plugins.kimchi.model.utils import set_metadata_node
+from wok.plugins.kimchi.osinfo import MAX_MEM_LIM
 from wok.plugins.kimchi.screenshot import VMScreenshot
 from wok.plugins.kimchi.utils import template_name_from_uri
 from wok.plugins.kimchi.xmlutils.cpu import get_cpu_xml, get_numa_xml
@@ -881,49 +882,62 @@ class VMModel(object):
         else:
             if memory is not None:
                 root.remove(memory)
+
+            def _get_slots(maxMem):
+                slots = (maxMem - params['memory']) >> 10
+                # Libvirt does not accepts slots <= 1
+                if slots < 0:
+                    raise OperationFailed("KCHVM0041E")
+                elif slots == 0:
+                    slots = 1
+
+                distro, _, _ = platform.linux_distribution()
+                if distro == "IBM_PowerKVM":
+                    # max 32 slots on Power
+                    if slots > 32:
+                        slots = 32
+                return slots
+            # End of _get_slots
+
+            def _get_newMaxMem():
+                # Setting max memory to 4x memory requested, host total memory,
+                # or 1 TB. This should avoid problems with live migration
+                newMaxMem = MAX_MEM_LIM
+                hostMem = self.conn.get().getInfo()[1] << 10
+                if hostMem < newMaxMem:
+                    newMaxMem = hostMem
+                mem = params.get('memory', 0)
+                if (mem != 0) and (((mem * 4) << 10) < newMaxMem):
+                    newMaxMem = (mem * 4) << 10
+
+                distro, _, _ = platform.linux_distribution()
+                if distro == "IBM_PowerKVM":
+                    # max memory 256MiB alignment
+                    newMaxMem -= (newMaxMem % 256)
+                return newMaxMem
+
             maxMem = root.find('.maxMemory')
-            host_mem = self.conn.get().getInfo()[1]
-            slots = (host_mem - params['memory']) >> 10
-            # Libvirt does not accepts slots <= 1
-            if slots < 0:
-                raise OperationFailed("KCHVM0041E")
-            elif slots == 0:
-                slots = 1
-
-            force_max_mem_update = False
-            distro, _, _ = platform.linux_distribution()
-            if distro == "IBM_PowerKVM":
-                # max memory 256MiB alignment
-                host_mem -= (host_mem % PPC_MEM_ALIGN)
-                # force max memory update if it exists but it's wrong.
-                if maxMem is not None and\
-                   int(maxMem.text) != (host_mem << 10):
-                    force_max_mem_update = True
-
-                # max 32 slots on Power
-                if slots > 32:
-                    slots = 32
-
-            if maxMem is None:
-                max_mem_xml = E.maxMemory(
-                    str(host_mem << 10),
-                    unit='Kib',
-                    slots=str(slots))
-                root.insert(0, max_mem_xml)
-                new_xml = ET.tostring(root, encoding="utf-8")
-            else:
-                # Update slots only
-                new_xml = xml_item_update(ET.tostring(root, encoding="utf-8"),
-                                          './maxMemory',
-                                          str(slots),
-                                          attr='slots')
-
-                if force_max_mem_update:
-                    new_xml = xml_item_update(new_xml,
-                                              './maxMemory',
-                                              str(host_mem << 10))
-
-            return new_xml
+            if maxMem is not None:
+                root.remove(maxMem)
+
+            # Setting maxMemory
+            newMaxMem = _get_newMaxMem()
+            slots = _get_slots(newMaxMem >> 10)
+            max_mem_xml = E.maxMemory(
+                str(newMaxMem),
+                unit='Kib',
+                slots=str(slots))
+            root.insert(0, max_mem_xml)
+
+            # Setting memory hard limit to max_memory + 1GiB
+            memtune = root.find('memtune')
+            if memtune is not None:
+                hl = memtune.find('hard_limit')
+                if hl is not None:
+                    memtune.remove(hl)
+                    memtune.insert(0, E.hard_limit(str(newMaxMem + 1048576),
+                                                   unit='Kib'))
+
         return ET.tostring(root, encoding="utf-8")
 
     def _get_host_maxcpu(self):
diff --git a/osinfo.py b/osinfo.py
index 1891398..33757a3 100644
--- a/osinfo.py
+++ b/osinfo.py
@@ -88,6 +88,9 @@ modern_version_bases = {'x86': {'debian': '6.0', 'ubuntu': '7.10',
 icon_available_distros = [icon[5:-4] for icon in glob.glob1('%s/images/'
                           % PluginPaths('kimchi').ui_dir, 'icon-*.png')]
 
+# Max memory 1TB, in KiB
+MAX_MEM_LIM = 1073741824
+
 
 def _get_arch():
     for arch, sub_archs in SUPPORTED_ARCHS.iteritems():
@@ -199,7 +202,9 @@ def lookup(distro, version):
     params['os_version'] = version
     arch = _get_arch()
 
-    # Setting maxMemory of the VM, which will be equal total Host memory in Kib
+    # Setting maxMemory of the VM, which will be lesser value between:
+    # [ 1TB,  (Template Memory * 4),  Host Physical Memory.
+    # Here, we return 1TB or aligned Host Physical Memory
     if hasattr(psutil, 'virtual_memory'):
         params['max_memory'] = psutil.virtual_memory().total >> 10
     else:
@@ -212,6 +217,10 @@ def lookup(distro, version):
             alignment = params['max_memory'] % (PPC_MEM_ALIGN << 10)
             params['max_memory'] -= alignment
 
+    # Setting limit to 1TB
+    if params['max_memory'] > MAX_MEM_LIM:
+        params['max_memory'] = MAX_MEM_LIM
+
     if distro in modern_version_bases[arch]:
         if LooseVersion(version) >= LooseVersion(
                 modern_version_bases[arch][distro]):
diff --git a/vmtemplate.py b/vmtemplate.py
index b90f221..b6e9431 100644
--- a/vmtemplate.py
+++ b/vmtemplate.py
@@ -352,6 +352,13 @@ class VMTemplate(object):
         else:
             params['cdroms'] = cdrom_xml
 
+        # In order to avoid problems with live migration, setting maxMemory of
+        # the VM, which will be lesser value between:
+        # [ 1TB,  (Template Memory * 4),  Host Physical Memory.
+        tmp_max_mem = (params['memory'] << 10) * 4
+        if tmp_max_mem < params['max_memory']:
+            params['max_memory'] = tmp_max_mem
+
         # Setting maximum number of slots to avoid errors when hotplug memory
         # Number of slots are the numbers of chunks of 1GB that fit inside
         # the max_memory of the host minus memory assigned to the VM. It
@@ -367,6 +374,9 @@ class VMTemplate(object):
             if distro == "IBM_PowerKVM":
                 params['slots'] = 32
 
+        # set a hard limit using max_memory + 1GiB
+        params['hard_limit'] = params['max_memory'] + (1024 << 10)
+
         cpu_topo = self.info.get('cpu_info').get('topology')
         if (cpu_topo is not None):
             sockets = int(max_vcpus / (cpu_topo['cores'] *
@@ -390,6 +400,9 @@ class VMTemplate(object):
           %(qemu-stream-cmdline)s
           <name>%(name)s</name>
           <uuid>%(uuid)s</uuid>
+          <memtune>
+            <hard_limit unit='KiB'>%(hard_limit)s</hard_limit>
+          </memtune>
           <maxMemory slots='%(slots)s' unit='KiB'>%(max_memory)s</maxMemory>
           <memory unit='MiB'>%(memory)s</memory>
           %(vcpus)s
-- 
2.1.0




More information about the Kimchi-devel mailing list