Blame SOURCES/libvirt-virNumaGetHugePageInfo-Return-page_avail-and-page_free-as-ULL.patch

4e77bf
From 0c98909e23aa8d3340b5752f2e774c9c966ff131 Mon Sep 17 00:00:00 2001
4e77bf
Message-Id: <0c98909e23aa8d3340b5752f2e774c9c966ff131@dist-git>
4e77bf
From: Michal Privoznik <mprivozn@redhat.com>
4e77bf
Date: Fri, 25 May 2018 14:44:04 +0200
4e77bf
Subject: [PATCH] virNumaGetHugePageInfo: Return page_avail and page_free as
4e77bf
 ULL
4e77bf
MIME-Version: 1.0
4e77bf
Content-Type: text/plain; charset=UTF-8
4e77bf
Content-Transfer-Encoding: 8bit
4e77bf
4e77bf
RHEL-7.6: https://bugzilla.redhat.com/show_bug.cgi?id=1569678
4e77bf
RHEL-7.5.z: https://bugzilla.redhat.com/show_bug.cgi?id=1582418
4e77bf
4e77bf
On some large systems (with ~400GB of RAM) it is possible for
4e77bf
unsigned int to overflow in which case we report invalid number
4e77bf
of 4K pages pool size. Switch to unsigned long long.
4e77bf
4e77bf
We hit overflow in virNumaGetPages when doing:
4e77bf
4e77bf
    huge_page_sum += 1024 * page_size * page_avail;
4e77bf
4e77bf
because although 'huge_page_sum' is an unsigned long long, the
4e77bf
page_size and page_avail are both unsigned int, so the promotion
4e77bf
to unsigned long long doesn't happen until the sum has been
4e77bf
calculated, by which time we've already overflowed.
4e77bf
4e77bf
Turning page_avail into a unsigned long long is not strictly
4e77bf
needed until we need ability to represent more than 2^32
4e77bf
4k pages, which equates to 16 TB of RAM. That's not
4e77bf
outside the realm of possibility, so makes sense that we
4e77bf
change it to unsigned long long to avoid future problems.
4e77bf
4e77bf
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
4e77bf
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
4e77bf
(cherry picked from commit 31daccf5a550e7ede35532004006b34ba5c5b92e)
4e77bf
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
4e77bf
---
4e77bf
 src/conf/capabilities.c |  5 +++--
4e77bf
 src/conf/capabilities.h |  2 +-
4e77bf
 src/util/virhostmem.c   |  2 +-
4e77bf
 src/util/virnuma.c      | 32 ++++++++++++++++++--------------
4e77bf
 src/util/virnuma.h      |  8 ++++----
4e77bf
 tests/virnumamock.c     |  4 ++--
4e77bf
 6 files changed, 29 insertions(+), 24 deletions(-)
4e77bf
4e77bf
diff --git a/src/conf/capabilities.c b/src/conf/capabilities.c
4e77bf
index edf9f54f77..66e2ecd151 100644
4e77bf
--- a/src/conf/capabilities.c
4e77bf
+++ b/src/conf/capabilities.c
4e77bf
@@ -819,7 +819,7 @@ virCapabilitiesFormatNUMATopology(virBufferPtr buf,
4e77bf
                               cells[i]->mem);
4e77bf
 
4e77bf
         for (j = 0; j < cells[i]->npageinfo; j++) {
4e77bf
-            virBufferAsprintf(buf, "<pages unit='KiB' size='%u'>%zu</pages>\n",
4e77bf
+            virBufferAsprintf(buf, "<pages unit='KiB' size='%u'>%llu</pages>\n",
4e77bf
                               cells[i]->pageinfo[j].size,
4e77bf
                               cells[i]->pageinfo[j].avail);
4e77bf
         }
4e77bf
@@ -1354,7 +1354,8 @@ virCapabilitiesGetNUMAPagesInfo(int node,
4e77bf
                                 int *npageinfo)
4e77bf
 {
4e77bf
     int ret = -1;
4e77bf
-    unsigned int *pages_size = NULL, *pages_avail = NULL;
4e77bf
+    unsigned int *pages_size = NULL;
4e77bf
+    unsigned long long *pages_avail = NULL;
4e77bf
     size_t npages, i;
4e77bf
 
4e77bf
     if (virNumaGetPages(node, &pages_size, &pages_avail, NULL, &npages) < 0)
4e77bf
diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
4e77bf
index 694a3590bf..f0a06a24df 100644
4e77bf
--- a/src/conf/capabilities.h
4e77bf
+++ b/src/conf/capabilities.h
4e77bf
@@ -107,7 +107,7 @@ typedef struct _virCapsHostNUMACellPageInfo virCapsHostNUMACellPageInfo;
4e77bf
 typedef virCapsHostNUMACellPageInfo *virCapsHostNUMACellPageInfoPtr;
4e77bf
 struct _virCapsHostNUMACellPageInfo {
4e77bf
     unsigned int size;      /* page size in kibibytes */
4e77bf
-    size_t avail;           /* the size of pool */
4e77bf
+    unsigned long long avail;           /* the size of pool */
4e77bf
 };
4e77bf
 
4e77bf
 typedef struct _virCapsHostNUMACell virCapsHostNUMACell;
4e77bf
diff --git a/src/util/virhostmem.c b/src/util/virhostmem.c
4e77bf
index a9ba2784ac..a795720954 100644
4e77bf
--- a/src/util/virhostmem.c
4e77bf
+++ b/src/util/virhostmem.c
4e77bf
@@ -775,7 +775,7 @@ virHostMemGetFreePages(unsigned int npages,
4e77bf
     for (cell = startCell; cell <= lastCell; cell++) {
4e77bf
         for (i = 0; i < npages; i++) {
4e77bf
             unsigned int page_size = pages[i];
4e77bf
-            unsigned int page_free;
4e77bf
+            unsigned long long page_free;
4e77bf
 
4e77bf
             if (virNumaGetPageInfo(cell, page_size, 0, NULL, &page_free) < 0)
4e77bf
                 goto cleanup;
4e77bf
diff --git a/src/util/virnuma.c b/src/util/virnuma.c
4e77bf
index bebe301f8d..784db0a7ce 100644
4e77bf
--- a/src/util/virnuma.c
4e77bf
+++ b/src/util/virnuma.c
4e77bf
@@ -563,8 +563,8 @@ virNumaGetHugePageInfoDir(char **path, int node)
4e77bf
 static int
4e77bf
 virNumaGetHugePageInfo(int node,
4e77bf
                        unsigned int page_size,
4e77bf
-                       unsigned int *page_avail,
4e77bf
-                       unsigned int *page_free)
4e77bf
+                       unsigned long long *page_avail,
4e77bf
+                       unsigned long long *page_free)
4e77bf
 {
4e77bf
     int ret = -1;
4e77bf
     char *path = NULL;
4e77bf
@@ -579,7 +579,7 @@ virNumaGetHugePageInfo(int node,
4e77bf
         if (virFileReadAll(path, 1024, &buf) < 0)
4e77bf
             goto cleanup;
4e77bf
 
4e77bf
-        if (virStrToLong_ui(buf, &end, 10, page_avail) < 0 ||
4e77bf
+        if (virStrToLong_ull(buf, &end, 10, page_avail) < 0 ||
4e77bf
             *end != '\n') {
4e77bf
             virReportError(VIR_ERR_INTERNAL_ERROR,
4e77bf
                            _("unable to parse: %s"),
4e77bf
@@ -598,7 +598,7 @@ virNumaGetHugePageInfo(int node,
4e77bf
         if (virFileReadAll(path, 1024, &buf) < 0)
4e77bf
             goto cleanup;
4e77bf
 
4e77bf
-        if (virStrToLong_ui(buf, &end, 10, page_free) < 0 ||
4e77bf
+        if (virStrToLong_ull(buf, &end, 10, page_free) < 0 ||
4e77bf
             *end != '\n') {
4e77bf
             virReportError(VIR_ERR_INTERNAL_ERROR,
4e77bf
                            _("unable to parse: %s"),
4e77bf
@@ -645,8 +645,8 @@ int
4e77bf
 virNumaGetPageInfo(int node,
4e77bf
                    unsigned int page_size,
4e77bf
                    unsigned long long huge_page_sum,
4e77bf
-                   unsigned int *page_avail,
4e77bf
-                   unsigned int *page_free)
4e77bf
+                   unsigned long long *page_avail,
4e77bf
+                   unsigned long long *page_free)
4e77bf
 {
4e77bf
     int ret = -1;
4e77bf
     long system_page_size = virGetSystemPageSize();
4e77bf
@@ -709,8 +709,8 @@ virNumaGetPageInfo(int node,
4e77bf
 int
4e77bf
 virNumaGetPages(int node,
4e77bf
                 unsigned int **pages_size,
4e77bf
-                unsigned int **pages_avail,
4e77bf
-                unsigned int **pages_free,
4e77bf
+                unsigned long long **pages_avail,
4e77bf
+                unsigned long long **pages_free,
4e77bf
                 size_t *npages)
4e77bf
 {
4e77bf
     int ret = -1;
4e77bf
@@ -718,7 +718,9 @@ virNumaGetPages(int node,
4e77bf
     DIR *dir = NULL;
4e77bf
     int direrr = 0;
4e77bf
     struct dirent *entry;
4e77bf
-    unsigned int *tmp_size = NULL, *tmp_avail = NULL, *tmp_free = NULL;
4e77bf
+    unsigned int *tmp_size = NULL;
4e77bf
+    unsigned long long *tmp_avail = NULL;
4e77bf
+    unsigned long long *tmp_free = NULL;
4e77bf
     unsigned int ntmp = 0;
4e77bf
     size_t i;
4e77bf
     bool exchange;
4e77bf
@@ -744,7 +746,9 @@ virNumaGetPages(int node,
4e77bf
 
4e77bf
     while (dir && (direrr = virDirRead(dir, &entry, path)) > 0) {
4e77bf
         const char *page_name = entry->d_name;
4e77bf
-        unsigned int page_size, page_avail = 0, page_free = 0;
4e77bf
+        unsigned int page_size;
4e77bf
+        unsigned long long page_avail = 0;
4e77bf
+        unsigned long long page_free = 0;
4e77bf
         char *end;
4e77bf
 
4e77bf
         /* Just to give you a hint, we're dealing with this:
4e77bf
@@ -934,8 +938,8 @@ int
4e77bf
 virNumaGetPageInfo(int node ATTRIBUTE_UNUSED,
4e77bf
                    unsigned int page_size ATTRIBUTE_UNUSED,
4e77bf
                    unsigned long long huge_page_sum ATTRIBUTE_UNUSED,
4e77bf
-                   unsigned int *page_avail ATTRIBUTE_UNUSED,
4e77bf
-                   unsigned int *page_free ATTRIBUTE_UNUSED)
4e77bf
+                   unsigned long long *page_avail ATTRIBUTE_UNUSED,
4e77bf
+                   unsigned long long *page_free ATTRIBUTE_UNUSED)
4e77bf
 {
4e77bf
     virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4e77bf
                    _("page info is not supported on this platform"));
4e77bf
@@ -946,8 +950,8 @@ virNumaGetPageInfo(int node ATTRIBUTE_UNUSED,
4e77bf
 int
4e77bf
 virNumaGetPages(int node ATTRIBUTE_UNUSED,
4e77bf
                 unsigned int **pages_size ATTRIBUTE_UNUSED,
4e77bf
-                unsigned int **pages_avail ATTRIBUTE_UNUSED,
4e77bf
-                unsigned int **pages_free ATTRIBUTE_UNUSED,
4e77bf
+                unsigned long long **pages_avail ATTRIBUTE_UNUSED,
4e77bf
+                unsigned long long **pages_free ATTRIBUTE_UNUSED,
4e77bf
                 size_t *npages ATTRIBUTE_UNUSED)
4e77bf
 {
4e77bf
     virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4e77bf
diff --git a/src/util/virnuma.h b/src/util/virnuma.h
4e77bf
index e4e1fd0b97..a3ffb6d6c7 100644
4e77bf
--- a/src/util/virnuma.h
4e77bf
+++ b/src/util/virnuma.h
4e77bf
@@ -52,12 +52,12 @@ int virNumaGetNodeCPUs(int node, virBitmapPtr *cpus) ATTRIBUTE_NOINLINE;
4e77bf
 int virNumaGetPageInfo(int node,
4e77bf
                        unsigned int page_size,
4e77bf
                        unsigned long long huge_page_sum,
4e77bf
-                       unsigned int *page_avail,
4e77bf
-                       unsigned int *page_free);
4e77bf
+                       unsigned long long *page_avail,
4e77bf
+                       unsigned long long *page_free);
4e77bf
 int virNumaGetPages(int node,
4e77bf
                     unsigned int **pages_size,
4e77bf
-                    unsigned int **pages_avail,
4e77bf
-                    unsigned int **pages_free,
4e77bf
+                    unsigned long long **pages_avail,
4e77bf
+                    unsigned long long **pages_free,
4e77bf
                     size_t *npages)
4e77bf
     ATTRIBUTE_NONNULL(5) ATTRIBUTE_NOINLINE;
4e77bf
 int virNumaSetPagePoolSize(int node,
4e77bf
diff --git a/tests/virnumamock.c b/tests/virnumamock.c
4e77bf
index d8f90b81b3..475efc1f34 100644
4e77bf
--- a/tests/virnumamock.c
4e77bf
+++ b/tests/virnumamock.c
4e77bf
@@ -125,8 +125,8 @@ virNumaGetDistances(int node ATTRIBUTE_UNUSED,
4e77bf
 int
4e77bf
 virNumaGetPages(int node,
4e77bf
                 unsigned int **pages_size,
4e77bf
-                unsigned int **pages_avail,
4e77bf
-                unsigned int **pages_free,
4e77bf
+                unsigned long long **pages_avail,
4e77bf
+                unsigned long long **pages_free,
4e77bf
                 size_t *npages)
4e77bf
 {
4e77bf
     const int pages_def[] = { 4, 2 * 1024, 1 * 1024 * 1024};
4e77bf
-- 
4e77bf
2.17.1
4e77bf