From d1fd4a9b3ba5f8c0edb24742e2d1fcf20a7c7737 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Thu, 18 Sep 2014 09:24:16 +0200 Subject: [PATCH] virnuma: Introduce virNumaSetPagePoolSize This internal API can be used to allocate or free some pages in the huge pages pool. Signed-off-by: Michal Privoznik --- src/libvirt_private.syms | 1 + src/util/virnuma.c | 108 +++++++++++++++++++++++++++++++++++++++ src/util/virnuma.h | 4 ++ 3 files changed, 113 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d648ed3982..6657d3d42e 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1719,6 +1719,7 @@ virNumaGetPageInfo; virNumaGetPages; virNumaIsAvailable; virNumaNodeIsAvailable; +virNumaSetPagePoolSize; virNumaSetupMemoryPolicy; diff --git a/src/util/virnuma.c b/src/util/virnuma.c index 1a3439807e..690615f2e1 100644 --- a/src/util/virnuma.c +++ b/src/util/virnuma.c @@ -841,6 +841,102 @@ virNumaGetPages(int node, } +int +virNumaSetPagePoolSize(int node, + unsigned int page_size, + unsigned long long page_count, + bool add) +{ + int ret = -1; + char *nr_path = NULL, *nr_buf = NULL; + char *end; + unsigned long long nr_count; + + if (page_size == sysconf(_SC_PAGESIZE) / 1024) { + /* Special case as kernel handles system pages + * differently to huge pages. */ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("system pages pool can't be modified")); + goto cleanup; + } + + if (virNumaGetHugePageInfoPath(&nr_path, node, page_size, "nr_hugepages") < 0) + goto cleanup; + + /* Firstly check, if there's anything for us to do */ + if (virFileReadAll(nr_path, 1024, &nr_buf) < 0) + goto cleanup; + + if (virStrToLong_ull(nr_buf, &end, 10, &nr_count) < 0 || + *end != '\n') { + virReportError(VIR_ERR_OPERATION_FAILED, + _("invalid number '%s' in '%s'"), + nr_buf, nr_path); + goto cleanup; + } + + if (add) { + if (!page_count) { + VIR_DEBUG("Nothing left to do: add = true page_count = 0"); + ret = 0; + goto cleanup; + } + page_count += nr_count; + } else { + if (nr_count == page_count) { + VIR_DEBUG("Nothing left to do: nr_count = page_count = %llu", + page_count); + ret = 0; + goto cleanup; + } + } + + /* Okay, page pool adjustment must be done in two steps. In + * first we write the desired number into nr_hugepages file. + * Kernel then starts to allocate the pages (return from + * write should be postponed until the kernel is finished). + * However, kernel may have not been successful and reserved + * all the pages we wanted. So do the second read to check. + */ + VIR_FREE(nr_buf); + if (virAsprintf(&nr_buf, "%llu", page_count) < 0) + goto cleanup; + + if (virFileWriteStr(nr_path, nr_buf, 0) < 0) { + virReportSystemError(errno, + _("Unable to write to: %s"), nr_path); + goto cleanup; + } + + /* And now do the check. */ + + VIR_FREE(nr_buf); + if (virFileReadAll(nr_path, 1024, &nr_buf) < 0) + goto cleanup; + + if (virStrToLong_ull(nr_buf, &end, 10, &nr_count) < 0 || + *end != '\n') { + virReportError(VIR_ERR_OPERATION_FAILED, + _("invalid number '%s' in '%s'"), + nr_buf, nr_path); + goto cleanup; + } + + if (nr_count != page_count) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Unable to allocate %llu pages. Allocated only %llu"), + page_count, nr_count); + goto cleanup; + } + + ret = 0; + cleanup: + VIR_FREE(nr_buf); + VIR_FREE(nr_path); + return ret; +} + + #else /* #ifdef __linux__ */ int virNumaGetPageInfo(int node ATTRIBUTE_UNUSED, @@ -866,4 +962,16 @@ virNumaGetPages(int node ATTRIBUTE_UNUSED, _("page info is not supported on this platform")); return -1; } + + +int +virNumaSetPagePoolSize(int node ATTRIBUTE_UNUSED, + unsigned int page_size ATTRIBUTE_UNUSED, + unsigned long long page_count ATTRIBUTE_UNUSED, + bool add ATTRIBUTE_UNUSED) +{ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("page pool allocation is not supported on this platform")); + return -1; +} #endif /* #ifdef __linux__ */ diff --git a/src/util/virnuma.h b/src/util/virnuma.h index 13ebec6273..04b6b8c6ec 100644 --- a/src/util/virnuma.h +++ b/src/util/virnuma.h @@ -59,4 +59,8 @@ int virNumaGetPages(int node, unsigned int **pages_free, size_t *npages) ATTRIBUTE_NONNULL(5); +int virNumaSetPagePoolSize(int node, + unsigned int page_size, + unsigned long long page_count, + bool add); #endif /* __VIR_NUMA_H__ */ -- GitLab