diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 5d1003f35c..db08c09534 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -883,7 +883,9 @@ nodeGetCPUStats; nodeGetCellsFreeMemory; nodeGetFreeMemory; nodeGetInfo; +nodeGetMemoryParameters; nodeGetMemoryStats; +nodeSetMemoryParameters; # nwfilter_conf.h diff --git a/src/nodeinfo.c b/src/nodeinfo.c index e3d4a242dd..7af6512a7f 100644 --- a/src/nodeinfo.c +++ b/src/nodeinfo.c @@ -48,6 +48,7 @@ #include "count-one-bits.h" #include "intprops.h" #include "virfile.h" +#include "virtypedparam.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -57,6 +58,7 @@ # define SYSFS_SYSTEM_PATH "/sys/devices/system" # define PROCSTAT_PATH "/proc/stat" # define MEMINFO_PATH "/proc/meminfo" +# define SYSFS_MEMORY_SHARED_PATH "/sys/kernel/mm/ksm" # define LINUX_NB_CPU_STATS 4 # define LINUX_NB_MEMORY_STATS_ALL 4 @@ -933,6 +935,253 @@ nodeGetCPUmap(virConnectPtr conn ATTRIBUTE_UNUSED, #endif } +static int +nodeSetMemoryParameterValue(const char *field, + virTypedParameterPtr param) +{ + char *path = NULL; + char *strval = NULL; + int ret = -1; + int rc = -1; + + if (virAsprintf(&path, "%s/%s", + SYSFS_MEMORY_SHARED_PATH, field) < 0) { + virReportOOMError(); + ret = -2; + goto cleanup; + } + + if (virAsprintf(&strval, "%u", param->value.ui) == -1) { + virReportOOMError(); + ret = -2; + goto cleanup; + } + + if ((rc = virFileWriteStr(path, strval, 0)) < 0) { + virReportSystemError(-rc, _("failed to set %s"), field); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FREE(path); + VIR_FREE(strval); + return ret; +} + +int +nodeSetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + unsigned int flags) +{ + virCheckFlags(0, -1); + +#ifdef __linux__ + int ret = 0; + int i; + + if (virTypedParameterArrayValidate(params, nparams, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, + NULL) < 0) + return -1; + + for (i = 0; i < nparams; i++) { + virTypedParameterPtr param = ¶ms[i]; + + if (STREQ(param->field, + VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN)) { + ret = nodeSetMemoryParameterValue("pages_to_scan", param); + + /* Out of memory */ + if (ret == -2) + return -1; + } else if (STREQ(param->field, + VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS)) { + ret = nodeSetMemoryParameterValue("sleep_millisecs", param); + + /* Out of memory */ + if (ret == -2) + return -1; + } + } + + return ret; +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node set memory parameters not implemented" + " on this platform")); + return -1; +#endif +} + +static int +nodeGetMemoryParameterValue(const char *field, + void *value) +{ + char *path = NULL; + char *buf = NULL; + char *tmp = NULL; + int ret = -1; + int rc = -1; + + if (virAsprintf(&path, "%s/%s", + SYSFS_MEMORY_SHARED_PATH, field) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileReadAll(path, 1024, &buf) < 0) + goto cleanup; + + if ((tmp = strchr(buf, '\n'))) + *tmp = '\0'; + + if (STREQ(field, "pages_to_scan") || + STREQ(field, "sleep_millisecs")) + rc = virStrToLong_ui(buf, NULL, 10, (unsigned int *)value); + else if (STREQ(field, "pages_shared") || + STREQ(field, "pages_sharing") || + STREQ(field, "pages_unshared") || + STREQ(field, "pages_volatile") || + STREQ(field, "full_scans")) + rc = virStrToLong_ull(buf, NULL, 10, (unsigned long long *)value); + + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse %s"), field); + goto cleanup; + } + + ret = 0; +cleanup: + VIR_FREE(path); + VIR_FREE(buf); + return ret; +} + +#define NODE_MEMORY_PARAMETERS_NUM 7 +int +nodeGetMemoryParameters(virConnectPtr conn ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int *nparams, + unsigned int flags) +{ + virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1); + +#ifdef __linux__ + unsigned int pages_to_scan; + unsigned int sleep_millisecs; + unsigned long long pages_shared; + unsigned long long pages_sharing; + unsigned long long pages_unshared; + unsigned long long pages_volatile; + unsigned long long full_scans = 0; + int i; + + if ((*nparams) == 0) { + *nparams = NODE_MEMORY_PARAMETERS_NUM; + return 0; + } + + for (i = 0; i < *nparams && i < NODE_MEMORY_PARAMETERS_NUM; i++) { + virTypedParameterPtr param = ¶ms[i]; + + switch(i) { + case 0: + if (nodeGetMemoryParameterValue("pages_to_scan", + &pages_to_scan) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN, + VIR_TYPED_PARAM_UINT, pages_to_scan) < 0) + return -1; + + break; + + case 1: + if (nodeGetMemoryParameterValue("sleep_millisecs", + &sleep_millisecs) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS, + VIR_TYPED_PARAM_UINT, sleep_millisecs) < 0) + return -1; + + break; + + case 2: + if (nodeGetMemoryParameterValue("pages_shared", + &pages_shared) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARED, + VIR_TYPED_PARAM_ULLONG, pages_shared) < 0) + return -1; + + break; + + case 3: + if (nodeGetMemoryParameterValue("pages_sharing", + &pages_sharing) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARING, + VIR_TYPED_PARAM_ULLONG, pages_sharing) < 0) + return -1; + + break; + + case 4: + if (nodeGetMemoryParameterValue("pages_unshared", + &pages_unshared) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED, + VIR_TYPED_PARAM_ULLONG, pages_unshared) < 0) + return -1; + + break; + + case 5: + if (nodeGetMemoryParameterValue("pages_volatile", + &pages_volatile) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE, + VIR_TYPED_PARAM_ULLONG, pages_volatile) < 0) + return -1; + + break; + + case 6: + if (nodeGetMemoryParameterValue("full_scans", + &full_scans) < 0) + return -1; + + if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_FULL_SCANS, + VIR_TYPED_PARAM_ULLONG, full_scans) < 0) + return -1; + + break; + + default: + break; + } + } + + return 0; +#else + virReportError(VIR_ERR_NO_SUPPORT, "%s", + _("node get memory parameters not implemented" + " on this platform")); + return -1; +#endif +} + #if HAVE_NUMACTL # if LIBNUMA_API_VERSION <= 1 # define NUMA_MAX_N_CPUS 4096 diff --git a/src/nodeinfo.h b/src/nodeinfo.h index 12090e26e8..25ad0dd5c5 100644 --- a/src/nodeinfo.h +++ b/src/nodeinfo.h @@ -49,4 +49,14 @@ unsigned long long nodeGetFreeMemory(virConnectPtr conn); char *nodeGetCPUmap(virConnectPtr conn, int *max_id, const char *mapname); + +int nodeGetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int *nparams, + unsigned int flags); + +int nodeSetMemoryParameters(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + unsigned int flags); #endif /* __VIR_NODEINFO_H__*/