|
From: <sv...@va...> - 2014-11-01 21:02:22
|
Author: philippe
Date: Sat Nov 1 21:02:13 2014
New Revision: 14682
Log:
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.
Modified:
trunk/NEWS
trunk/coregrind/m_syswrap/syswrap-generic.c
trunk/none/tests/map_unmap.c
Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS (original)
+++ trunk/NEWS Sat Nov 1 21:02:13 2014
@@ -27,6 +27,7 @@
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
Modified: trunk/coregrind/m_syswrap/syswrap-generic.c
==============================================================================
--- trunk/coregrind/m_syswrap/syswrap-generic.c (original)
+++ trunk/coregrind/m_syswrap/syswrap-generic.c Sat Nov 1 21:02:13 2014
@@ -2214,6 +2214,33 @@
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. */
Modified: trunk/none/tests/map_unmap.c
==============================================================================
--- trunk/none/tests/map_unmap.c (original)
+++ trunk/none/tests/map_unmap.c Sat Nov 1 21:02:13 2014
@@ -3,14 +3,50 @@
#include <stdlib.h>
#include <unistd.h>
+/* 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 <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/stat.h>
+
+/* 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 @@
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 @@
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;
}
|