---
po/POTFILES.in | 1 +
src/Makefile.am | 1 +
src/lxc/lxc_driver.c | 1 +
src/nodeinfo.c | 812 +-----------------------------------------
src/nodeinfo.h | 31 --
src/openvz/openvz_driver.c | 1 +
src/qemu/qemu_driver.c | 1 +
src/uml/uml_driver.c | 1 +
src/util/virhostmem.c | 865 +++++++++++++++++++++++++++++++++++++++++++++
src/util/virhostmem.h | 60 ++++
src/util/virnuma.c | 2 +-
src/vbox/vbox_common.c | 1 +
src/xen/xen_driver.c | 1 +
13 files changed, 935 insertions(+), 843 deletions(-)
create mode 100644 src/util/virhostmem.c
create mode 100644 src/util/virhostmem.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b0cd8cf..0cd9c08 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -197,6 +197,7 @@ src/util/virhash.c
src/util/virhook.c
src/util/virhostcpu.c
src/util/virhostdev.c
+src/util/virhostmem.c
src/util/viridentity.c
src/util/virinitctl.c
src/util/viriptables.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 8d2a8e0..8b6ff15 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -120,6 +120,7 @@ UTIL_SOURCES = \
util/virhook.c util/virhook.h \
util/virhostcpu.c util/virhostcpu.h util/virhostcpupriv.h \
util/virhostdev.c util/virhostdev.h \
+ util/virhostmem.c util/virhostmem.h \
util/viridentity.c util/viridentity.h \
util/virinitctl.c util/virinitctl.h \
util/viriptables.c util/viriptables.h \
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 2cecabc..3550026 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -52,6 +52,7 @@
#include "virnetdevopenvswitch.h"
#include "nodeinfo.h"
#include "virhostcpu.h"
+#include "virhostmem.h"
#include "viruuid.h"
#include "virstats.h"
#include "virhook.h"
diff --git a/src/nodeinfo.c b/src/nodeinfo.c
index 8bf495f..4e344bb 100644
--- a/src/nodeinfo.c
+++ b/src/nodeinfo.c
@@ -28,27 +28,16 @@
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
-#include <dirent.h>
#include <sys/utsname.h>
#include "conf/domain_conf.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
-#if HAVE_LINUX_KVM_H
-# include <linux/kvm.h>
-#endif
-
-#if defined(__FreeBSD__) || defined(__APPLE__)
-# include <sys/time.h>
-# include <sys/types.h>
-# include <sys/sysctl.h>
-# include <sys/resource.h>
-#endif
-
#include "viralloc.h"
#include "nodeinfo.h"
#include "virhostcpu.h"
+#include "virhostmem.h"
#include "physmem.h"
#include "virerror.h"
#include "count-one-bits.h"
@@ -65,92 +54,11 @@
VIR_LOG_INIT("nodeinfo");
-#ifdef __FreeBSD__
-# define BSD_MEMORY_STATS_ALL 4
-
-static int
-virHostMemGetStatsFreeBSD(virNodeMemoryStatsPtr params,
- int *nparams)
-{
- size_t i, j = 0;
- unsigned long pagesize = getpagesize() >> 10;
- long bufpages;
- size_t bufpages_size = sizeof(bufpages);
- struct field_sysctl_map {
- const char *field;
- const char *sysctl_name;
- } sysctl_map[] = {
- {VIR_NODE_MEMORY_STATS_TOTAL, "vm.stats.vm.v_page_count"},
- {VIR_NODE_MEMORY_STATS_FREE, "vm.stats.vm.v_free_count"},
- {VIR_NODE_MEMORY_STATS_CACHED, "vm.stats.vm.v_cache_count"},
- {NULL, NULL}
- };
-
- if ((*nparams) == 0) {
- *nparams = BSD_MEMORY_STATS_ALL;
- return 0;
- }
-
- if ((*nparams) != BSD_MEMORY_STATS_ALL) {
- virReportInvalidArg(nparams,
- _("nparams in %s must be %d"),
- __FUNCTION__, BSD_MEMORY_STATS_ALL);
- return -1;
- }
-
- for (i = 0; sysctl_map[i].field != NULL; i++) {
- u_int value;
- size_t value_size = sizeof(value);
- virNodeMemoryStatsPtr param;
-
- if (sysctlbyname(sysctl_map[i].sysctl_name, &value,
- &value_size, NULL, 0) < 0) {
- virReportSystemError(errno,
- _("sysctl failed for '%s'"),
- sysctl_map[i].sysctl_name);
- return -1;
- }
-
- param = ¶ms[j++];
- if (virStrcpyStatic(param->field, sysctl_map[i].field) == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Field '%s' too long for destination"),
- sysctl_map[i].field);
- return -1;
- }
- param->value = (unsigned long long)value * pagesize;
- }
-
- {
- virNodeMemoryStatsPtr param = ¶ms[j++];
-
- if (sysctlbyname("vfs.bufspace", &bufpages, &bufpages_size,
NULL, 0) < 0) {
- virReportSystemError(errno,
- _("sysctl failed for '%s'"),
- "vfs.bufspace");
- return -1;
- }
- if (virStrcpyStatic(param->field, VIR_NODE_MEMORY_STATS_BUFFERS) == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Field '%s' too long for destination"),
- VIR_NODE_MEMORY_STATS_BUFFERS);
- return -1;
- }
- param->value = (unsigned long long)bufpages >> 10;
- }
-
- return 0;
-}
-#endif /* __FreeBSD__ */
#ifdef __linux__
# define SYSFS_SYSTEM_PATH "/sys/devices/system"
-# define MEMINFO_PATH "/proc/meminfo"
-# define SYSFS_MEMORY_SHARED_PATH "/sys/kernel/mm/ksm"
# define SYSFS_THREAD_SIBLINGS_LIST_LENGTH_MAX 8192
-# define LINUX_NB_MEMORY_STATS_ALL 4
-# define LINUX_NB_MEMORY_STATS_CELL 2
/* Return the positive decimal contents of the given
* DIR/cpu%u/FILE, or -1 on error. If DEFAULT_VALUE is non-negative
@@ -199,113 +107,6 @@ virNodeGetCpuValue(const char *dir, unsigned int cpu, const char
*file,
}
-static int
-virHostMemGetStatsLinux(FILE *meminfo,
- int cellNum,
- virNodeMemoryStatsPtr params,
- int *nparams)
-{
- int ret = -1;
- size_t i = 0, j = 0, k = 0;
- int found = 0;
- int nr_param;
- char line[1024];
- char meminfo_hdr[VIR_NODE_MEMORY_STATS_FIELD_LENGTH];
- unsigned long val;
- struct field_conv {
- const char *meminfo_hdr; // meminfo header
- const char *field; // MemoryStats field name
- } field_conv[] = {
- {"MemTotal:", VIR_NODE_MEMORY_STATS_TOTAL},
- {"MemFree:", VIR_NODE_MEMORY_STATS_FREE},
- {"Buffers:", VIR_NODE_MEMORY_STATS_BUFFERS},
- {"Cached:", VIR_NODE_MEMORY_STATS_CACHED},
- {NULL, NULL}
- };
-
- if (cellNum == VIR_NODE_MEMORY_STATS_ALL_CELLS) {
- nr_param = LINUX_NB_MEMORY_STATS_ALL;
- } else {
- nr_param = LINUX_NB_MEMORY_STATS_CELL;
- }
-
- if ((*nparams) == 0) {
- /* Current number of memory stats supported by linux */
- *nparams = nr_param;
- ret = 0;
- goto cleanup;
- }
-
- if ((*nparams) != nr_param) {
- virReportInvalidArg(nparams,
- _("nparams in %s must be %d"),
- __FUNCTION__, nr_param);
- goto cleanup;
- }
-
- while (fgets(line, sizeof(line), meminfo) != NULL) {
- char *buf = line;
-
- if (STRPREFIX(buf, "Node ")) {
- /*
- * /sys/devices/system/node/nodeX/meminfo format is below.
- * So, skip prefix "Node XX ".
- *
- * Node 0 MemTotal: 8386980 kB
- * Node 0 MemFree: 5300920 kB
- * :
- */
- char *p;
-
- p = buf;
- for (i = 0; i < 2; i++) {
- p = strchr(p, ' ');
- if (p == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("no prefix found"));
- goto cleanup;
- }
- p++;
- }
- buf = p;
- }
-
- if (sscanf(buf, "%s %lu kB", meminfo_hdr, &val) < 2)
- continue;
-
- for (j = 0; field_conv[j].meminfo_hdr != NULL; j++) {
- struct field_conv *convp = &field_conv[j];
-
- if (STREQ(meminfo_hdr, convp->meminfo_hdr)) {
- virNodeMemoryStatsPtr param = ¶ms[k++];
-
- if (virStrcpyStatic(param->field, convp->field) == NULL) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("Field kernel memory too long
for destination"));
- goto cleanup;
- }
- param->value = val;
- found++;
- break;
- }
- }
- if (found >= nr_param)
- break;
- }
-
- if (found == 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("no available memory line found"));
- goto cleanup;
- }
-
- ret = 0;
-
- cleanup:
- return ret;
-}
-
-
static virBitmapPtr
virNodeGetSiblingsListLinux(const char *dir, int cpu_id)
{
@@ -356,367 +157,6 @@ nodeGetInfo(virNodeInfoPtr nodeinfo)
}
-int
-virHostMemGetStats(int cellNum ATTRIBUTE_UNUSED,
- virNodeMemoryStatsPtr params ATTRIBUTE_UNUSED,
- int *nparams ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- virCheckFlags(0, -1);
-
-#ifdef __linux__
- {
- int ret;
- char *meminfo_path = NULL;
- FILE *meminfo;
- int max_node;
-
- if (cellNum == VIR_NODE_MEMORY_STATS_ALL_CELLS) {
- if (VIR_STRDUP(meminfo_path, MEMINFO_PATH) < 0)
- return -1;
- } else {
- if ((max_node = virNumaGetMaxNode()) < 0)
- return -1;
-
- if (cellNum > max_node) {
- virReportInvalidArg(cellNum,
- _("cellNum in %s must be less than or equal to
%d"),
- __FUNCTION__, max_node);
- return -1;
- }
-
- if (virAsprintf(&meminfo_path,
- SYSFS_SYSTEM_PATH "/node/node%d/meminfo",
- cellNum) < 0)
- return -1;
- }
- meminfo = fopen(meminfo_path, "r");
-
- if (!meminfo) {
- virReportSystemError(errno,
- _("cannot open %s"), meminfo_path);
- VIR_FREE(meminfo_path);
- return -1;
- }
- ret = virHostMemGetStatsLinux(meminfo, cellNum, params, nparams);
- VIR_FORCE_FCLOSE(meminfo);
- VIR_FREE(meminfo_path);
-
- return ret;
- }
-#elif defined(__FreeBSD__)
- return virHostMemGetStatsFreeBSD(params, nparams);
-#else
- virReportError(VIR_ERR_NO_SUPPORT, "%s",
- _("node memory stats not implemented on this platform"));
- return -1;
-#endif
-}
-
-
-#ifdef __linux__
-static int
-virHostMemSetParameterValue(virTypedParameterPtr param)
-{
- char *path = NULL;
- char *strval = NULL;
- int ret = -1;
- int rc = -1;
-
- char *field = strchr(param->field, '_');
- sa_assert(field);
- field++;
- if (virAsprintf(&path, "%s/%s",
- SYSFS_MEMORY_SHARED_PATH, field) < 0) {
- ret = -2;
- goto cleanup;
- }
-
- if (virAsprintf(&strval, "%u", param->value.ui) == -1) {
- ret = -2;
- goto cleanup;
- }
-
- if ((rc = virFileWriteStr(path, strval, 0)) < 0) {
- virReportSystemError(-rc, _("failed to set %s"), param->field);
- goto cleanup;
- }
-
- ret = 0;
- cleanup:
- VIR_FREE(path);
- VIR_FREE(strval);
- return ret;
-}
-
-static bool
-virHostMemParametersAreAllSupported(virTypedParameterPtr params,
- int nparams)
-{
- char *path = NULL;
- size_t i;
-
- for (i = 0; i < nparams; i++) {
- virTypedParameterPtr param = ¶ms[i];
-
- char *field = strchr(param->field, '_');
- sa_assert(field);
- field++;
- if (virAsprintf(&path, "%s/%s",
- SYSFS_MEMORY_SHARED_PATH, field) < 0)
- return false;
-
- if (!virFileExists(path)) {
- virReportError(VIR_ERR_OPERATION_INVALID,
- _("Parameter '%s' is not supported by "
- "this kernel"), param->field);
- VIR_FREE(path);
- return false;
- }
-
- VIR_FREE(path);
- }
-
- return true;
-}
-#endif
-
-int
-virHostMemSetParameters(virTypedParameterPtr params ATTRIBUTE_UNUSED,
- int nparams ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- virCheckFlags(0, -1);
-
-#ifdef __linux__
- size_t i;
- int rc;
-
- if (virTypedParamsValidate(params, nparams,
- VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN,
- VIR_TYPED_PARAM_UINT,
- VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS,
- VIR_TYPED_PARAM_UINT,
- VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES,
- VIR_TYPED_PARAM_UINT,
- NULL) < 0)
- return -1;
-
- if (!virHostMemParametersAreAllSupported(params, nparams))
- return -1;
-
- for (i = 0; i < nparams; i++) {
- rc = virHostMemSetParameterValue(¶ms[i]);
-
- if (rc < 0)
- return -1;
- }
-
- return 0;
-#else
- virReportError(VIR_ERR_NO_SUPPORT, "%s",
- _("node set memory parameters not implemented"
- " on this platform"));
- return -1;
-#endif
-}
-
-#ifdef __linux__
-static int
-virHostMemGetParameterValue(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)
- goto cleanup;
-
- if (!virFileExists(path)) {
- ret = -2;
- 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") ||
- STREQ(field, "merge_across_nodes"))
- 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;
-}
-#endif
-
-#define NODE_MEMORY_PARAMETERS_NUM 8
-int
-virHostMemGetParameters(virTypedParameterPtr params ATTRIBUTE_UNUSED,
- int *nparams ATTRIBUTE_UNUSED,
- unsigned int flags)
-{
- virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
-
-#ifdef __linux__
- unsigned int pages_to_scan;
- unsigned int sleep_millisecs;
- unsigned int merge_across_nodes;
- 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;
- size_t i;
- int ret;
-
- 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:
- ret = virHostMemGetParameterValue("pages_to_scan",
&pages_to_scan);
- if (ret == -2)
- continue;
- else if (ret == -1)
- 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:
- ret = virHostMemGetParameterValue("sleep_millisecs",
&sleep_millisecs);
- if (ret == -2)
- continue;
- else if (ret == -1)
- return -1;
-
- if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS,
- VIR_TYPED_PARAM_UINT, sleep_millisecs) < 0)
- return -1;
-
- break;
-
- case 2:
- ret = virHostMemGetParameterValue("pages_shared",
&pages_shared);
- if (ret == -2)
- continue;
- else if (ret == -1)
- return -1;
-
- if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARED,
- VIR_TYPED_PARAM_ULLONG, pages_shared) < 0)
- return -1;
-
- break;
-
- case 3:
- ret = virHostMemGetParameterValue("pages_sharing",
&pages_sharing);
- if (ret == -2)
- continue;
- else if (ret == -1)
- return -1;
-
- if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARING,
- VIR_TYPED_PARAM_ULLONG, pages_sharing) < 0)
- return -1;
-
- break;
-
- case 4:
- ret = virHostMemGetParameterValue("pages_unshared",
&pages_unshared);
- if (ret == -2)
- continue;
- else if (ret == -1)
- return -1;
-
- if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED,
- VIR_TYPED_PARAM_ULLONG, pages_unshared) < 0)
- return -1;
-
- break;
-
- case 5:
- ret = virHostMemGetParameterValue("pages_volatile",
&pages_volatile);
- if (ret == -2)
- continue;
- else if (ret == -1)
- return -1;
-
- if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE,
- VIR_TYPED_PARAM_ULLONG, pages_volatile) < 0)
- return -1;
-
- break;
-
- case 6:
- ret = virHostMemGetParameterValue("full_scans", &full_scans);
- if (ret == -2)
- continue;
- else if (ret == -1)
- return -1;
-
- if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_FULL_SCANS,
- VIR_TYPED_PARAM_ULLONG, full_scans) < 0)
- return -1;
-
- break;
-
- case 7:
- ret = virHostMemGetParameterValue("merge_across_nodes",
&merge_across_nodes);
- if (ret == -2)
- continue;
- else if (ret == -1)
- return -1;
-
- if (virTypedParameterAssign(param,
VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES,
- VIR_TYPED_PARAM_UINT, merge_across_nodes) <
0)
- return -1;
-
- break;
- }
- }
-
- return 0;
-#else
- virReportError(VIR_ERR_NO_SUPPORT, "%s",
- _("node get memory parameters not implemented"
- " on this platform"));
- return -1;
-#endif
-}
-
-
static int
nodeCapsInitNUMAFake(const char *cpupath ATTRIBUTE_UNUSED,
virCapsPtr caps ATTRIBUTE_UNUSED)
@@ -780,92 +220,6 @@ nodeCapsInitNUMAFake(const char *cpupath ATTRIBUTE_UNUSED,
return -1;
}
-static int
-virHostMemGetCellsFreeFake(unsigned long long *freeMems,
- int startCell,
- int maxCells ATTRIBUTE_UNUSED)
-{
- double avail = physmem_available();
-
- if (startCell != 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("start cell %d out of range (0-%d)"),
- startCell, 0);
- return -1;
- }
-
- freeMems[0] = (unsigned long long)avail;
-
- if (!freeMems[0]) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot determine free memory"));
- return -1;
- }
-
- return 1;
-}
-
-static int
-virHostMemGetInfoFake(unsigned long long *mem,
- unsigned long long *freeMem)
-{
- int ret = -1;
-
-#if defined(__FreeBSD__)
- unsigned long pagesize = getpagesize();
- u_int value;
- size_t value_size = sizeof(value);
-
- if (mem) {
- if (sysctlbyname("vm.stats.vm.v_page_count", &value,
- &value_size, NULL, 0) < 0) {
- virReportSystemError(errno, "%s",
- _("sysctl failed for
vm.stats.vm.v_page_count"));
- goto cleanup;
- }
- *mem = value * (unsigned long long)pagesize;
- }
-
- if (freeMem) {
- if (sysctlbyname("vm.stats.vm.v_free_count", &value,
- &value_size, NULL, 0) < 0) {
- virReportSystemError(errno, "%s",
- _("sysctl failed for
vm.stats.vm.v_free_count"));
- goto cleanup;
- }
-
- *freeMem = value * (unsigned long long)pagesize;
- }
-
-#else
- if (mem) {
- double total = physmem_total();
- if (!total) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot determine free memory"));
- goto cleanup;
- }
-
- *mem = (unsigned long long) total;
- }
-
- if (freeMem) {
- double avail = physmem_available();
-
- if (!avail) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Cannot determine free memory"));
- goto cleanup;
- }
-
- *freeMem = (unsigned long long) avail;
- }
-#endif
-
- ret = 0;
- cleanup:
- return ret;
-}
/* returns 1 on success, 0 if the detection failed and -1 on hard error */
static int
@@ -1060,167 +414,3 @@ nodeCapsInitNUMA(virCapsPtr caps)
VIR_FREE(pageinfo);
return ret;
}
-
-
-int
-virHostMemGetCellsFree(unsigned long long *freeMems,
- int startCell,
- int maxCells)
-{
- unsigned long long mem;
- int n, lastCell, numCells;
- int ret = -1;
- int maxCell;
-
- if (!virNumaIsAvailable())
- return virHostMemGetCellsFreeFake(freeMems,
- startCell, maxCells);
-
- if ((maxCell = virNumaGetMaxNode()) < 0)
- return 0;
-
- if (startCell > maxCell) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("start cell %d out of range (0-%d)"),
- startCell, maxCell);
- goto cleanup;
- }
- lastCell = startCell + maxCells - 1;
- if (lastCell > maxCell)
- lastCell = maxCell;
-
- for (numCells = 0, n = startCell; n <= lastCell; n++) {
- virNumaGetNodeMemory(n, NULL, &mem);
-
- freeMems[numCells++] = mem;
- }
- ret = numCells;
-
- cleanup:
- return ret;
-}
-
-int
-virHostMemGetInfo(unsigned long long *mem,
- unsigned long long *freeMem)
-{
- int max_node;
- int n;
-
- if (mem)
- *mem = 0;
-
- if (freeMem)
- *freeMem = 0;
-
- if (!virNumaIsAvailable())
- return virHostMemGetInfoFake(mem, freeMem);
-
- if ((max_node = virNumaGetMaxNode()) < 0)
- return -1;
-
- for (n = 0; n <= max_node; n++) {
- unsigned long long tmp_mem = 0, tmp_freeMem = 0;
-
- if (!virNumaNodeIsAvailable(n))
- continue;
-
- if (virNumaGetNodeMemory(n, &tmp_mem, &tmp_freeMem) < 0)
- return -1;
-
- if (mem)
- *mem += tmp_mem;
-
- if (freeMem)
- *freeMem += tmp_freeMem;
- }
-
- return 0;
-}
-
-int
-virHostMemGetFreePages(unsigned int npages,
- unsigned int *pages,
- int startCell,
- unsigned int cellCount,
- unsigned long long *counts)
-{
- int ret = -1;
- int cell, lastCell;
- size_t i, ncounts = 0;
-
- if ((lastCell = virNumaGetMaxNode()) < 0)
- return 0;
-
- if (startCell > lastCell) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("start cell %d out of range (0-%d)"),
- startCell, lastCell);
- goto cleanup;
- }
-
- lastCell = MIN(lastCell, startCell + (int) cellCount - 1);
-
- for (cell = startCell; cell <= lastCell; cell++) {
- for (i = 0; i < npages; i++) {
- unsigned int page_size = pages[i];
- unsigned int page_free;
-
- if (virNumaGetPageInfo(cell, page_size, 0, NULL, &page_free) < 0)
- goto cleanup;
-
- counts[ncounts++] = page_free;
- }
- }
-
- if (!ncounts) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("no suitable info found"));
- goto cleanup;
- }
-
- ret = ncounts;
- cleanup:
- return ret;
-}
-
-int
-virHostMemAllocPages(unsigned int npages,
- unsigned int *pageSizes,
- unsigned long long *pageCounts,
- int startCell,
- unsigned int cellCount,
- bool add)
-{
- int ret = -1;
- int cell, lastCell;
- size_t i, ncounts = 0;
-
- if ((lastCell = virNumaGetMaxNode()) < 0)
- return 0;
-
- if (startCell > lastCell) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("start cell %d out of range (0-%d)"),
- startCell, lastCell);
- goto cleanup;
- }
-
- lastCell = MIN(lastCell, startCell + (int) cellCount - 1);
-
- for (cell = startCell; cell <= lastCell; cell++) {
- for (i = 0; i < npages; i++) {
- unsigned int page_size = pageSizes[i];
- unsigned long long page_count = pageCounts[i];
-
- if (virNumaSetPagePoolSize(cell, page_size, page_count, add) < 0)
- goto cleanup;
-
- ncounts++;
- }
- }
-
- ret = ncounts;
- cleanup:
- return ret;
-}
diff --git a/src/nodeinfo.h b/src/nodeinfo.h
index 918fcb5..3c4dc46 100644
--- a/src/nodeinfo.h
+++ b/src/nodeinfo.h
@@ -29,35 +29,4 @@
int nodeGetInfo(virNodeInfoPtr nodeinfo);
int nodeCapsInitNUMA(virCapsPtr caps);
-int virHostMemGetStats(int cellNum,
- virNodeMemoryStatsPtr params,
- int *nparams,
- unsigned int flags);
-int virHostMemGetCellsFree(unsigned long long *freeMems,
- int startCell,
- int maxCells);
-int virHostMemGetInfo(unsigned long long *mem,
- unsigned long long *freeMem);
-
-int virHostMemGetParameters(virTypedParameterPtr params,
- int *nparams,
- unsigned int flags);
-
-int virHostMemSetParameters(virTypedParameterPtr params,
- int nparams,
- unsigned int flags);
-
-int virHostMemGetFreePages(unsigned int npages,
- unsigned int *pages,
- int startCell,
- unsigned int cellCount,
- unsigned long long *counts);
-
-int virHostMemAllocPages(unsigned int npages,
- unsigned int *pageSizes,
- unsigned long long *pageCounts,
- int startCell,
- unsigned int cellCount,
- bool add);
-
#endif /* __VIR_NODEINFO_H__*/
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index 910ccfe..f3586ce 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -50,6 +50,7 @@
#include "openvz_conf.h"
#include "nodeinfo.h"
#include "virhostcpu.h"
+#include "virhostmem.h"
#include "viralloc.h"
#include "virfile.h"
#include "virtypedparam.h"
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ec04fb7..9860be3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -64,6 +64,7 @@
#include "virbuffer.h"
#include "nodeinfo.h"
#include "virhostcpu.h"
+#include "virhostmem.h"
#include "virstats.h"
#include "capabilities.h"
#include "viralloc.h"
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index 4048b11..cea9999 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -47,6 +47,7 @@
#include "virbuffer.h"
#include "nodeinfo.h"
#include "virhostcpu.h"
+#include "virhostmem.h"
#include "virstats.h"
#include "capabilities.h"
#include "viralloc.h"
diff --git a/src/util/virhostmem.c b/src/util/virhostmem.c
new file mode 100644
index 0000000..6fb383e
--- /dev/null
+++ b/src/util/virhostmem.c
@@ -0,0 +1,865 @@
+/*
+ * virhostmem.c: helper APIs for host memory info
+ *
+ * Copyright (C) 2006-2008, 2010-2015 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#if defined(__FreeBSD__) || defined(__APPLE__)
+# include <sys/time.h>
+# include <sys/types.h>
+# include <sys/sysctl.h>
+# include <sys/resource.h>
+#endif
+
+#include "viralloc.h"
+#include "virhostmem.h"
+#include "physmem.h"
+#include "virerror.h"
+#include "count-one-bits.h"
+#include "virarch.h"
+#include "virfile.h"
+#include "virtypedparam.h"
+#include "virstring.h"
+#include "virnuma.h"
+#include "virlog.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+VIR_LOG_INIT("util.hostmem");
+
+
+#ifdef __FreeBSD__
+# define BSD_MEMORY_STATS_ALL 4
+
+static int
+virHostMemGetStatsFreeBSD(virNodeMemoryStatsPtr params,
+ int *nparams)
+{
+ size_t i, j = 0;
+ unsigned long pagesize = getpagesize() >> 10;
+ long bufpages;
+ size_t bufpages_size = sizeof(bufpages);
+ struct field_sysctl_map {
+ const char *field;
+ const char *sysctl_name;
+ } sysctl_map[] = {
+ {VIR_NODE_MEMORY_STATS_TOTAL, "vm.stats.vm.v_page_count"},
+ {VIR_NODE_MEMORY_STATS_FREE, "vm.stats.vm.v_free_count"},
+ {VIR_NODE_MEMORY_STATS_CACHED, "vm.stats.vm.v_cache_count"},
+ {NULL, NULL}
+ };
+
+ if ((*nparams) == 0) {
+ *nparams = BSD_MEMORY_STATS_ALL;
+ return 0;
+ }
+
+ if ((*nparams) != BSD_MEMORY_STATS_ALL) {
+ virReportInvalidArg(nparams,
+ _("nparams in %s must be %d"),
+ __FUNCTION__, BSD_MEMORY_STATS_ALL);
+ return -1;
+ }
+
+ for (i = 0; sysctl_map[i].field != NULL; i++) {
+ u_int value;
+ size_t value_size = sizeof(value);
+ virNodeMemoryStatsPtr param;
+
+ if (sysctlbyname(sysctl_map[i].sysctl_name, &value,
+ &value_size, NULL, 0) < 0) {
+ virReportSystemError(errno,
+ _("sysctl failed for '%s'"),
+ sysctl_map[i].sysctl_name);
+ return -1;
+ }
+
+ param = ¶ms[j++];
+ if (virStrcpyStatic(param->field, sysctl_map[i].field) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Field '%s' too long for destination"),
+ sysctl_map[i].field);
+ return -1;
+ }
+ param->value = (unsigned long long)value * pagesize;
+ }
+
+ {
+ virNodeMemoryStatsPtr param = ¶ms[j++];
+
+ if (sysctlbyname("vfs.bufspace", &bufpages, &bufpages_size,
NULL, 0) < 0) {
+ virReportSystemError(errno,
+ _("sysctl failed for '%s'"),
+ "vfs.bufspace");
+ return -1;
+ }
+ if (virStrcpyStatic(param->field, VIR_NODE_MEMORY_STATS_BUFFERS) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Field '%s' too long for destination"),
+ VIR_NODE_MEMORY_STATS_BUFFERS);
+ return -1;
+ }
+ param->value = (unsigned long long)bufpages >> 10;
+ }
+
+ return 0;
+}
+#endif /* __FreeBSD__ */
+
+#ifdef __linux__
+# define SYSFS_SYSTEM_PATH "/sys/devices/system"
+# define MEMINFO_PATH "/proc/meminfo"
+# define SYSFS_MEMORY_SHARED_PATH "/sys/kernel/mm/ksm"
+# define SYSFS_THREAD_SIBLINGS_LIST_LENGTH_MAX 8192
+
+# define LINUX_NB_MEMORY_STATS_ALL 4
+# define LINUX_NB_MEMORY_STATS_CELL 2
+
+static int
+virHostMemGetStatsLinux(FILE *meminfo,
+ int cellNum,
+ virNodeMemoryStatsPtr params,
+ int *nparams)
+{
+ int ret = -1;
+ size_t i = 0, j = 0, k = 0;
+ int found = 0;
+ int nr_param;
+ char line[1024];
+ char meminfo_hdr[VIR_NODE_MEMORY_STATS_FIELD_LENGTH];
+ unsigned long val;
+ struct field_conv {
+ const char *meminfo_hdr; // meminfo header
+ const char *field; // MemoryStats field name
+ } field_conv[] = {
+ {"MemTotal:", VIR_NODE_MEMORY_STATS_TOTAL},
+ {"MemFree:", VIR_NODE_MEMORY_STATS_FREE},
+ {"Buffers:", VIR_NODE_MEMORY_STATS_BUFFERS},
+ {"Cached:", VIR_NODE_MEMORY_STATS_CACHED},
+ {NULL, NULL}
+ };
+
+ if (cellNum == VIR_NODE_MEMORY_STATS_ALL_CELLS) {
+ nr_param = LINUX_NB_MEMORY_STATS_ALL;
+ } else {
+ nr_param = LINUX_NB_MEMORY_STATS_CELL;
+ }
+
+ if ((*nparams) == 0) {
+ /* Current number of memory stats supported by linux */
+ *nparams = nr_param;
+ ret = 0;
+ goto cleanup;
+ }
+
+ if ((*nparams) != nr_param) {
+ virReportInvalidArg(nparams,
+ _("nparams in %s must be %d"),
+ __FUNCTION__, nr_param);
+ goto cleanup;
+ }
+
+ while (fgets(line, sizeof(line), meminfo) != NULL) {
+ char *buf = line;
+
+ if (STRPREFIX(buf, "Node ")) {
+ /*
+ * /sys/devices/system/node/nodeX/meminfo format is below.
+ * So, skip prefix "Node XX ".
+ *
+ * Node 0 MemTotal: 8386980 kB
+ * Node 0 MemFree: 5300920 kB
+ * :
+ */
+ char *p;
+
+ p = buf;
+ for (i = 0; i < 2; i++) {
+ p = strchr(p, ' ');
+ if (p == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("no prefix found"));
+ goto cleanup;
+ }
+ p++;
+ }
+ buf = p;
+ }
+
+ if (sscanf(buf, "%s %lu kB", meminfo_hdr, &val) < 2)
+ continue;
+
+ for (j = 0; field_conv[j].meminfo_hdr != NULL; j++) {
+ struct field_conv *convp = &field_conv[j];
+
+ if (STREQ(meminfo_hdr, convp->meminfo_hdr)) {
+ virNodeMemoryStatsPtr param = ¶ms[k++];
+
+ if (virStrcpyStatic(param->field, convp->field) == NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Field kernel memory too long
for destination"));
+ goto cleanup;
+ }
+ param->value = val;
+ found++;
+ break;
+ }
+ }
+ if (found >= nr_param)
+ break;
+ }
+
+ if (found == 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("no available memory line found"));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+#endif
+
+
+int
+virHostMemGetStats(int cellNum ATTRIBUTE_UNUSED,
+ virNodeMemoryStatsPtr params ATTRIBUTE_UNUSED,
+ int *nparams ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+#ifdef __linux__
+ {
+ int ret;
+ char *meminfo_path = NULL;
+ FILE *meminfo;
+ int max_node;
+
+ if (cellNum == VIR_NODE_MEMORY_STATS_ALL_CELLS) {
+ if (VIR_STRDUP(meminfo_path, MEMINFO_PATH) < 0)
+ return -1;
+ } else {
+ if ((max_node = virNumaGetMaxNode()) < 0)
+ return -1;
+
+ if (cellNum > max_node) {
+ virReportInvalidArg(cellNum,
+ _("cellNum in %s must be less than or equal to
%d"),
+ __FUNCTION__, max_node);
+ return -1;
+ }
+
+ if (virAsprintf(&meminfo_path,
+ SYSFS_SYSTEM_PATH "/node/node%d/meminfo",
+ cellNum) < 0)
+ return -1;
+ }
+ meminfo = fopen(meminfo_path, "r");
+
+ if (!meminfo) {
+ virReportSystemError(errno,
+ _("cannot open %s"), meminfo_path);
+ VIR_FREE(meminfo_path);
+ return -1;
+ }
+ ret = virHostMemGetStatsLinux(meminfo, cellNum, params, nparams);
+ VIR_FORCE_FCLOSE(meminfo);
+ VIR_FREE(meminfo_path);
+
+ return ret;
+ }
+#elif defined(__FreeBSD__)
+ return virHostMemGetStatsFreeBSD(params, nparams);
+#else
+ virReportError(VIR_ERR_NO_SUPPORT, "%s",
+ _("node memory stats not implemented on this platform"));
+ return -1;
+#endif
+}
+
+
+#ifdef __linux__
+static int
+virHostMemSetParameterValue(virTypedParameterPtr param)
+{
+ char *path = NULL;
+ char *strval = NULL;
+ int ret = -1;
+ int rc = -1;
+
+ char *field = strchr(param->field, '_');
+ sa_assert(field);
+ field++;
+ if (virAsprintf(&path, "%s/%s",
+ SYSFS_MEMORY_SHARED_PATH, field) < 0) {
+ ret = -2;
+ goto cleanup;
+ }
+
+ if (virAsprintf(&strval, "%u", param->value.ui) == -1) {
+ ret = -2;
+ goto cleanup;
+ }
+
+ if ((rc = virFileWriteStr(path, strval, 0)) < 0) {
+ virReportSystemError(-rc, _("failed to set %s"), param->field);
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(path);
+ VIR_FREE(strval);
+ return ret;
+}
+
+static bool
+virHostMemParametersAreAllSupported(virTypedParameterPtr params,
+ int nparams)
+{
+ char *path = NULL;
+ size_t i;
+
+ for (i = 0; i < nparams; i++) {
+ virTypedParameterPtr param = ¶ms[i];
+
+ char *field = strchr(param->field, '_');
+ sa_assert(field);
+ field++;
+ if (virAsprintf(&path, "%s/%s",
+ SYSFS_MEMORY_SHARED_PATH, field) < 0)
+ return false;
+
+ if (!virFileExists(path)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("Parameter '%s' is not supported by "
+ "this kernel"), param->field);
+ VIR_FREE(path);
+ return false;
+ }
+
+ VIR_FREE(path);
+ }
+
+ return true;
+}
+#endif
+
+int
+virHostMemSetParameters(virTypedParameterPtr params ATTRIBUTE_UNUSED,
+ int nparams ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+#ifdef __linux__
+ size_t i;
+ int rc;
+
+ if (virTypedParamsValidate(params, nparams,
+ VIR_NODE_MEMORY_SHARED_PAGES_TO_SCAN,
+ VIR_TYPED_PARAM_UINT,
+ VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS,
+ VIR_TYPED_PARAM_UINT,
+ VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES,
+ VIR_TYPED_PARAM_UINT,
+ NULL) < 0)
+ return -1;
+
+ if (!virHostMemParametersAreAllSupported(params, nparams))
+ return -1;
+
+ for (i = 0; i < nparams; i++) {
+ rc = virHostMemSetParameterValue(¶ms[i]);
+
+ if (rc < 0)
+ return -1;
+ }
+
+ return 0;
+#else
+ virReportError(VIR_ERR_NO_SUPPORT, "%s",
+ _("node set memory parameters not implemented"
+ " on this platform"));
+ return -1;
+#endif
+}
+
+#ifdef __linux__
+static int
+virHostMemGetParameterValue(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)
+ goto cleanup;
+
+ if (!virFileExists(path)) {
+ ret = -2;
+ 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") ||
+ STREQ(field, "merge_across_nodes"))
+ 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;
+}
+#endif
+
+#define NODE_MEMORY_PARAMETERS_NUM 8
+int
+virHostMemGetParameters(virTypedParameterPtr params ATTRIBUTE_UNUSED,
+ int *nparams ATTRIBUTE_UNUSED,
+ unsigned int flags)
+{
+ virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
+
+#ifdef __linux__
+ unsigned int pages_to_scan;
+ unsigned int sleep_millisecs;
+ unsigned int merge_across_nodes;
+ 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;
+ size_t i;
+ int ret;
+
+ 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:
+ ret = virHostMemGetParameterValue("pages_to_scan",
&pages_to_scan);
+ if (ret == -2)
+ continue;
+ else if (ret == -1)
+ 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:
+ ret = virHostMemGetParameterValue("sleep_millisecs",
&sleep_millisecs);
+ if (ret == -2)
+ continue;
+ else if (ret == -1)
+ return -1;
+
+ if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_SLEEP_MILLISECS,
+ VIR_TYPED_PARAM_UINT, sleep_millisecs) < 0)
+ return -1;
+
+ break;
+
+ case 2:
+ ret = virHostMemGetParameterValue("pages_shared",
&pages_shared);
+ if (ret == -2)
+ continue;
+ else if (ret == -1)
+ return -1;
+
+ if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARED,
+ VIR_TYPED_PARAM_ULLONG, pages_shared) < 0)
+ return -1;
+
+ break;
+
+ case 3:
+ ret = virHostMemGetParameterValue("pages_sharing",
&pages_sharing);
+ if (ret == -2)
+ continue;
+ else if (ret == -1)
+ return -1;
+
+ if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_SHARING,
+ VIR_TYPED_PARAM_ULLONG, pages_sharing) < 0)
+ return -1;
+
+ break;
+
+ case 4:
+ ret = virHostMemGetParameterValue("pages_unshared",
&pages_unshared);
+ if (ret == -2)
+ continue;
+ else if (ret == -1)
+ return -1;
+
+ if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_UNSHARED,
+ VIR_TYPED_PARAM_ULLONG, pages_unshared) < 0)
+ return -1;
+
+ break;
+
+ case 5:
+ ret = virHostMemGetParameterValue("pages_volatile",
&pages_volatile);
+ if (ret == -2)
+ continue;
+ else if (ret == -1)
+ return -1;
+
+ if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_PAGES_VOLATILE,
+ VIR_TYPED_PARAM_ULLONG, pages_volatile) < 0)
+ return -1;
+
+ break;
+
+ case 6:
+ ret = virHostMemGetParameterValue("full_scans", &full_scans);
+ if (ret == -2)
+ continue;
+ else if (ret == -1)
+ return -1;
+
+ if (virTypedParameterAssign(param, VIR_NODE_MEMORY_SHARED_FULL_SCANS,
+ VIR_TYPED_PARAM_ULLONG, full_scans) < 0)
+ return -1;
+
+ break;
+
+ case 7:
+ ret = virHostMemGetParameterValue("merge_across_nodes",
&merge_across_nodes);
+ if (ret == -2)
+ continue;
+ else if (ret == -1)
+ return -1;
+
+ if (virTypedParameterAssign(param,
VIR_NODE_MEMORY_SHARED_MERGE_ACROSS_NODES,
+ VIR_TYPED_PARAM_UINT, merge_across_nodes) <
0)
+ return -1;
+
+ break;
+ }
+ }
+
+ return 0;
+#else
+ virReportError(VIR_ERR_NO_SUPPORT, "%s",
+ _("node get memory parameters not implemented"
+ " on this platform"));
+ return -1;
+#endif
+}
+
+
+static int
+virHostMemGetCellsFreeFake(unsigned long long *freeMems,
+ int startCell,
+ int maxCells ATTRIBUTE_UNUSED)
+{
+ double avail = physmem_available();
+
+ if (startCell != 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("start cell %d out of range (0-%d)"),
+ startCell, 0);
+ return -1;
+ }
+
+ freeMems[0] = (unsigned long long)avail;
+
+ if (!freeMems[0]) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot determine free memory"));
+ return -1;
+ }
+
+ return 1;
+}
+
+static int
+virHostMemGetInfoFake(unsigned long long *mem,
+ unsigned long long *freeMem)
+{
+ int ret = -1;
+
+#if defined(__FreeBSD__)
+ unsigned long pagesize = getpagesize();
+ u_int value;
+ size_t value_size = sizeof(value);
+
+ if (mem) {
+ if (sysctlbyname("vm.stats.vm.v_page_count", &value,
+ &value_size, NULL, 0) < 0) {
+ virReportSystemError(errno, "%s",
+ _("sysctl failed for
vm.stats.vm.v_page_count"));
+ goto cleanup;
+ }
+ *mem = value * (unsigned long long)pagesize;
+ }
+
+ if (freeMem) {
+ if (sysctlbyname("vm.stats.vm.v_free_count", &value,
+ &value_size, NULL, 0) < 0) {
+ virReportSystemError(errno, "%s",
+ _("sysctl failed for
vm.stats.vm.v_free_count"));
+ goto cleanup;
+ }
+
+ *freeMem = value * (unsigned long long)pagesize;
+ }
+
+#else
+ if (mem) {
+ double total = physmem_total();
+ if (!total) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot determine free memory"));
+ goto cleanup;
+ }
+
+ *mem = (unsigned long long) total;
+ }
+
+ if (freeMem) {
+ double avail = physmem_available();
+
+ if (!avail) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot determine free memory"));
+ goto cleanup;
+ }
+
+ *freeMem = (unsigned long long) avail;
+ }
+#endif
+
+ ret = 0;
+ cleanup:
+ return ret;
+}
+
+
+int
+virHostMemGetCellsFree(unsigned long long *freeMems,
+ int startCell,
+ int maxCells)
+{
+ unsigned long long mem;
+ int n, lastCell, numCells;
+ int ret = -1;
+ int maxCell;
+
+ if (!virNumaIsAvailable())
+ return virHostMemGetCellsFreeFake(freeMems,
+ startCell, maxCells);
+
+ if ((maxCell = virNumaGetMaxNode()) < 0)
+ return 0;
+
+ if (startCell > maxCell) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("start cell %d out of range (0-%d)"),
+ startCell, maxCell);
+ goto cleanup;
+ }
+ lastCell = startCell + maxCells - 1;
+ if (lastCell > maxCell)
+ lastCell = maxCell;
+
+ for (numCells = 0, n = startCell; n <= lastCell; n++) {
+ virNumaGetNodeMemory(n, NULL, &mem);
+
+ freeMems[numCells++] = mem;
+ }
+ ret = numCells;
+
+ cleanup:
+ return ret;
+}
+
+int
+virHostMemGetInfo(unsigned long long *mem,
+ unsigned long long *freeMem)
+{
+ int max_node;
+ int n;
+
+ if (mem)
+ *mem = 0;
+
+ if (freeMem)
+ *freeMem = 0;
+
+ if (!virNumaIsAvailable())
+ return virHostMemGetInfoFake(mem, freeMem);
+
+ if ((max_node = virNumaGetMaxNode()) < 0)
+ return -1;
+
+ for (n = 0; n <= max_node; n++) {
+ unsigned long long tmp_mem = 0, tmp_freeMem = 0;
+
+ if (!virNumaNodeIsAvailable(n))
+ continue;
+
+ if (virNumaGetNodeMemory(n, &tmp_mem, &tmp_freeMem) < 0)
+ return -1;
+
+ if (mem)
+ *mem += tmp_mem;
+
+ if (freeMem)
+ *freeMem += tmp_freeMem;
+ }
+
+ return 0;
+}
+
+int
+virHostMemGetFreePages(unsigned int npages,
+ unsigned int *pages,
+ int startCell,
+ unsigned int cellCount,
+ unsigned long long *counts)
+{
+ int ret = -1;
+ int cell, lastCell;
+ size_t i, ncounts = 0;
+
+ if ((lastCell = virNumaGetMaxNode()) < 0)
+ return 0;
+
+ if (startCell > lastCell) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("start cell %d out of range (0-%d)"),
+ startCell, lastCell);
+ goto cleanup;
+ }
+
+ lastCell = MIN(lastCell, startCell + (int) cellCount - 1);
+
+ for (cell = startCell; cell <= lastCell; cell++) {
+ for (i = 0; i < npages; i++) {
+ unsigned int page_size = pages[i];
+ unsigned int page_free;
+
+ if (virNumaGetPageInfo(cell, page_size, 0, NULL, &page_free) < 0)
+ goto cleanup;
+
+ counts[ncounts++] = page_free;
+ }
+ }
+
+ if (!ncounts) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("no suitable info found"));
+ goto cleanup;
+ }
+
+ ret = ncounts;
+ cleanup:
+ return ret;
+}
+
+int
+virHostMemAllocPages(unsigned int npages,
+ unsigned int *pageSizes,
+ unsigned long long *pageCounts,
+ int startCell,
+ unsigned int cellCount,
+ bool add)
+{
+ int ret = -1;
+ int cell, lastCell;
+ size_t i, ncounts = 0;
+
+ if ((lastCell = virNumaGetMaxNode()) < 0)
+ return 0;
+
+ if (startCell > lastCell) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("start cell %d out of range (0-%d)"),
+ startCell, lastCell);
+ goto cleanup;
+ }
+
+ lastCell = MIN(lastCell, startCell + (int) cellCount - 1);
+
+ for (cell = startCell; cell <= lastCell; cell++) {
+ for (i = 0; i < npages; i++) {
+ unsigned int page_size = pageSizes[i];
+ unsigned long long page_count = pageCounts[i];
+
+ if (virNumaSetPagePoolSize(cell, page_size, page_count, add) < 0)
+ goto cleanup;
+
+ ncounts++;
+ }
+ }
+
+ ret = ncounts;
+ cleanup:
+ return ret;
+}
diff --git a/src/util/virhostmem.h b/src/util/virhostmem.h
new file mode 100644
index 0000000..4008521
--- /dev/null
+++ b/src/util/virhostmem.h
@@ -0,0 +1,60 @@
+/*
+ * virhostmem.h: helper APIs for host memory info
+ *
+ * Copyright (C) 2006-2016 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#ifndef __VIR_HOSTMEM_H__
+# define __VIR_HOSTMEM_H__
+
+# include "internal.h"
+
+int virHostMemGetStats(int cellNum,
+ virNodeMemoryStatsPtr params,
+ int *nparams,
+ unsigned int flags);
+int virHostMemGetCellsFree(unsigned long long *freeMems,
+ int startCell,
+ int maxCells);
+int virHostMemGetInfo(unsigned long long *mem,
+ unsigned long long *freeMem);
+
+int virHostMemGetParameters(virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags);
+
+int virHostMemSetParameters(virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags);
+
+int virHostMemGetFreePages(unsigned int npages,
+ unsigned int *pages,
+ int startCell,
+ unsigned int cellCount,
+ unsigned long long *counts);
+
+int virHostMemAllocPages(unsigned int npages,
+ unsigned int *pageSizes,
+ unsigned long long *pageCounts,
+ int startCell,
+ unsigned int cellCount,
+ bool add);
+
+#endif /* __VIR_HOSTMEM_H__*/
diff --git a/src/util/virnuma.c b/src/util/virnuma.c
index 1e78eb6..23064ff 100644
--- a/src/util/virnuma.c
+++ b/src/util/virnuma.c
@@ -45,7 +45,7 @@
#include "virbitmap.h"
#include "virstring.h"
#include "virfile.h"
-#include "nodeinfo.h"
+#include "virhostmem.h"
#define VIR_FROM_THIS VIR_FROM_NONE
diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
index 603a071..a00977e 100644
--- a/src/vbox/vbox_common.c
+++ b/src/vbox/vbox_common.c
@@ -30,6 +30,7 @@
#include "virlog.h"
#include "viralloc.h"
#include "nodeinfo.h"
+#include "virhostmem.h"
#include "virstring.h"
#include "virfile.h"
#include "virtime.h"
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index 2196666..a218392 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -65,6 +65,7 @@
#include "vircommand.h"
#include "virnodesuspend.h"
#include "nodeinfo.h"
+#include "virhostmem.h"
#include "configmake.h"
#include "virstring.h"
#include "viraccessapicheck.h"
--
2.5.5