--- OpenVZ's memory paramters [1,2] aren't very well supported at the moment. Let's make a start with privvmpages/vmguarpages using already available memtune parameters. I hope the mapping looks correct. Cheers, -- Guido [1] http://wiki.openvz.org/UBC_primary_parameters [2] http://wiki.openvz.org/UBC_secondary_parameters src/openvz/openvz_conf.c | 103 +++++++++++++++++++++++ src/openvz/openvz_driver.c | 200 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 303 insertions(+) diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 5848ec4..579fcfc 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -423,6 +423,108 @@ error: } +/* Parse config values of the form barrier:limit into barrier and limit */ +static int +openvzParseBarrierAndLimit(const char* value, + unsigned long *barrier, + unsigned long *limit) +{ + char *token; + char *saveptr = NULL; + char *str = strdup(value); + + if (str == NULL) { + virReportOOMError(); + goto error; + } + + token = strtok_r(str, ":", &saveptr); + if (token == NULL) { + goto error; + } else { + if (barrier != NULL) { + if (virStrToLong_ul(token, NULL, 10, barrier)) + goto error; + } + } + token = strtok_r(NULL, ":", &saveptr); + if (token == NULL) { + goto error; + } else { + if (limit != NULL) { + if (virStrToLong_ul(token, NULL, 10, limit)) + goto error; + } + } + return 0; +error: + VIR_FREE(str); + return -1; +} + + +static int +openvzReadMemConf(virDomainDefPtr def, int veid) +{ + int ret; + char *temp = NULL; + unsigned long barrier, limit; + const char *param; + unsigned long kb_per_pages; + + kb_per_pages = sysconf(_SC_PAGESIZE) / 1024; + if (kb_per_pages == -1) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Can't determine page size")); + goto error; + } + + /* Memory allocation guarantee */ + param = "VMGUARPAGES"; + ret = openvzReadVPSConfigParam(veid, param, &temp); + if (ret < 0) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Could not read '%s' from config for container %d"), + param, veid); + goto error; + } else if (ret > 0) { + ret = openvzParseBarrierAndLimit(temp, &barrier, NULL); + if (ret < 0) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse barrier of '%s' " + "from config for container %d"), param, veid); + goto error; + } + def->mem.min_guarantee = barrier * kb_per_pages; + } + + /* Memory hard and soft limits */ + param = "PRIVVMPAGES"; + ret = openvzReadVPSConfigParam(veid, param, &temp); + if (ret < 0) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Could not read '%s' from config for container %d"), + param, veid); + goto error; + } else if (ret > 0) { + ret = openvzParseBarrierAndLimit(temp, &barrier, &limit); + if (ret < 0) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Could not parse barrier and limit of '%s' " + "from config for container %d"), param, veid); + goto error; + } + def->mem.soft_limit = barrier * kb_per_pages; + def->mem.hard_limit = limit * kb_per_pages; + } + + ret = 0; +error: + VIR_FREE(temp); + return ret; +} + + /* Free all memory associated with a openvz_driver structure */ void openvzFreeDriver(struct openvz_driver *driver) @@ -535,6 +637,7 @@ int openvzLoadDomains(struct openvz_driver *driver) { openvzReadNetworkConf(dom->def, veid); openvzReadFSConf(dom->def, veid); + openvzReadMemConf(dom->def, veid); virUUIDFormat(dom->def->uuid, uuidstr); if (virHashAddEntry(driver->domains.objs, uuidstr, dom) < 0) diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index e8b6915..6f8a6a8 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -54,6 +54,7 @@ #include "nodeinfo.h" #include "memory.h" #include "virfile.h" +#include "virtypedparam.h" #include "logging.h" #include "command.h" #include "viruri.h" @@ -65,6 +66,8 @@ #define CMDBUF_LEN 1488 #define CMDOP_LEN 288 +#define OPENVZ_NB_MEM_PARAM 3 + static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid); static int openvzGetMaxVCPUs(virConnectPtr conn, const char *type); static int openvzDomainGetMaxVcpus(virDomainPtr dom); @@ -1631,6 +1634,201 @@ cleanup: return -1; } + +static int +openvzDomainGetBarrierLimit(virDomainPtr domain, + const char *param, + long *barrier, + long *limit) +{ + int status, ret = -1; + char *output = NULL; + virCommandPtr cmd = virCommandNewArgList(VZLIST, "--no-header", NULL); + + virCommandSetOutputBuffer(cmd, &output); + virCommandAddArgFormat(cmd, "-o%s.b,%s.l", param, param); + virCommandAddArg(cmd, domain->name); + if (virCommandRun(cmd, &status)) { + openvzError(VIR_ERR_OPERATION_FAILED, + _("Failed to get %s for %s: %d"), param, domain->name, + status); + goto cleanup; + } + + if (sscanf(output, "%ld %ld", barrier, limit) != 2) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Can't parse "VZLIST" output, got %s"), output); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FREE(output); + virCommandFree(cmd); + return ret; +} + + +static int +openvzDomainSetBarrierLimit(virDomainPtr domain, + const char *param, + long barrier, + long limit) +{ + int status, ret = -1; + virCommandPtr cmd = virCommandNewArgList(VZCTL, "--quiet", "set", NULL); + + virCommandAddArg(cmd, domain->name); + virCommandAddArgFormat(cmd, "--%s", param); + virCommandAddArgFormat(cmd, "%ld:%ld", barrier, limit); + virCommandAddArg(cmd, "--save"); + if (virCommandRun(cmd, &status)) { + openvzError(VIR_ERR_OPERATION_FAILED, + _("Failed to set %s for %s: %d"), param, domain->name, + status); + goto cleanup; + } + + ret = 0; +cleanup: + virCommandFree(cmd); + return ret; +} + + +static int +openvzDomainGetMemoryParameters(virDomainPtr domain, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + int i, result = -1; + const char *name; + long barrier, limit, kb_per_pages; + unsigned long long int val; + + virCheckFlags(0, -1); + + kb_per_pages = sysconf(_SC_PAGESIZE) / 1024; + if (kb_per_pages == -1) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Can't determine page size")); + goto cleanup; + } + + if (*nparams == 0) { + *nparams = OPENVZ_NB_MEM_PARAM; + return 0; + } + + for (i = 0; i <= *nparams; i++) { + virMemoryParameterPtr param = ¶ms[i]; + + switch (i) { + case 0: + name = "privvmpages"; + if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0) + goto cleanup; + + val = limit * kb_per_pages; + if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT, + VIR_TYPED_PARAM_ULLONG, val) < 0) + goto cleanup; + break; + + case 1: + name = "privvmpages"; + if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0) + goto cleanup; + + val = barrier * kb_per_pages; + if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT, + VIR_TYPED_PARAM_ULLONG, val) < 0) + goto cleanup; + break; + + case 2: + name = "vmguarpages"; + if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0) + goto cleanup; + + val = barrier * kb_per_pages; + if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_MIN_GUARANTEE, + VIR_TYPED_PARAM_ULLONG, val) < 0) + goto cleanup; + break; + } + } + + if (*nparams > OPENVZ_NB_MEM_PARAM) + *nparams = OPENVZ_NB_MEM_PARAM; + result = 0; + +cleanup: + return result; +} + + +static int +openvzDomainSetMemoryParameters(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + int i, result = -1; + long kb_per_pages; + + kb_per_pages = sysconf(_SC_PAGESIZE) / 1024; + if (kb_per_pages == -1) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Can't determine page size")); + goto cleanup; + } + + virCheckFlags(0, -1); + if (virTypedParameterArrayValidate(params, nparams, + VIR_DOMAIN_MEMORY_HARD_LIMIT, + VIR_TYPED_PARAM_ULLONG, + VIR_DOMAIN_MEMORY_SOFT_LIMIT, + VIR_TYPED_PARAM_ULLONG, + VIR_DOMAIN_MEMORY_MIN_GUARANTEE, + VIR_TYPED_PARAM_ULLONG, + NULL) < 0) + return -1; + + for (i = 0; i < nparams; i++) { + virTypedParameterPtr param = ¶ms[i]; + long barrier, limit; + + if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) { + if (openvzDomainGetBarrierLimit(domain, "privvmpages", + &barrier, &limit) < 0) + goto cleanup; + limit = params[i].value.ul / kb_per_pages; + if (openvzDomainSetBarrierLimit(domain, "privvmpages", + barrier, limit) < 0) + goto cleanup; + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) { + if (openvzDomainGetBarrierLimit(domain, "privvmpages", + &barrier, &limit) < 0) + goto cleanup; + barrier = params[i].value.ul / kb_per_pages; + if (openvzDomainSetBarrierLimit(domain, "privvmpages", + barrier, limit) < 0) + goto cleanup; + } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) { + barrier = params[i].value.ul / kb_per_pages; + if (openvzDomainSetBarrierLimit(domain, "vmguarpages", + barrier, LONG_MAX) < 0) + goto cleanup; + } + } + result = 0; +cleanup: + return result; +} + + static int openvzGetVEStatus(virDomainObjPtr vm, int *status, int *reason) { @@ -1752,6 +1950,8 @@ static virDriver openvzDriver = { .domainDestroy = openvzDomainShutdown, /* 0.3.1 */ .domainDestroyFlags = openvzDomainShutdownFlags, /* 0.9.4 */ .domainGetOSType = openvzGetOSType, /* 0.3.1 */ + .domainGetMemoryParameters = openvzDomainGetMemoryParameters, /* 0.9.12 */ + .domainSetMemoryParameters = openvzDomainSetMemoryParameters, /* 0.9.12 */ .domainGetInfo = openvzDomainGetInfo, /* 0.3.1 */ .domainGetState = openvzDomainGetState, /* 0.9.2 */ .domainSetVcpus = openvzDomainSetVcpus, /* 0.4.6 */ -- 1.7.10 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list