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