--- Changes since last time: * check sysconf return value before division * use virStrToLong_ull instead of sscanf O.k. to apply? Cheers, -- Guido src/openvz/openvz_conf.c | 115 ++++++++++++ src/openvz/openvz_driver.c | 222 +++++++++++++++++++++++ tests/domainschemadata/domain-openvz-simple.xml | 27 +++ 3 files changed, 364 insertions(+) create mode 100644 tests/domainschemadata/domain-openvz-simple.xml diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c index 5848ec4..3806835 100644 --- a/src/openvz/openvz_conf.c +++ b/src/openvz/openvz_conf.c @@ -129,6 +129,46 @@ int openvzExtractVersion(struct openvz_driver *driver) } +/* Parse config values of the form barrier:limit into barrier and limit */ +static int +openvzParseBarrierLimit(const char* value, + unsigned long long *barrier, + unsigned long 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_ull(token, NULL, 10, barrier)) + goto error; + } + } + token = strtok_r(NULL, ":", &saveptr); + if (token == NULL) { + goto error; + } else { + if (limit != NULL) { + if (virStrToLong_ull(token, NULL, 10, limit)) + goto error; + } + } + return 0; +error: + VIR_FREE(str); + return -1; +} + + static int openvzDefaultConsoleType(const char *ostype ATTRIBUTE_UNUSED) { return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_OPENVZ; @@ -423,6 +463,80 @@ error: } +static int +openvzReadMemConf(virDomainDefPtr def, int veid) +{ + int ret; + char *temp = NULL; + unsigned long long barrier, limit; + const char *param; + unsigned long kb_per_pages; + + kb_per_pages = sysconf(_SC_PAGESIZE); + if (kb_per_pages > 0) { + kb_per_pages /= 1024; + } else { + 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 = openvzParseBarrierLimit(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; + } + if (barrier == LONG_MAX) + def->mem.min_guarantee = 0ull; + else + 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 = openvzParseBarrierLimit(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; + } + if (barrier == LONG_MAX) + def->mem.soft_limit = 0ull; + else + def->mem.soft_limit = barrier * kb_per_pages; + + if (limit == LONG_MAX) + def->mem.hard_limit = 0ull; + else + 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 +649,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..91f5d49 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,223 @@ cleanup: return -1; } + +static int +openvzDomainGetBarrierLimit(virDomainPtr domain, + const char *param, + unsigned long long *barrier, + unsigned long long *limit) +{ + int status, ret = -1; + char *endp, *output = NULL; + const char *tmp; + 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; + } + + tmp = output; + virSkipSpaces(&tmp); + if (virStrToLong_ull(tmp, &endp, 10, barrier) < 0) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Can't parse limit from "VZLIST" output '%s'"), output); + goto cleanup; + } + tmp = endp; + virSkipSpaces(&tmp); + if (virStrToLong_ull(tmp, &endp, 10, limit) < 0) { + openvzError(VIR_ERR_INTERNAL_ERROR, + _("Can't parse barrier from "VZLIST" output '%s'"), output); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FREE(output); + virCommandFree(cmd); + return ret; +} + + +static int +openvzDomainSetBarrierLimit(virDomainPtr domain, + const char *param, + unsigned long long barrier, + unsigned long long limit) +{ + int status, ret = -1; + virCommandPtr cmd = virCommandNewArgList(VZCTL, "--quiet", "set", NULL); + + /* LONG_MAX indicates unlimited so reject larger values */ + if (barrier > LONG_MAX || limit > LONG_MAX) { + openvzError(VIR_ERR_OPERATION_FAILED, + _("Failed to set %s for %s: value too large"), param, + domain->name); + goto cleanup; + } + + virCommandAddArg(cmd, domain->name); + virCommandAddArgFormat(cmd, "--%s", param); + virCommandAddArgFormat(cmd, "%llu:%llu", 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 kb_per_pages; + unsigned long long barrier, limit, val; + + virCheckFlags(0, -1); + + kb_per_pages = sysconf(_SC_PAGESIZE); + if (kb_per_pages > 0) { + kb_per_pages /= 1024; + } else { + 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 == LONG_MAX) ? 0ull : 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 == LONG_MAX) ? 0ull : 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 == LONG_MAX) ? 0ull : 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); + if (kb_per_pages > 0) { + kb_per_pages /= 1024; + } else { + 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]; + unsigned long 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 +1972,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 */ diff --git a/tests/domainschemadata/domain-openvz-simple.xml b/tests/domainschemadata/domain-openvz-simple.xml new file mode 100644 index 0000000..aba64a4 --- /dev/null +++ b/tests/domainschemadata/domain-openvz-simple.xml @@ -0,0 +1,27 @@ +<domain type='openvz'> + <name>100</name> + <uuid>7109d234-f5a8-30a6-5dd2-39ca85ce3958</uuid> + <memory unit='KiB'>0</memory> + <currentMemory unit='KiB'>0</currentMemory> + <memtune> + <hard_limit unit='KiB'>278528</hard_limit> + <soft_limit unit='KiB'>262144</soft_limit> + <min_guarantee unit='KiB'>135168</min_guarantee> + </memtune> + <vcpu>1</vcpu> + <os> + <type>exe</type> + <init>/sbin/init</init> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>destroy</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <filesystem type='template' accessmode='passthrough'> + <source name='debian'/> + <target dir='/'/> + </filesystem> + </devices> +</domain> + -- 1.7.10 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list