From: Philippe Waroquiers Date: Sat, 1 Nov 2014 21:02:13 +0000 (+0000) Subject: Fix 333051 mmap of huge pages fails due to incorrect alignment X-Git-Tag: svn/VALGRIND_3_11_0~866 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=41610f34c2b8dbed9064ca9000bab27457eaf01e;p=thirdparty%2Fvalgrind.git Fix 333051 mmap of huge pages fails due to incorrect alignment Learning aspacemgr to handle huge page is too difficult. So, huge page requests that fails due to bad advice by aspacemgr will (we hope) succeed if a mmap retry is done with the kernel, without any constraints. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14682 --- diff --git a/NEWS b/NEWS index fb15c0882f..418e9febb3 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,7 @@ To see details of a given bug, visit https://bugs.kde.org/show_bug.cgi?id=XXXXXX where XXXXXX is the bug number as listed below. +333051 mmap of huge pages fails due to incorrect alignment 335440 arm64: ld1 (single structure) is not implemented 335713 arm64: unhanded instruction: prfm (immediate) 338731 ppc: Fix testuite build for toolchains not supporting -maltivec diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c index 121b0644f0..0e5d21229f 100644 --- a/coregrind/m_syswrap/syswrap-generic.c +++ b/coregrind/m_syswrap/syswrap-generic.c @@ -2214,6 +2214,33 @@ ML_(generic_PRE_sys_mmap) ( ThreadId tid, arg5, arg6); } + /* Yet another refinement : sometimes valgrind chooses an address + which is not acceptable by the kernel. This at least happens + when mmap-ing huge pages, using the flag MAP_HUGETLB. + valgrind aspacem does not know about huge pages, and modifying + it to handle huge pages is not straightforward (e.g. need + to understand special file system mount options). + So, let's just redo an mmap, without giving any constraint to + the kernel. If that succeeds, check with aspacem that the returned + address is acceptable (i.e. is free). + This will give a similar effect as if the user would have + specified a MAP_FIXED at that address. + The aspacem state will be correctly updated afterwards. + We however cannot do this last refinement when the user asked + for a fixed mapping, as the user asked a specific address. */ + if (sr_isError(sres) && !(arg4 & VKI_MAP_FIXED)) { + advised = 0; + /* try mmap with NULL address and without VKI_MAP_FIXED + to let the kernel decide. */ + sres = VG_(am_do_mmap_NO_NOTIFY)(advised, arg2, arg3, + arg4, + arg5, arg6); + if (!sr_isError(sres)) { + vg_assert(VG_(am_covered_by_single_free_segment)((Addr)sr_Res(sres), + arg2)); + } + } + if (!sr_isError(sres)) { ULong di_handle; /* Notify aspacem. */ diff --git a/none/tests/map_unmap.c b/none/tests/map_unmap.c index c5dc490a77..e149c586c6 100644 --- a/none/tests/map_unmap.c +++ b/none/tests/map_unmap.c @@ -3,14 +3,50 @@ #include #include +/* The code testing MAP_HUGETLB huge pages is disabled by default, + as many distros do not have huge pages configured + by default. + To have e.g. 20 huge pages configured, do (as root) + echo 20 > /proc/sys/vm/nr_hugepages + Once this is done, uncomment the below, and recompile. +*/ +// #define TEST_MAP_HUGETLB 1 + +/* Similarly, testing SHM_HUGETLB huge pages is disabled by default. + To have shmget/shmat big pages working, do (as root) + echo 500 > /proc/sys/vm/hugetlb_shm_group + where 500 is the groupid of the user that runs this test + Once this is done, uncomment the below, and recompile. +*/ +// #define TEST_SHM_HUGETLB 1 + +#ifdef TEST_MAP_HUGETLB +#include +#include +#include + +/* Ensure this compiles on pre 2.6 systems, or on glibc missing MAP_HUGETLB */ +#ifndef MAP_HUGETLB +/* The below works for me on an f12/x86 linux */ +#define MAP_HUGETLB 0x40000 +#endif + +#endif /* TEST_MAP_HUGETLB */ + +#ifdef TEST_SHM_HUGETLB +#ifndef SHM_HUGETLB +#define SHM_HUGETLB 04000 +#endif +#endif /* TEST_SHM_HUGETLB */ + static unsigned int pagesize; #define PAGES 1024u #define LEN (PAGES*pagesize) -static void *domap(void) +static void *domap(size_t len, int addflags) { - void *ret = mmap(0, LEN, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + void *ret = mmap(0, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|addflags, -1, 0); if (ret == (void *)-1) { perror("mmap"); @@ -51,22 +87,22 @@ int main() pagesize = getpagesize(); - expect1 = domap(); - expect2 = domap(); + expect1 = domap(LEN, 0); + expect2 = domap(LEN, 0); munmap(expect1, LEN); munmap(expect2, LEN); for(i = 0; i < 5; i++) { void *m1, *m2; - m1 = domap(); + m1 = domap(LEN, 0); if (m1 != expect1) { printf("FAIL i=%d: m1=%p expect1=%p\n", i, m1, expect1); prmaps(); return 1; } - m2 = domap(); + m2 = domap(LEN, 0); if (m2 != expect2) { printf("FAIL i=%d: m2=%p expect2=%p\n", i, m2, expect2); @@ -76,7 +112,44 @@ int main() nibblemap(m2); munmap(m1, LEN); } - + +#ifdef TEST_MAP_HUGETLB +#define HUGESZ (4 * 1024 * 1024) + { + void *expect3; + expect3 = domap(HUGESZ, MAP_HUGETLB); + munmap(expect3, HUGESZ); + } +#endif + +#ifdef TEST_SHM_HUGETLB + { + int shmid; + void *expect4; + + + shmid = shmget(IPC_PRIVATE, HUGESZ, + IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | SHM_HUGETLB); + if (shmid == -1) { + perror("shmget"); + exit(1); + } + expect4 = shmat(shmid, NULL, 0); + if (expect4 == (void*) -1){ + perror("shmat"); + exit(1); + } + if (shmdt(expect4) != 0) { + perror("shmdt"); + exit(1); + } + if (shmctl(shmid, IPC_RMID, 0) != 0) { + perror("shmctl IPC_RMID"); + exit(1); + } + } +#endif + printf("PASS\n"); return 0; }