---
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