[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCHv2] openvz: read vmguarpages/privvmpages to set memory tunables



---
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 = &params[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 = &params[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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]