From 3a05dc09ec57be5a6f0ea1755ccfb3685efea0fa Mon Sep 17 00:00:00 2001 From: Ryota Ozaki Date: Wed, 7 Oct 2009 15:26:23 +0200 Subject: [PATCH] LXC implement memory control APIs 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. * 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 952ed2968c..37c729c725 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 5fb4105a0b..8ec4ae4964 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 2e646fdf61..e56d293188 100644 --- a/src/util/cgroup.c +++ b/src/util/cgroup.c @@ -701,6 +701,26 @@ int virCgroupSetMemory(virCgroupPtr group, unsigned long kb) kb << 10); } +/** + * 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: * diff --git a/src/util/cgroup.h b/src/util/cgroup.h index aba56c69cd..aa36632c16 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); -- GitLab