free_hugepage_region() is currently assuming that the region was backed
by hugepages. This may not be the case when GHP_FALLBACK is specified
and it was luck on the original test machines that the addresses
happened to work out. The test case also makes assumptions on alignment.

This patch makes free_huge_pages() an internal helper function called
__free_huge_pages() which can take aligned or unaligned addresses. When
it is told the address is unaligned, it'll check the mappings to see if
it was page or hugepage aligned before freeing. free_huge_pages() and
free_hugepage_region() only differ then on whether the addresses are
aligned or not.

Signed-off-by: Mel Gorman <[EMAIL PROTECTED]>
--- 
 alloc.c                     |   49 ++++++++++++++++++++++++++++--------------
 tests/get_hugepage_region.c |   14 ++++++++----
 2 files changed, 43 insertions(+), 20 deletions(-)

diff --git a/alloc.c b/alloc.c
index 6fb26c3..c357827 100644
--- a/alloc.c
+++ b/alloc.c
@@ -124,20 +124,12 @@ void *get_huge_pages(size_t len, ghp_t flags)
 }
 
 #define MAPS_BUF_SZ 4096
-/**
- * free_huge_pages - Free a region allocated that was backed by large pages
- * ptr - The pointer to the buffer returned by get_huge_pages()
- *
- * This function finds a region to free based on the contents of
- * /proc/pid/maps. The assumption is made that the ptr is the start of
- * a hugepage region allocated with free_huge_pages. No checking is made
- * that the pointer is to a hugepage backed region.
- */
-void free_huge_pages(void *ptr)
+static void __free_huge_pages(void *ptr, int aligned)
 {
        FILE *fd;
        char line[MAPS_BUF_SZ];
        unsigned long start = 0, end = 0;
+       unsigned long palign = 0, hpalign = 0;
 
        /*
         * /proc/self/maps is used to determine the length of the original
@@ -151,6 +143,15 @@ void free_huge_pages(void *ptr)
                return;
        }
 
+       /*
+        * An unaligned address allocated by get_hugepage_region()
+        * could be either page or hugepage aligned
+        */
+       if (!aligned) {
+               palign = ALIGN_DOWN((unsigned long)ptr, getpagesize());
+               hpalign = ALIGN_DOWN((unsigned long)ptr, gethugepagesize());
+       }
+
        /* Parse /proc/maps for address ranges line by line */
        while (!feof(fd)) {
                char *bufptr;
@@ -172,6 +173,13 @@ void free_huge_pages(void *ptr)
                        munmap(ptr, end - start);
                        break;
                }
+
+               /* Check the unaligned possibilities */
+               if (!aligned && (start == palign || start == hpalign)) {
+                       end = strtoull(bufptr, NULL, 16);
+                       munmap((void *)start, end - start);
+                       break;
+               }
        }
 
        /* Print a warning if the ptr appeared to point nowhere */
@@ -181,6 +189,20 @@ void free_huge_pages(void *ptr)
        fclose(fd);
 }
 
+/**
+ * free_huge_pages - Free a region allocated that was backed by large pages
+ * ptr - The pointer to the buffer returned by get_huge_pages()
+ *
+ * This function finds a region to free based on the contents of
+ * /proc/pid/maps. The assumption is made that the ptr is the start of
+ * a hugepage region allocated with free_huge_pages. No checking is made
+ * that the pointer is to a hugepage backed region.
+ */
+void free_huge_pages(void *ptr)
+{
+       __free_huge_pages(ptr, 1);
+}
+
 /*
  * Offset the buffer using bytes wasted due to alignment to avoid using the
  * same cache lines for the start of every buffer returned by
@@ -269,10 +291,5 @@ void *get_hugepage_region(size_t len, ghr_t flags)
  */
 void free_hugepage_region(void *ptr)
 {
-       /* Buffers may be offset for cache line coloring */
-       DEBUG("free_hugepage_region(%p) unaligned\n", ptr);
-       ptr = (void *)ALIGN_DOWN((unsigned long)ptr, gethugepagesize());
-       DEBUG("free_hugepage_region(%p) aligned\n", ptr);
-
-       free_huge_pages(ptr);
+       __free_huge_pages(ptr, 0);
 }
diff --git a/tests/get_hugepage_region.c b/tests/get_hugepage_region.c
index 81428e4..2fb5b23 100644
--- a/tests/get_hugepage_region.c
+++ b/tests/get_hugepage_region.c
@@ -43,6 +43,12 @@ void free_and_confirm_region_free(void *p, int line) {
                FAIL("free_hugepage_region did not free region at line %d", 
line);
 }
 
+int test_unaligned_addr_huge(void *p)
+{
+       p = (void *)((unsigned long)p & ~((gethugepagesize()) - 1));
+       return test_addr_huge(p);
+}
+
 #define TESTLEN ((num_hugepages - 1) * hpage_size + hpage_size / 2)
 
 void test_GHR_STRICT(int num_hugepages)
@@ -54,12 +60,12 @@ void test_GHR_STRICT(int num_hugepages)
 
        memset(p, 1, TESTLEN);
 
-       err = test_addr_huge(p + (num_hugepages - 1) * hpage_size);
+       err = test_unaligned_addr_huge(p + (num_hugepages - 1) * hpage_size);
        if (err != 1)
                FAIL("Returned page is not hugepage");
 
        free_and_confirm_region_free(p, __LINE__);
-       err = test_addr_huge(p);
+       err = test_unaligned_addr_huge(p);
        if (err == 1)
                FAIL("hugepage was not correctly freed");
 }
@@ -81,7 +87,7 @@ void test_GHR_FALLBACK(void)
                FAIL("test_GHR_FALLBACK(GHR_DEFAULT) failed for %ld hugepages",
                        num_hugepages);
        memset(p, 1, TESTLEN);
-       err = test_addr_huge(p + (num_hugepages - 1) * hpage_size);
+       err = test_unaligned_addr_huge(p + (num_hugepages - 1) * hpage_size);
        if (err != 1)
                FAIL("Returned page is not hugepage");
        free_and_confirm_region_free(p, __LINE__);
@@ -98,7 +104,7 @@ void test_GHR_FALLBACK(void)
                FAIL("test_GHR_FALLBACK(GHR_FALLBACK) failed for %ld hugepages",
                        num_hugepages);
        memset(p, 1, TESTLEN);
-       err = test_addr_huge(p + (num_hugepages - 1) * hpage_size);
+       err = test_unaligned_addr_huge(p + (num_hugepages - 1) * hpage_size);
        if (err == 1)
                FAIL("Returned page is not a base page");
 

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Libhugetlbfs-devel mailing list
Libhugetlbfs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel

Reply via email to