Skip to content

Commit f5c7329

Browse files
mjkravetztorvalds
authored andcommitted
userfaultfd/selftests: fix hugetlb area allocations
Currently, userfaultfd selftest for hugetlb as run from run_vmtests.sh or any environment where there are 'just enough' hugetlb pages will always fail with: testing events (fork, remap, remove): ERROR: UFFDIO_COPY error: -12 (errno=12, line=616) The ENOMEM error code implies there are not enough hugetlb pages. However, there are free hugetlb pages but they are all reserved. There is a basic problem with the way the test allocates hugetlb pages which has existed since the test was originally written. Due to the way 'cleanup' was done between different phases of the test, this issue was masked until recently. The issue was uncovered by commit 8ba6e86 ("userfaultfd/selftests: reinitialize test context in each test"). For the hugetlb test, src and dst areas are allocated as PRIVATE mappings of a hugetlb file. This means that at mmap time, pages are reserved for the src and dst areas. At the start of event testing (and other tests) the src area is populated which results in allocation of huge pages to fill the area and consumption of reserves associated with the area. Then, a child is forked to fault in the dst area. Note that the dst area was allocated in the parent and hence the parent owns the reserves associated with the mapping. The child has normal access to the dst area, but can not use the reserves created/owned by the parent. Thus, if there are no other huge pages available allocation of a page for the dst by the child will fail. Fix by not creating reserves for the dst area. In this way the child can use free (non-reserved) pages. Also, MAP_PRIVATE of a file only makes sense if you are interested in the contents of the file before making a COW copy. The test does not do this. So, just use MAP_ANONYMOUS | MAP_HUGETLB to create an anonymous hugetlb mapping. There is no need to create a hugetlb file in the non-shared case. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Mike Kravetz <[email protected]> Cc: Axel Rasmussen <[email protected]> Cc: Peter Xu <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Mina Almasry <[email protected]> Cc: Shuah Khan <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 4f3d93c commit f5c7329

File tree

1 file changed

+10
-6
lines changed

1 file changed

+10
-6
lines changed

tools/testing/selftests/vm/userfaultfd.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static bool test_uffdio_minor = false;
8787

8888
static bool map_shared;
8989
static int shm_fd;
90-
static int huge_fd;
90+
static int huge_fd = -1; /* only used for hugetlb_shared test */
9191
static char *huge_fd_off0;
9292
static unsigned long long *count_verify;
9393
static int uffd = -1;
@@ -223,6 +223,9 @@ static void noop_alias_mapping(__u64 *start, size_t len, unsigned long offset)
223223

224224
static void hugetlb_release_pages(char *rel_area)
225225
{
226+
if (huge_fd == -1)
227+
return;
228+
226229
if (fallocate(huge_fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
227230
rel_area == huge_fd_off0 ? 0 : nr_pages * page_size,
228231
nr_pages * page_size))
@@ -235,16 +238,17 @@ static void hugetlb_allocate_area(void **alloc_area)
235238
char **alloc_area_alias;
236239

237240
*alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
238-
(map_shared ? MAP_SHARED : MAP_PRIVATE) |
239-
MAP_HUGETLB,
240-
huge_fd, *alloc_area == area_src ? 0 :
241-
nr_pages * page_size);
241+
map_shared ? MAP_SHARED :
242+
MAP_PRIVATE | MAP_HUGETLB |
243+
(*alloc_area == area_src ? 0 : MAP_NORESERVE),
244+
huge_fd,
245+
*alloc_area == area_src ? 0 : nr_pages * page_size);
242246
if (*alloc_area == MAP_FAILED)
243247
err("mmap of hugetlbfs file failed");
244248

245249
if (map_shared) {
246250
area_alias = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
247-
MAP_SHARED | MAP_HUGETLB,
251+
MAP_SHARED,
248252
huge_fd, *alloc_area == area_src ? 0 :
249253
nr_pages * page_size);
250254
if (area_alias == MAP_FAILED)

0 commit comments

Comments
 (0)