Current powerpc kernels have a bug, where due to bugs in the powerpc
version of hugetlb_get_unmapped_area(), 32-bit mmap()s which attempt
to create a mapping extending past TASK_SIZE (4GB) can cause a BUG()
to be triggered.  This patch adds a testcase for this bug.

Signed-off-by: David Gibson <[EMAIL PROTECTED]>

Index: libhugetlbfs/tests/Makefile
===================================================================
--- libhugetlbfs.orig/tests/Makefile    2006-12-21 13:34:01.000000000 +1100
+++ libhugetlbfs/tests/Makefile 2006-12-21 13:34:19.000000000 +1100
@@ -6,7 +6,7 @@ LIB_TESTS = gethugepagesize test_root fi
        chunk-overcommit mprotect alloc-instantiate-race mlock \
        truncate_reserve_wraparound truncate_sigbus_versus_oom \
        map_high_truncate_2 truncate_above_4GB \
-       misaligned_offset brk_near_huge
+       misaligned_offset brk_near_huge task-size-overrun
 LIB_TESTS_64 = straddle_4GB huge_at_4GB_normal_below \
        huge_below_4GB_normal_above
 NOLIB_TESTS = malloc malloc_manysmall dummy
Index: libhugetlbfs/tests/run_tests.sh
===================================================================
--- libhugetlbfs.orig/tests/run_tests.sh        2006-12-21 14:22:36.000000000 
+1100
+++ libhugetlbfs/tests/run_tests.sh     2006-12-21 14:24:16.000000000 +1100
@@ -142,6 +142,7 @@ functional_tests () {
     run_test misaligned_offset
     run_test truncate_above_4GB
     run_test brk_near_huge
+    run_test task-size-overrun
 
 # Tests requiring an active mount and hugepage COW
     run_test private
Index: libhugetlbfs/tests/task-size-overrun.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ libhugetlbfs/tests/task-size-overrun.c      2006-12-21 14:38:58.000000000 
+1100
@@ -0,0 +1,140 @@
+/*
+ * libhugetlbfs - Easy use of Linux hugepages
+ * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <hugetlbfs.h>
+
+#include "hugetests.h"
+
+#define MAPS_BUF_SZ 4096
+
+static int endswith(const char *buf, const char *tail)
+{
+       const char *p = buf + strlen(buf) - strlen(tail);
+
+       return strcmp(p, tail) == 0;
+}
+
+static unsigned long find_end_stack(void)
+{
+       FILE *f;
+       char line[MAPS_BUF_SZ];
+       char *tmp;
+       unsigned long start, end, off, ino;
+       int ret;
+
+       f = fopen("/proc/self/maps", "r");
+       if (!f) {
+               ERROR("Failed to open /proc/self/maps\n");
+               return -1;
+       }
+
+       do {
+               tmp = fgets(line, MAPS_BUF_SZ, f);
+               if (!tmp)
+                       FAIL("Couldn't find maps line for stack");
+       } while (! endswith(line, "[stack]\n"));
+
+       fclose(f);
+
+       verbose_printf("Stack map: %s", line);
+       ret = sscanf(line, "%lx-%lx %*s %lx %*s %ld %*s", &start, &end, &off, 
&ino);
+       if (ret != 4)
+               FAIL("Couldn't parse /proc/self/maps line: %s\n", line);
+
+       verbose_printf("Stack mapped at 0x%lx-0x%lx\n", start, end);
+       return end;
+}
+
+static unsigned long find_task_size(void)
+{
+       unsigned long addr;
+       void *p;
+
+       addr = find_end_stack();
+       if (!addr || ((addr % getpagesize()) != 0))
+               FAIL("Bogus stack end address, 0x%lx!?", addr);
+
+       while (addr) {
+               p = mmap64((void *)addr, getpagesize(), PROT_READ,
+                          MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
+               if (p == MAP_FAILED) {
+                       verbose_printf("Searching map failed: %s\n", 
strerror(errno));
+                       return addr;
+               }
+               munmap(p, getpagesize());
+               addr += getpagesize();
+       }
+       /* addr wrapped around */
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       int hpage_size;
+       int fd;
+       void *p;
+       unsigned long task_size;
+       unsigned long straddle_addr;
+
+       test_init(argc, argv);
+
+       task_size = find_task_size();
+
+       verbose_printf("TASK_SIZE = 0x%lx\n", task_size);
+
+       hpage_size = gethugepagesize();
+       if (hpage_size < 0)
+               CONFIG("No hugepage kernel support");
+
+       fd = hugetlbfs_unlinked_fd();
+       if (fd < 0)
+               FAIL("hugetlbfs_unlinked_fd()");
+
+       straddle_addr = task_size - hpage_size;
+       straddle_addr = ALIGN(straddle_addr, hpage_size);
+
+       /* We first try to get the mapping without MAP_FIXED */
+       verbose_printf("Mapping without MAP_FIXED at %lx...", straddle_addr);
+       errno = 0;
+       p = mmap((void *)straddle_addr, 2*hpage_size, PROT_READ|PROT_WRITE,
+                MAP_SHARED, fd, 0);
+       verbose_printf("%s\n", strerror(errno));
+       if (p == (void *)straddle_addr)
+               FAIL("Apparently suceeded in mapping across TASK_SIZE 
boundary");
+
+       verbose_printf("Mapping with MAP_FIXED at %lx...", straddle_addr);
+       errno = 0;
+       p = mmap((void *)straddle_addr, 2*hpage_size, PROT_READ|PROT_WRITE,
+                MAP_SHARED|MAP_FIXED, fd, 0);
+       verbose_printf("%s\n", strerror(errno));
+       if (p != MAP_FAILED)
+               FAIL("Apparently suceeded in mapping across TASK_SIZE 
boundary");
+
+       PASS();
+}


-- 
David Gibson                    | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
                                | _way_ _around_!
http://www.ozlabs.org/~dgibson

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Libhugetlbfs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel

Reply via email to