This patch implements BalloonInstanceMemory function of the
LXCHypervisor.
Memory ballooning for the LXC container can be done by using
memory.limit_in_bytes and memory.memsw.limit_in_bytes cgroup parameter.
The Linux kernel does not kill processes inside the cgroup which is
tried to shrink its memory accounted, so the update for
memory.memsw.limit_in_bytes can be fail even if the update for
memory.limit_in_bytes was succeed, so this function must care about
all cgroup memory limit parameters consistency for update.

Signed-off-by: Yuto KAWAMURA(kawamuray) <[email protected]>
---
 lib/hypervisor/hv_lxc.py | 32 ++++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/lib/hypervisor/hv_lxc.py b/lib/hypervisor/hv_lxc.py
index e94862f..8594628 100644
--- a/lib/hypervisor/hv_lxc.py
+++ b/lib/hypervisor/hv_lxc.py
@@ -23,6 +23,7 @@
 
 """
 
+import errno
 import os
 import os.path
 import logging
@@ -749,8 +750,35 @@ class LXCHypervisor(hv_base.BaseHypervisor):
     @param mem: actual memory size to use for instance runtime
 
     """
-    # Currently lxc instances don't have memory limits
-    pass
+    mem_in_bytes = mem * 1024 ** 2
+    current_mem_usage = self._GetCgroupMemoryLimit(instance.name)
+    is_shrink = mem_in_bytes <= current_mem_usage
+
+    # memory.memsw.limit_in_bytes is the superlimit of the 
memory.limit_in_bytes
+    # so the order of setting these parameters is quite important.
+    cgparams = ["memory.memsw.limit_in_bytes", "memory.limit_in_bytes"]
+    if is_shrink:
+      cgparams.reverse()
+
+    for i, cgparam in enumerate(cgparams):
+      try:
+        self._SetCgroupInstanceValue(instance.name, cgparam, str(mem_in_bytes))
+      except EnvironmentError, err:
+        if is_shrink and err.errno == errno.EBUSY:
+          logging.warn("Unable to reclaim memory or swap usage from instance"
+                       " %s", instance.name)
+        # Restore changed parameters for an atomicity
+        for restore_param in cgparams[0:i]:
+          try:
+            self._SetCgroupInstanceValue(instance.name, restore_param,
+                                         str(current_mem_usage))
+          except EnvironmentError, restore_err:
+            logging.warn("Can't restore the cgroup parameter %s of %s: %s",
+                         restore_param, instance.name, restore_err)
+
+        raise HypervisorError("Failed to balloon the memory of %s, can't set"
+                              " cgroup parameter %s: %s" %
+                              (instance.name, cgparam, err))
 
   def GetNodeInfo(self, hvparams=None):
     """Return information about the node.
-- 
2.0.4

Reply via email to