Hi,
The patch implements the missing memory control APIs for lxc, i.e.,
domainGetMaxMemory, domainSetMaxMemory, domainSetMemory, and improves
domainGetInfo to return proper amount of used memory via cgroup.
And also it includes trivial two fixes; add missing virCgroupSetMemory in
libvirt_private.syms and fix invalid lxcError argument in lxcDomainGetInfo.
Thanks,
ozaki-r
From 530e56db9367fcb325aeaa7fb0d52a008db2f19f Mon Sep 17 00:00:00 2001
From: Ryota Ozaki <ozaki.ryota(a)gmail.com>
Date: Mon, 5 Oct 2009 02:07:04 +0900
Subject: [PATCH] lxc: implement missing APIs to control the amount of memory
* src/libvirt_private.syms: Export virCgroupGetMemoryUsage
and add missing virCgroupSetMemory
* src/lxc/lxc_driver.c: Implement missing memory functions
* src/util/cgroup.c, src/util/cgroup.h: Add the function
to get used memory
---
src/libvirt_private.syms | 2 +
src/lxc/lxc_driver.c | 122 ++++++++++++++++++++++++++++++++++++++++++++--
src/util/cgroup.c | 20 ++++++++
src/util/cgroup.h | 1 +
4 files changed, 140 insertions(+), 5 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 49bbf96..3be3724 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -53,6 +53,8 @@ virCgroupForDriver;
virCgroupRemove;
virCgroupFree;
virCgroupAddTask;
+virCgroupSetMemory;
+virCgroupGetMemoryUsage;
virCgroupSetCpuShares;
virCgroupGetCpuShares;
virCgroupDenyDevicePath;
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 5fb4105..8ec4ae4 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -450,6 +450,7 @@ static int lxcDomainGetInfo(virDomainPtr dom,
if (!virDomainIsActive(vm) || driver->cgroup == NULL) {
info->cpuTime = 0;
+ info->memory = vm->def->memory;
} else {
if (virCgroupForDomain(driver->cgroup, vm->def->name,
&cgroup, 0) != 0) {
lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
@@ -458,13 +459,18 @@ static int lxcDomainGetInfo(virDomainPtr dom,
}
if (virCgroupGetCpuacctUsage(cgroup, &(info->cpuTime)) < 0) {
- lxcError(dom->conn, dom, VIR_ERR_OPERATION_FAILED,
("cannot read cputime for domain"));
+ lxcError(dom->conn, dom, VIR_ERR_OPERATION_FAILED,
+ "%s", _("cannot read cputime for domain"));
+ goto cleanup;
+ }
+ if (virCgroupGetMemoryUsage(cgroup, &(info->memory)) < 0) {
+ lxcError(dom->conn, dom, VIR_ERR_OPERATION_FAILED,
+ "%s", _("cannot read memory usage for
domain"));
goto cleanup;
}
}
info->maxMem = vm->def->maxmem;
- info->memory = vm->def->memory;
info->nrVirtCpu = 1;
ret = 0;
@@ -501,6 +507,112 @@ cleanup:
return ret;
}
+/* Returns max memory in kb, 0 if error */
+static unsigned long lxcDomainGetMaxMemory(virDomainPtr dom) {
+ lxc_driver_t *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ unsigned long ret = 0;
+
+ lxcDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ lxcDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ lxcError(dom->conn, dom, VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ ret = vm->def->maxmem;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
+ lxc_driver_t *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ int ret = -1;
+
+ lxcDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ lxcDriverUnlock(driver);
+
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ lxcError(dom->conn, dom, VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ if (newmax < vm->def->memory) {
+ lxcError(dom->conn, dom, VIR_ERR_INVALID_ARG,
+ "%s", _("cannot set max memory lower than
current memory"));
+ goto cleanup;
+ }
+
+ vm->def->maxmem = newmax;
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ return ret;
+}
+
+static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
+ lxc_driver_t *driver = dom->conn->privateData;
+ virDomainObjPtr vm;
+ virCgroupPtr cgroup = NULL;
+ int ret = -1;
+
+ lxcDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+ lxcDriverUnlock(driver);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(dom->uuid, uuidstr);
+ lxcError(dom->conn, dom, VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"), uuidstr);
+ goto cleanup;
+ }
+
+ if (newmem > vm->def->maxmem) {
+ lxcError(dom->conn, dom, VIR_ERR_INVALID_ARG,
+ "%s", _("cannot set memory higher than max
memory"));
+ goto cleanup;
+ }
+
+ if (virDomainIsActive(vm)) {
+ if (virCgroupForDomain(driver->cgroup, vm->def->name,
&cgroup, 0) != 0) {
+ lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+ _("Unable to get cgroup for %s¥n"), vm->def->name);
+ goto cleanup;
+ }
+
+ if (virCgroupSetMemory(cgroup, newmem) < 0) {
+ lxcError(dom->conn, dom, VIR_ERR_OPERATION_FAILED,
+ "%s", _("cannot set memory for domain"));
+ goto cleanup;
+ }
+ } else {
+ vm->def->memory = newmem;
+ }
+ ret = 0;
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ if (cgroup)
+ virCgroupFree(&cgroup);
+ return ret;
+}
+
static char *lxcDomainDumpXML(virDomainPtr dom,
int flags)
{
@@ -2103,9 +2215,9 @@ static virDriver lxcDriver = {
NULL, /* domainReboot */
lxcDomainDestroy, /* domainDestroy */
lxcGetOSType, /* domainGetOSType */
- NULL, /* domainGetMaxMemory */
- NULL, /* domainSetMaxMemory */
- NULL, /* domainSetMemory */
+ lxcDomainGetMaxMemory, /* domainGetMaxMemory */
+ lxcDomainSetMaxMemory, /* domainSetMaxMemory */
+ lxcDomainSetMemory, /* domainSetMemory */
lxcDomainGetInfo, /* domainGetInfo */
NULL, /* domainSave */
NULL, /* domainRestore */
diff --git a/src/util/cgroup.c b/src/util/cgroup.c
index 2e646fd..e56d293 100644
--- a/src/util/cgroup.c
+++ b/src/util/cgroup.c
@@ -702,6 +702,26 @@ int virCgroupSetMemory(virCgroupPtr group,
unsigned long kb)
}
/**
+ * virCgroupGetMemoryUsage:
+ *
+ * @group: The cgroup to change memory for
+ * @kb: Pointer to returned used memory in kilobytes
+ *
+ * Returns: 0 on success
+ */
+int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb)
+{
+ uint64_t usage_in_bytes;
+ int ret;
+ ret = virCgroupGetValueU64(group,
+ VIR_CGROUP_CONTROLLER_MEMORY,
+ "memory.usage_in_bytes", &usage_in_bytes);
+ if (ret == 0)
+ *kb = (unsigned long) usage_in_bytes >> 10;
+ return ret;
+}
+
+/**
* virCgroupDenyAllDevices:
*
* @group: The cgroup to deny devices for
diff --git a/src/util/cgroup.h b/src/util/cgroup.h
index aba56c6..aa36632 100644
--- a/src/util/cgroup.h
+++ b/src/util/cgroup.h
@@ -41,6 +41,7 @@ int virCgroupForDomain(virCgroupPtr driver,
int virCgroupAddTask(virCgroupPtr group, pid_t pid);
int virCgroupSetMemory(virCgroupPtr group, unsigned long kb);
+int virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb);
int virCgroupDenyAllDevices(virCgroupPtr group);
--
1.6.5.rc2