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. */
#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");
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);
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;
}