[libvirt] [PATCH 2/4] virnuma: Introduce virNumaSetPagePoolSize

Michal Privoznik mprivozn at redhat.com
Thu Sep 18 08:24:20 UTC 2014


This internal API can be used to allocate or free some pages in
the huge pages pool.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 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 51a692b..aabc11f 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1699,6 +1699,7 @@ virNumaGetPageInfo;
 virNumaGetPages;
 virNumaIsAvailable;
 virNumaNodeIsAvailable;
+virNumaSetPagePoolSize;
 virNumaSetupMemoryPolicy;
 
 
diff --git a/src/util/virnuma.c b/src/util/virnuma.c
index 1a34398..690615f 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 13ebec6..04b6b8c 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__ */
-- 
1.8.5.5




More information about the libvir-list mailing list