Merge branch 'akpm' (patches from Andrew)

Merge updates from Andrew Morton:

 - misc fixes

 - ocfs2 updates

 - most of MM

* emailed patches from Andrew Morton <akpm@linux-foundation.org>: (118 commits)
  mm: remove PG_highmem description
  tools, vm: new option to specify kpageflags file
  mm/swap.c: make functions and their kernel-doc agree
  mm, memory_hotplug: fix memmap initialization
  mm: correct comments regarding do_fault_around()
  mm: numa: do not trap faults on shared data section pages.
  hugetlb, mbind: fall back to default policy if vma is NULL
  hugetlb, mempolicy: fix the mbind hugetlb migration
  mm, hugetlb: further simplify hugetlb allocation API
  mm, hugetlb: get rid of surplus page accounting tricks
  mm, hugetlb: do not rely on overcommit limit during migration
  mm, hugetlb: integrate giga hugetlb more naturally to the allocation path
  mm, hugetlb: unify core page allocation accounting and initialization
  mm/memcontrol.c: try harder to decrease [memory,memsw].limit_in_bytes
  mm/memcontrol.c: make local symbol static
  mm/hmm: fix uninitialized use of 'entry' in hmm_vma_walk_pmd()
  include/linux/mmzone.h: fix explanation of lower bits in the SPARSEMEM mem_map pointer
  mm/compaction.c: fix comment for try_to_compact_pages()
  mm/page_ext.c: make page_ext_init a noop when CONFIG_PAGE_EXTENSION but nothing uses it
  zsmalloc: use U suffix for negative literals being shifted
  ...
This commit is contained in:
Linus Torvalds 2018-01-31 18:46:22 -08:00
commit 73da9e1a9f
118 changed files with 2607 additions and 1863 deletions

View file

@ -12,3 +12,8 @@ fuse_mnt.o: CFLAGS += $(shell pkg-config fuse --cflags)
include ../lib.mk
$(OUTPUT)/fuse_mnt: LDLIBS += $(shell pkg-config fuse --libs)
$(OUTPUT)/memfd_test: memfd_test.c common.o
$(OUTPUT)/fuse_test: fuse_test.c common.o
EXTRA_CLEAN = common.o

View file

@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#define __EXPORTED_HEADERS__
#include <stdio.h>
#include <stdlib.h>
#include <linux/fcntl.h>
#include <linux/memfd.h>
#include <unistd.h>
#include <sys/syscall.h>
#include "common.h"
int hugetlbfs_test = 0;
/*
* Copied from mlock2-tests.c
*/
unsigned long default_huge_page_size(void)
{
unsigned long hps = 0;
char *line = NULL;
size_t linelen = 0;
FILE *f = fopen("/proc/meminfo", "r");
if (!f)
return 0;
while (getline(&line, &linelen, f) > 0) {
if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
hps <<= 10;
break;
}
}
free(line);
fclose(f);
return hps;
}
int sys_memfd_create(const char *name, unsigned int flags)
{
if (hugetlbfs_test)
flags |= MFD_HUGETLB;
return syscall(__NR_memfd_create, name, flags);
}

View file

@ -0,0 +1,9 @@
#ifndef COMMON_H_
#define COMMON_H_
extern int hugetlbfs_test;
unsigned long default_huge_page_size(void);
int sys_memfd_create(const char *name, unsigned int flags);
#endif

View file

@ -33,14 +33,12 @@
#include <sys/wait.h>
#include <unistd.h>
#include "common.h"
#define MFD_DEF_SIZE 8192
#define STACK_SIZE 65536
static int sys_memfd_create(const char *name,
unsigned int flags)
{
return syscall(__NR_memfd_create, name, flags);
}
static size_t mfd_def_size = MFD_DEF_SIZE;
static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
{
@ -127,7 +125,7 @@ static void *mfd_assert_mmap_shared(int fd)
void *p;
p = mmap(NULL,
MFD_DEF_SIZE,
mfd_def_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
@ -145,7 +143,7 @@ static void *mfd_assert_mmap_private(int fd)
void *p;
p = mmap(NULL,
MFD_DEF_SIZE,
mfd_def_size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE,
fd,
@ -178,7 +176,7 @@ static int sealing_thread_fn(void *arg)
usleep(200000);
/* unmount mapping before sealing to avoid i_mmap_writable failures */
munmap(global_p, MFD_DEF_SIZE);
munmap(global_p, mfd_def_size);
/* Try sealing the global file; expect EBUSY or success. Current
* kernels will never succeed, but in the future, kernels might
@ -228,7 +226,7 @@ static void join_sealing_thread(pid_t pid)
int main(int argc, char **argv)
{
static const char zero[MFD_DEF_SIZE];
char *zero;
int fd, mfd, r;
void *p;
int was_sealed;
@ -239,6 +237,25 @@ int main(int argc, char **argv)
abort();
}
if (argc >= 3) {
if (!strcmp(argv[2], "hugetlbfs")) {
unsigned long hpage_size = default_huge_page_size();
if (!hpage_size) {
printf("Unable to determine huge page size\n");
abort();
}
hugetlbfs_test = 1;
mfd_def_size = hpage_size * 2;
} else {
printf("Unknown option: %s\n", argv[2]);
abort();
}
}
zero = calloc(sizeof(*zero), mfd_def_size);
/* open FUSE memfd file for GUP testing */
printf("opening: %s\n", argv[1]);
fd = open(argv[1], O_RDONLY | O_CLOEXEC);
@ -249,7 +266,7 @@ int main(int argc, char **argv)
/* create new memfd-object */
mfd = mfd_assert_new("kern_memfd_fuse",
MFD_DEF_SIZE,
mfd_def_size,
MFD_CLOEXEC | MFD_ALLOW_SEALING);
/* mmap memfd-object for writing */
@ -268,7 +285,7 @@ int main(int argc, char **argv)
* This guarantees that the receive-buffer is pinned for 1s until the
* data is written into it. The racing ADD_SEALS should thus fail as
* the pages are still pinned. */
r = read(fd, p, MFD_DEF_SIZE);
r = read(fd, p, mfd_def_size);
if (r < 0) {
printf("read() failed: %m\n");
abort();
@ -295,10 +312,10 @@ int main(int argc, char **argv)
* enough to avoid any in-flight writes. */
p = mfd_assert_mmap_private(mfd);
if (was_sealed && memcmp(p, zero, MFD_DEF_SIZE)) {
if (was_sealed && memcmp(p, zero, mfd_def_size)) {
printf("memfd sealed during read() but data not discarded\n");
abort();
} else if (!was_sealed && !memcmp(p, zero, MFD_DEF_SIZE)) {
} else if (!was_sealed && !memcmp(p, zero, mfd_def_size)) {
printf("memfd sealed after read() but data discarded\n");
abort();
}
@ -307,6 +324,7 @@ int main(int argc, char **argv)
close(fd);
printf("fuse: DONE\n");
free(zero);
return 0;
}

View file

@ -19,7 +19,10 @@
#include <sys/wait.h>
#include <unistd.h>
#include "common.h"
#define MEMFD_STR "memfd:"
#define MEMFD_HUGE_STR "memfd-hugetlb:"
#define SHARED_FT_STR "(shared file-table)"
#define MFD_DEF_SIZE 8192
@ -28,41 +31,8 @@
/*
* Default is not to test hugetlbfs
*/
static int hugetlbfs_test;
static size_t mfd_def_size = MFD_DEF_SIZE;
/*
* Copied from mlock2-tests.c
*/
static unsigned long default_huge_page_size(void)
{
unsigned long hps = 0;
char *line = NULL;
size_t linelen = 0;
FILE *f = fopen("/proc/meminfo", "r");
if (!f)
return 0;
while (getline(&line, &linelen, f) > 0) {
if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
hps <<= 10;
break;
}
}
free(line);
fclose(f);
return hps;
}
static int sys_memfd_create(const char *name,
unsigned int flags)
{
if (hugetlbfs_test)
flags |= MFD_HUGETLB;
return syscall(__NR_memfd_create, name, flags);
}
static const char *memfd_str = MEMFD_STR;
static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
{
@ -513,6 +483,10 @@ static void mfd_assert_grow_write(int fd)
static char *buf;
ssize_t l;
/* hugetlbfs does not support write */
if (hugetlbfs_test)
return;
buf = malloc(mfd_def_size * 8);
if (!buf) {
printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
@ -533,6 +507,10 @@ static void mfd_fail_grow_write(int fd)
static char *buf;
ssize_t l;
/* hugetlbfs does not support write */
if (hugetlbfs_test)
return;
buf = malloc(mfd_def_size * 8);
if (!buf) {
printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
@ -598,7 +576,7 @@ static void test_create(void)
char buf[2048];
int fd;
printf("%s CREATE\n", MEMFD_STR);
printf("%s CREATE\n", memfd_str);
/* test NULL name */
mfd_fail_new(NULL, 0);
@ -627,18 +605,13 @@ static void test_create(void)
fd = mfd_assert_new("", 0, MFD_CLOEXEC);
close(fd);
if (!hugetlbfs_test) {
/* verify MFD_ALLOW_SEALING is allowed */
fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
close(fd);
/* verify MFD_ALLOW_SEALING is allowed */
fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
close(fd);
/* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
close(fd);
} else {
/* sealing is not supported on hugetlbfs */
mfd_fail_new("", MFD_ALLOW_SEALING);
}
/* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
close(fd);
}
/*
@ -649,11 +622,7 @@ static void test_basic(void)
{
int fd;
/* hugetlbfs does not contain sealing support */
if (hugetlbfs_test)
return;
printf("%s BASIC\n", MEMFD_STR);
printf("%s BASIC\n", memfd_str);
fd = mfd_assert_new("kern_memfd_basic",
mfd_def_size,
@ -697,28 +666,6 @@ static void test_basic(void)
close(fd);
}
/*
* hugetlbfs doesn't support seals or write, so just verify grow and shrink
* on a hugetlbfs file created via memfd_create.
*/
static void test_hugetlbfs_grow_shrink(void)
{
int fd;
printf("%s HUGETLBFS-GROW-SHRINK\n", MEMFD_STR);
fd = mfd_assert_new("kern_memfd_seal_write",
mfd_def_size,
MFD_CLOEXEC);
mfd_assert_read(fd);
mfd_assert_write(fd);
mfd_assert_shrink(fd);
mfd_assert_grow(fd);
close(fd);
}
/*
* Test SEAL_WRITE
* Test whether SEAL_WRITE actually prevents modifications.
@ -727,14 +674,7 @@ static void test_seal_write(void)
{
int fd;
/*
* hugetlbfs does not contain sealing or write support. Just test
* basic grow and shrink via test_hugetlbfs_grow_shrink.
*/
if (hugetlbfs_test)
return test_hugetlbfs_grow_shrink();
printf("%s SEAL-WRITE\n", MEMFD_STR);
printf("%s SEAL-WRITE\n", memfd_str);
fd = mfd_assert_new("kern_memfd_seal_write",
mfd_def_size,
@ -760,11 +700,7 @@ static void test_seal_shrink(void)
{
int fd;
/* hugetlbfs does not contain sealing support */
if (hugetlbfs_test)
return;
printf("%s SEAL-SHRINK\n", MEMFD_STR);
printf("%s SEAL-SHRINK\n", memfd_str);
fd = mfd_assert_new("kern_memfd_seal_shrink",
mfd_def_size,
@ -790,11 +726,7 @@ static void test_seal_grow(void)
{
int fd;
/* hugetlbfs does not contain sealing support */
if (hugetlbfs_test)
return;
printf("%s SEAL-GROW\n", MEMFD_STR);
printf("%s SEAL-GROW\n", memfd_str);
fd = mfd_assert_new("kern_memfd_seal_grow",
mfd_def_size,
@ -820,11 +752,7 @@ static void test_seal_resize(void)
{
int fd;
/* hugetlbfs does not contain sealing support */
if (hugetlbfs_test)
return;
printf("%s SEAL-RESIZE\n", MEMFD_STR);
printf("%s SEAL-RESIZE\n", memfd_str);
fd = mfd_assert_new("kern_memfd_seal_resize",
mfd_def_size,
@ -842,32 +770,6 @@ static void test_seal_resize(void)
close(fd);
}
/*
* hugetlbfs does not support seals. Basic test to dup the memfd created
* fd and perform some basic operations on it.
*/
static void hugetlbfs_dup(char *b_suffix)
{
int fd, fd2;
printf("%s HUGETLBFS-DUP %s\n", MEMFD_STR, b_suffix);
fd = mfd_assert_new("kern_memfd_share_dup",
mfd_def_size,
MFD_CLOEXEC);
fd2 = mfd_assert_dup(fd);
mfd_assert_read(fd);
mfd_assert_write(fd);
mfd_assert_shrink(fd2);
mfd_assert_grow(fd2);
close(fd2);
close(fd);
}
/*
* Test sharing via dup()
* Test that seals are shared between dupped FDs and they're all equal.
@ -876,16 +778,7 @@ static void test_share_dup(char *banner, char *b_suffix)
{
int fd, fd2;
/*
* hugetlbfs does not contain sealing support. Perform some
* basic testing on dup'ed fd instead via hugetlbfs_dup.
*/
if (hugetlbfs_test) {
hugetlbfs_dup(b_suffix);
return;
}
printf("%s %s %s\n", MEMFD_STR, banner, b_suffix);
printf("%s %s %s\n", memfd_str, banner, b_suffix);
fd = mfd_assert_new("kern_memfd_share_dup",
mfd_def_size,
@ -927,11 +820,7 @@ static void test_share_mmap(char *banner, char *b_suffix)
int fd;
void *p;
/* hugetlbfs does not contain sealing support */
if (hugetlbfs_test)
return;
printf("%s %s %s\n", MEMFD_STR, banner, b_suffix);
printf("%s %s %s\n", memfd_str, banner, b_suffix);
fd = mfd_assert_new("kern_memfd_share_mmap",
mfd_def_size,
@ -955,32 +844,6 @@ static void test_share_mmap(char *banner, char *b_suffix)
close(fd);
}
/*
* Basic test to make sure we can open the hugetlbfs fd via /proc and
* perform some simple operations on it.
*/
static void hugetlbfs_proc_open(char *b_suffix)
{
int fd, fd2;
printf("%s HUGETLBFS-PROC-OPEN %s\n", MEMFD_STR, b_suffix);
fd = mfd_assert_new("kern_memfd_share_open",
mfd_def_size,
MFD_CLOEXEC);
fd2 = mfd_assert_open(fd, O_RDWR, 0);
mfd_assert_read(fd);
mfd_assert_write(fd);
mfd_assert_shrink(fd2);
mfd_assert_grow(fd2);
close(fd2);
close(fd);
}
/*
* Test sealing with open(/proc/self/fd/%d)
* Via /proc we can get access to a separate file-context for the same memfd.
@ -991,16 +854,7 @@ static void test_share_open(char *banner, char *b_suffix)
{
int fd, fd2;
/*
* hugetlbfs does not contain sealing support. So test basic
* functionality of using /proc fd via hugetlbfs_proc_open
*/
if (hugetlbfs_test) {
hugetlbfs_proc_open(b_suffix);
return;
}
printf("%s %s %s\n", MEMFD_STR, banner, b_suffix);
printf("%s %s %s\n", memfd_str, banner, b_suffix);
fd = mfd_assert_new("kern_memfd_share_open",
mfd_def_size,
@ -1043,11 +897,7 @@ static void test_share_fork(char *banner, char *b_suffix)
int fd;
pid_t pid;
/* hugetlbfs does not contain sealing support */
if (hugetlbfs_test)
return;
printf("%s %s %s\n", MEMFD_STR, banner, b_suffix);
printf("%s %s %s\n", memfd_str, banner, b_suffix);
fd = mfd_assert_new("kern_memfd_share_fork",
mfd_def_size,
@ -1083,7 +933,11 @@ int main(int argc, char **argv)
}
hugetlbfs_test = 1;
memfd_str = MEMFD_HUGE_STR;
mfd_def_size = hpage_size * 2;
} else {
printf("Unknown option: %s\n", argv[1]);
abort();
}
}

View file

@ -10,6 +10,6 @@ set -e
mkdir mnt
./fuse_mnt ./mnt
./fuse_test ./mnt/memfd
./fuse_test ./mnt/memfd $@
fusermount -u ./mnt
rmdir ./mnt

View file

@ -60,6 +60,7 @@ fi
# Run the hugetlbfs test
#
./memfd_test hugetlbfs
./run_fuse_test.sh hugetlbfs
#
# Give back any huge pages allocated for the test

View file

@ -8,17 +8,18 @@ endif
CFLAGS = -Wall -I ../../../../usr/include $(EXTRA_CFLAGS)
LDLIBS = -lrt
TEST_GEN_FILES = compaction_test
TEST_GEN_FILES += gup_benchmark
TEST_GEN_FILES += hugepage-mmap
TEST_GEN_FILES += hugepage-shm
TEST_GEN_FILES += map_hugetlb
TEST_GEN_FILES += mlock-random-test
TEST_GEN_FILES += mlock2-tests
TEST_GEN_FILES += on-fault-limit
TEST_GEN_FILES += thuge-gen
TEST_GEN_FILES += transhuge-stress
TEST_GEN_FILES += userfaultfd
TEST_GEN_FILES += mlock-random-test
TEST_GEN_FILES += va_128TBswitch
TEST_GEN_FILES += virtual_address_range
TEST_GEN_FILES += gup_benchmark
TEST_PROGS := run_vmtests

View file

@ -177,4 +177,15 @@ else
echo "[PASS]"
fi
echo "-----------------------------"
echo "running virtual address 128TB switch test"
echo "-----------------------------"
./va_128TBswitch
if [ $? -ne 0 ]; then
echo "[FAIL]"
exitcode=1
else
echo "[PASS]"
fi
exit $exitcode

View file

@ -0,0 +1,297 @@
/*
*
* Authors: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
* Authors: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#ifdef __powerpc64__
#define PAGE_SIZE (64 << 10)
/*
* This will work with 16M and 2M hugepage size
*/
#define HUGETLB_SIZE (16 << 20)
#else
#define PAGE_SIZE (4 << 10)
#define HUGETLB_SIZE (2 << 20)
#endif
/*
* >= 128TB is the hint addr value we used to select
* large address space.
*/
#define ADDR_SWITCH_HINT (1UL << 47)
#define LOW_ADDR ((void *) (1UL << 30))
#define HIGH_ADDR ((void *) (1UL << 48))
struct testcase {
void *addr;
unsigned long size;
unsigned long flags;
const char *msg;
unsigned int low_addr_required:1;
unsigned int keep_mapped:1;
};
static struct testcase testcases[] = {
{
/*
* If stack is moved, we could possibly allocate
* this at the requested address.
*/
.addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
.size = PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
.low_addr_required = 1,
},
{
/*
* We should never allocate at the requested address or above it
* The len cross the 128TB boundary. Without MAP_FIXED
* we will always search in the lower address space.
*/
.addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, (2 * PAGE_SIZE))",
.low_addr_required = 1,
},
{
/*
* Exact mapping at 128TB, the area is free we should get that
* even without MAP_FIXED.
*/
.addr = ((void *)(ADDR_SWITCH_HINT)),
.size = PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
.keep_mapped = 1,
},
{
.addr = (void *)(ADDR_SWITCH_HINT),
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
.msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
},
{
.addr = NULL,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(NULL)",
.low_addr_required = 1,
},
{
.addr = LOW_ADDR,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(LOW_ADDR)",
.low_addr_required = 1,
},
{
.addr = HIGH_ADDR,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(HIGH_ADDR)",
.keep_mapped = 1,
},
{
.addr = HIGH_ADDR,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(HIGH_ADDR) again",
.keep_mapped = 1,
},
{
.addr = HIGH_ADDR,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
.msg = "mmap(HIGH_ADDR, MAP_FIXED)",
},
{
.addr = (void *) -1,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(-1)",
.keep_mapped = 1,
},
{
.addr = (void *) -1,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(-1) again",
},
{
.addr = ((void *)(ADDR_SWITCH_HINT - PAGE_SIZE)),
.size = PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, PAGE_SIZE)",
.low_addr_required = 1,
},
{
.addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2 * PAGE_SIZE)",
.low_addr_required = 1,
.keep_mapped = 1,
},
{
.addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE / 2),
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE/2 , 2 * PAGE_SIZE)",
.low_addr_required = 1,
.keep_mapped = 1,
},
{
.addr = ((void *)(ADDR_SWITCH_HINT)),
.size = PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(ADDR_SWITCH_HINT, PAGE_SIZE)",
},
{
.addr = (void *)(ADDR_SWITCH_HINT),
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
.msg = "mmap(ADDR_SWITCH_HINT, 2 * PAGE_SIZE, MAP_FIXED)",
},
};
static struct testcase hugetlb_testcases[] = {
{
.addr = NULL,
.size = HUGETLB_SIZE,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(NULL, MAP_HUGETLB)",
.low_addr_required = 1,
},
{
.addr = LOW_ADDR,
.size = HUGETLB_SIZE,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(LOW_ADDR, MAP_HUGETLB)",
.low_addr_required = 1,
},
{
.addr = HIGH_ADDR,
.size = HUGETLB_SIZE,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(HIGH_ADDR, MAP_HUGETLB)",
.keep_mapped = 1,
},
{
.addr = HIGH_ADDR,
.size = HUGETLB_SIZE,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again",
.keep_mapped = 1,
},
{
.addr = HIGH_ADDR,
.size = HUGETLB_SIZE,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
.msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)",
},
{
.addr = (void *) -1,
.size = HUGETLB_SIZE,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(-1, MAP_HUGETLB)",
.keep_mapped = 1,
},
{
.addr = (void *) -1,
.size = HUGETLB_SIZE,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(-1, MAP_HUGETLB) again",
},
{
.addr = (void *)(ADDR_SWITCH_HINT - PAGE_SIZE),
.size = 2 * HUGETLB_SIZE,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(ADDR_SWITCH_HINT - PAGE_SIZE, 2*HUGETLB_SIZE, MAP_HUGETLB)",
.low_addr_required = 1,
.keep_mapped = 1,
},
{
.addr = (void *)(ADDR_SWITCH_HINT),
.size = 2 * HUGETLB_SIZE,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
.msg = "mmap(ADDR_SWITCH_HINT , 2*HUGETLB_SIZE, MAP_FIXED | MAP_HUGETLB)",
},
};
static int run_test(struct testcase *test, int count)
{
void *p;
int i, ret = 0;
for (i = 0; i < count; i++) {
struct testcase *t = test + i;
p = mmap(t->addr, t->size, PROT_READ | PROT_WRITE, t->flags, -1, 0);
printf("%s: %p - ", t->msg, p);
if (p == MAP_FAILED) {
printf("FAILED\n");
ret = 1;
continue;
}
if (t->low_addr_required && p >= (void *)(ADDR_SWITCH_HINT)) {
printf("FAILED\n");
ret = 1;
} else {
/*
* Do a dereference of the address returned so that we catch
* bugs in page fault handling
*/
memset(p, 0, t->size);
printf("OK\n");
}
if (!t->keep_mapped)
munmap(p, t->size);
}
return ret;
}
static int supported_arch(void)
{
#if defined(__powerpc64__)
return 1;
#elif defined(__x86_64__)
return 1;
#else
return 0;
#endif
}
int main(int argc, char **argv)
{
int ret;
if (!supported_arch())
return 0;
ret = run_test(testcases, ARRAY_SIZE(testcases));
if (argc == 2 && !strcmp(argv[1], "--run-hugetlb"))
ret = run_test(hugetlb_testcases, ARRAY_SIZE(hugetlb_testcases));
return ret;
}

View file

@ -1,177 +0,0 @@
#include <stdio.h>
#include <sys/mman.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define PAGE_SIZE 4096
#define LOW_ADDR ((void *) (1UL << 30))
#define HIGH_ADDR ((void *) (1UL << 50))
struct testcase {
void *addr;
unsigned long size;
unsigned long flags;
const char *msg;
unsigned int low_addr_required:1;
unsigned int keep_mapped:1;
};
static struct testcase testcases[] = {
{
.addr = NULL,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(NULL)",
.low_addr_required = 1,
},
{
.addr = LOW_ADDR,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(LOW_ADDR)",
.low_addr_required = 1,
},
{
.addr = HIGH_ADDR,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(HIGH_ADDR)",
.keep_mapped = 1,
},
{
.addr = HIGH_ADDR,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(HIGH_ADDR) again",
.keep_mapped = 1,
},
{
.addr = HIGH_ADDR,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
.msg = "mmap(HIGH_ADDR, MAP_FIXED)",
},
{
.addr = (void*) -1,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(-1)",
.keep_mapped = 1,
},
{
.addr = (void*) -1,
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(-1) again",
},
{
.addr = (void *)((1UL << 47) - PAGE_SIZE),
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap((1UL << 47), 2 * PAGE_SIZE)",
.low_addr_required = 1,
.keep_mapped = 1,
},
{
.addr = (void *)((1UL << 47) - PAGE_SIZE / 2),
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap((1UL << 47), 2 * PAGE_SIZE / 2)",
.low_addr_required = 1,
.keep_mapped = 1,
},
{
.addr = (void *)((1UL << 47) - PAGE_SIZE),
.size = 2 * PAGE_SIZE,
.flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
.msg = "mmap((1UL << 47) - PAGE_SIZE, 2 * PAGE_SIZE, MAP_FIXED)",
},
{
.addr = NULL,
.size = 2UL << 20,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(NULL, MAP_HUGETLB)",
.low_addr_required = 1,
},
{
.addr = LOW_ADDR,
.size = 2UL << 20,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(LOW_ADDR, MAP_HUGETLB)",
.low_addr_required = 1,
},
{
.addr = HIGH_ADDR,
.size = 2UL << 20,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(HIGH_ADDR, MAP_HUGETLB)",
.keep_mapped = 1,
},
{
.addr = HIGH_ADDR,
.size = 2UL << 20,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(HIGH_ADDR, MAP_HUGETLB) again",
.keep_mapped = 1,
},
{
.addr = HIGH_ADDR,
.size = 2UL << 20,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
.msg = "mmap(HIGH_ADDR, MAP_FIXED | MAP_HUGETLB)",
},
{
.addr = (void*) -1,
.size = 2UL << 20,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(-1, MAP_HUGETLB)",
.keep_mapped = 1,
},
{
.addr = (void*) -1,
.size = 2UL << 20,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap(-1, MAP_HUGETLB) again",
},
{
.addr = (void *)((1UL << 47) - PAGE_SIZE),
.size = 4UL << 20,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS,
.msg = "mmap((1UL << 47), 4UL << 20, MAP_HUGETLB)",
.low_addr_required = 1,
.keep_mapped = 1,
},
{
.addr = (void *)((1UL << 47) - (2UL << 20)),
.size = 4UL << 20,
.flags = MAP_HUGETLB | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
.msg = "mmap((1UL << 47) - (2UL << 20), 4UL << 20, MAP_FIXED | MAP_HUGETLB)",
},
};
int main(int argc, char **argv)
{
int i;
void *p;
for (i = 0; i < ARRAY_SIZE(testcases); i++) {
struct testcase *t = testcases + i;
p = mmap(t->addr, t->size, PROT_NONE, t->flags, -1, 0);
printf("%s: %p - ", t->msg, p);
if (p == MAP_FAILED) {
printf("FAILED\n");
continue;
}
if (t->low_addr_required && p >= (void *)(1UL << 47))
printf("FAILED\n");
else
printf("OK\n");
if (!t->keep_mapped)
munmap(p, t->size);
}
return 0;
}