Reviewed-by: Paulo Vital <pvital(a)linux.vnet.ibm.com>
On 12/08/2015 02:15 PM, Rodrigo Trujillo wrote:
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(a)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