--- 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@xxxxxxxxxx> + */ + +#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@xxxxxxxxxx> + */ + +#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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list