mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
nodeinfo: move host memory APIs out into virhostmem file
Move all APIs with a virHostMEM name prefix out into new util/virhostmem.h & util/virhostmem.c files Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
eaf18f4c2b
commit
86dd9fac0f
@ -198,6 +198,7 @@ src/util/virhash.c
|
|||||||
src/util/virhook.c
|
src/util/virhook.c
|
||||||
src/util/virhostcpu.c
|
src/util/virhostcpu.c
|
||||||
src/util/virhostdev.c
|
src/util/virhostdev.c
|
||||||
|
src/util/virhostmem.c
|
||||||
src/util/viridentity.c
|
src/util/viridentity.c
|
||||||
src/util/virinitctl.c
|
src/util/virinitctl.c
|
||||||
src/util/viriptables.c
|
src/util/viriptables.c
|
||||||
|
@ -121,6 +121,7 @@ UTIL_SOURCES = \
|
|||||||
util/virhook.c util/virhook.h \
|
util/virhook.c util/virhook.h \
|
||||||
util/virhostcpu.c util/virhostcpu.h util/virhostcpupriv.h \
|
util/virhostcpu.c util/virhostcpu.h util/virhostcpupriv.h \
|
||||||
util/virhostdev.c util/virhostdev.h \
|
util/virhostdev.c util/virhostdev.h \
|
||||||
|
util/virhostmem.c util/virhostmem.h \
|
||||||
util/viridentity.c util/viridentity.h \
|
util/viridentity.c util/viridentity.h \
|
||||||
util/virinitctl.c util/virinitctl.h \
|
util/virinitctl.c util/virinitctl.h \
|
||||||
util/viriptables.c util/viriptables.h \
|
util/viriptables.c util/viriptables.h \
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
#include "virnetdevopenvswitch.h"
|
#include "virnetdevopenvswitch.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
#include "virhostcpu.h"
|
#include "virhostcpu.h"
|
||||||
|
#include "virhostmem.h"
|
||||||
#include "viruuid.h"
|
#include "viruuid.h"
|
||||||
#include "virstats.h"
|
#include "virstats.h"
|
||||||
#include "virhook.h"
|
#include "virhook.h"
|
||||||
|
784
src/nodeinfo.c
784
src/nodeinfo.c
@ -28,27 +28,16 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include "conf/domain_conf.h"
|
#include "conf/domain_conf.h"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <unistd.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 "viralloc.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
#include "virhostcpu.h"
|
#include "virhostcpu.h"
|
||||||
|
#include "virhostmem.h"
|
||||||
#include "physmem.h"
|
#include "physmem.h"
|
||||||
#include "virerror.h"
|
#include "virerror.h"
|
||||||
#include "count-one-bits.h"
|
#include "count-one-bits.h"
|
||||||
@ -65,92 +54,11 @@
|
|||||||
VIR_LOG_INIT("nodeinfo");
|
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__
|
#ifdef __linux__
|
||||||
# define SYSFS_SYSTEM_PATH "/sys/devices/system"
|
# 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 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
|
/* Return the positive decimal contents of the given
|
||||||
* DIR/cpu%u/FILE, or -1 on error. If DEFAULT_VALUE is non-negative
|
* 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
|
static virBitmapPtr
|
||||||
virNodeGetSiblingsListLinux(const char *dir, int cpu_id)
|
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
|
static int
|
||||||
nodeCapsInitNUMAFake(const char *cpupath ATTRIBUTE_UNUSED,
|
nodeCapsInitNUMAFake(const char *cpupath ATTRIBUTE_UNUSED,
|
||||||
virCapsPtr caps ATTRIBUTE_UNUSED)
|
virCapsPtr caps ATTRIBUTE_UNUSED)
|
||||||
@ -780,64 +220,6 @@ nodeCapsInitNUMAFake(const char *cpupath ATTRIBUTE_UNUSED,
|
|||||||
return -1;
|
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 (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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
cleanup:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* returns 1 on success, 0 if the detection failed and -1 on hard error */
|
/* returns 1 on success, 0 if the detection failed and -1 on hard error */
|
||||||
static int
|
static int
|
||||||
@ -1032,167 +414,3 @@ nodeCapsInitNUMA(virCapsPtr caps)
|
|||||||
VIR_FREE(pageinfo);
|
VIR_FREE(pageinfo);
|
||||||
return ret;
|
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;
|
|
||||||
}
|
|
||||||
|
@ -29,35 +29,4 @@
|
|||||||
int nodeGetInfo(virNodeInfoPtr nodeinfo);
|
int nodeGetInfo(virNodeInfoPtr nodeinfo);
|
||||||
int nodeCapsInitNUMA(virCapsPtr caps);
|
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__*/
|
#endif /* __VIR_NODEINFO_H__*/
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#include "openvz_conf.h"
|
#include "openvz_conf.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
#include "virhostcpu.h"
|
#include "virhostcpu.h"
|
||||||
|
#include "virhostmem.h"
|
||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
#include "virfile.h"
|
#include "virfile.h"
|
||||||
#include "virtypedparam.h"
|
#include "virtypedparam.h"
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
#include "virbuffer.h"
|
#include "virbuffer.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
#include "virhostcpu.h"
|
#include "virhostcpu.h"
|
||||||
|
#include "virhostmem.h"
|
||||||
#include "virstats.h"
|
#include "virstats.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "virbuffer.h"
|
#include "virbuffer.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
#include "virhostcpu.h"
|
#include "virhostcpu.h"
|
||||||
|
#include "virhostmem.h"
|
||||||
#include "virstats.h"
|
#include "virstats.h"
|
||||||
#include "capabilities.h"
|
#include "capabilities.h"
|
||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
|
837
src/util/virhostmem.c
Normal file
837
src/util/virhostmem.c
Normal file
@ -0,0 +1,837 @@
|
|||||||
|
/*
|
||||||
|
* 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@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 (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
60
src/util/virhostmem.h
Normal file
60
src/util/virhostmem.h
Normal file
@ -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@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__*/
|
@ -45,7 +45,7 @@
|
|||||||
#include "virbitmap.h"
|
#include "virbitmap.h"
|
||||||
#include "virstring.h"
|
#include "virstring.h"
|
||||||
#include "virfile.h"
|
#include "virfile.h"
|
||||||
#include "nodeinfo.h"
|
#include "virhostmem.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "virlog.h"
|
#include "virlog.h"
|
||||||
#include "viralloc.h"
|
#include "viralloc.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
|
#include "virhostmem.h"
|
||||||
#include "virstring.h"
|
#include "virstring.h"
|
||||||
#include "virfile.h"
|
#include "virfile.h"
|
||||||
#include "virtime.h"
|
#include "virtime.h"
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
#include "vircommand.h"
|
#include "vircommand.h"
|
||||||
#include "virnodesuspend.h"
|
#include "virnodesuspend.h"
|
||||||
#include "nodeinfo.h"
|
#include "nodeinfo.h"
|
||||||
|
#include "virhostmem.h"
|
||||||
#include "configmake.h"
|
#include "configmake.h"
|
||||||
#include "virstring.h"
|
#include "virstring.h"
|
||||||
#include "viraccessapicheck.h"
|
#include "viraccessapicheck.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user