[Kimchi-devel] [PATCH][Kimchi 1/2] Implements support to memory hotplug in non-NUMA guests

Rodrigo Trujillo rodrigo.trujillo at linux.vnet.ibm.com
Thu May 12 15:42:26 UTC 2016


This patch makes necessary changes in Kimchi guest update to support
memory hotplug operations in non-numa guests, due to latest Libvirt
changes.
---
 model/utils.py | 18 ++++++++++++++++++
 model/vms.py   | 53 +++++++++++++++++------------------------------------
 2 files changed, 35 insertions(+), 36 deletions(-)

diff --git a/model/utils.py b/model/utils.py
index b7ea82e..da62971 100644
--- a/model/utils.py
+++ b/model/utils.py
@@ -129,3 +129,21 @@ def metadata_exists(dom):
     if root.find("metadata") is None:
         return False
     return True
+
+
+def has_cpu_numa(dom):
+    """
+    Verify if domain has NUMA configuration
+    Returns: True or False
+    """
+    root = etree.fromstring(dom.XMLDesc(0))
+    return (root.find('./cpu/numa') is not None)
+
+
+def set_numa_memory(mem, root):
+    """
+    Set new NUMA memory value
+    Returns: etree element updated
+    """
+    root.find('./cpu/numa/cell').set('memory', str(mem))
+    return root
diff --git a/model/vms.py b/model/vms.py
index cf40ad1..f88cfdb 100644
--- a/model/vms.py
+++ b/model/vms.py
@@ -61,9 +61,9 @@ from wok.plugins.kimchi.model.utils import set_metadata_node
 from wok.plugins.kimchi.screenshot import VMScreenshot
 from wok.plugins.kimchi.utils import get_next_clone_name
 from wok.plugins.kimchi.utils import template_name_from_uri
-from wok.plugins.kimchi.xmlutils.cpu import get_cpu_xml, get_numa_xml
 from wok.plugins.kimchi.xmlutils.cpu import get_topology_xml
 from wok.plugins.kimchi.xmlutils.disk import get_vm_disk_info, get_vm_disks
+from utils import has_cpu_numa, set_numa_memory
 
 
 DOM_STATE_MAP = {0: 'nostate',
@@ -769,10 +769,10 @@ class VMModel(object):
             # topology is being undefined: remove it
             new_xml = xml_item_remove(new_xml, XPATH_TOPOLOGY)
 
-        # Updating memory and NUMA if necessary, if vm is offline
+        # Updating memory if vm is offline
         if (not dom.isActive() and 'memory' in params and
            params['memory'] != {}):
-            new_xml = self._update_memory_config(new_xml, params)
+            new_xml = self._update_memory_config(new_xml, params, dom)
 
         if 'graphics' in params:
             new_xml = self._update_graphics(dom, new_xml, params)
@@ -810,7 +810,7 @@ class VMModel(object):
             vm_name = name
         return (nonascii_name if nonascii_name is not None else vm_name, dom)
 
-    def _update_memory_config(self, xml, params):
+    def _update_memory_config(self, xml, params, dom):
         # Cannot pass max memory if there is not support to memory hotplug
         # Then set max memory as memory, just to continue with the update
         if not self.caps.mem_hotplug_support:
@@ -905,16 +905,18 @@ class VMModel(object):
                 root.remove(currentMem)
 
             memory = root.find('.memory')
-            # If host/guest does not support memory hot plug, then there is
-            # NUMA configure, we must update the tag directly
-            if not self.caps.mem_hotplug_support:
-                if memory is not None:
-                    memory.text = str(newMem)
-            else:
+            # Set NUMA parameterers if necessary. NUMA is not required for CPU
+            # and Memory hotplug anymore
+            if has_cpu_numa(dom):
                 if memory is not None:
                     # Libvirt is going to set the value automatically with
                     # the value configured in NUMA tag
                     root.remove(memory)
+                root = set_numa_memory(newMem, root)
+            else:
+                # update the memory tag directly
+                if memory is not None:
+                    memory.text = str(newMem)
 
             if (maxMemTag is not None) and (not hasMaxMem):
                 if newMem == newMaxMem:
@@ -922,22 +924,6 @@ class VMModel(object):
                 else:
                     maxMemTag.set('slots', str(_get_slots(newMem, newMaxMem)))
 
-        # Set NUMA parameterers and create it if does not exist
-        # CPU tag DO NOT exist? Create it
-        cpu = root.find(XPATH_CPU)
-        if cpu is None:
-            cpu = get_cpu_xml(0, newMem)
-            root.insert(0, ET.fromstring(cpu))
-        else:
-            # Does NUMA tag exist ?
-            numaTag = cpu.find('./numa')
-            if numaTag is None:
-                numa_element = get_numa_xml(0, newMem)
-                cpu.insert(0, ET.fromstring(numa_element))
-            else:
-                cellTag = cpu.find('./numa/cell')
-                cellTag.set('memory', str(newMem))
-
         # Setting memory hard limit to max_memory + 1GiB
         memtune = root.find('memtune')
         if memtune is not None:
@@ -990,12 +976,9 @@ class VMModel(object):
         if not self.caps.mem_hotplug_support:
             raise InvalidOperation("KCHVM0046E")
 
-        # Check if the vm xml supports memory hotplug, if not, static update
-        # must be done firstly, then Kimchi is going to update the xml
         xml = dom.XMLDesc(0)
-        numa_mem = xpath_get_text(xml, XPATH_NUMA_CELL + '/@memory')
         max_mem = xpath_get_text(xml, './maxMemory')
-        if numa_mem == [] or max_mem == []:
+        if max_mem == []:
             raise OperationFailed('KCHVM0042E', {'name': dom.name()})
 
         # Memory live update must be done in chunks of 1024 Mib or 1Gib
@@ -1038,12 +1021,10 @@ class VMModel(object):
         # Hot add given number of memory devices in the guest
         flags = libvirt.VIR_DOMAIN_MEM_CONFIG | libvirt.VIR_DOMAIN_MEM_LIVE
         # Create memory device xml
-        mem_dev_xml = etree.tostring(
-            E.memory(
-                E.target(
-                    E.size('1', unit='GiB'),
-                    E.node('0')),
-                model='dimm'))
+        tmp_xml = E.memory(E.target(E.size('1', unit='GiB')), model='dimm')
+        if has_cpu_numa(dom):
+            tmp_xml.find('target').append(E.node('0'))
+        mem_dev_xml = etree.tostring(tmp_xml)
         # Add chunks of 1G of memory
         for i in range(amount):
             dom.attachDeviceFlags(mem_dev_xml, flags)
-- 
2.1.0




More information about the Kimchi-devel mailing list