diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 952ed2968c5fea72357aa3b64513e3956fdfb3cb..37c729c72508f66d58cd59aa4c562dbd717c8a78 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 5fb4105a0bd24b3ec7c60da4c91bca6e426488cf..8ec4ae4964cc64ca10325724f708e5e69bedc44b 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 2e646fdf615967ceaffa3f1169719c14feab1daa..e56d293188ba423d41d0b4519eb4285d53d8ebfc 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 aba56c69cd0ae4b0de803df032268c49c90fa0cf..aa36632c166ba8e48d42b902baa8bdd12b83a8d5 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);