]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Fix 333051 mmap of huge pages fails due to incorrect alignment
authorPhilippe Waroquiers <philippe.waroquiers@skynet.be>
Sat, 1 Nov 2014 21:02:13 +0000 (21:02 +0000)
committerPhilippe Waroquiers <philippe.waroquiers@skynet.be>
Sat, 1 Nov 2014 21:02:13 +0000 (21:02 +0000)
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

NEWS
coregrind/m_syswrap/syswrap-generic.c
none/tests/map_unmap.c

diff --git a/NEWS b/NEWS
index fb15c0882f5094fb9878917cbc7acc7562f4a151..418e9febb3e2c29fa746754ca721a6398ee97e9e 100644 (file)
--- 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
index 121b0644f0fed45949556c368a184ddf0349c1e0..0e5d21229f2422c86f99256c5949cf5c900af58f 100644 (file)
@@ -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. */
index c5dc490a7779ec6dfbfaf3ed4fcc8d66fb671c25..e149c586c6f0d41bb636222e8015f9058f1d52ad 100644 (file)
@@ -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 @@ 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;
 }