Commit 4bf6a4eb authored by David Hildenbrand's avatar David Hildenbrand Committed by Andrew Morton

selftests: mm: cow: flag vmsplice() hugetlb tests as XFAIL

Patch series "selftests: mm: cow: flag vmsplice() hugetlb tests as XFAIL".

The failing hugetlb vmsplice() COW tests keep confusing people, and having
tests that have been failing for years and likely will keep failing for
years to come because nobody cares enough is rather suboptimal.  Let's
mark them as XFAIL and document why fixing them is not that easy as it
would appear at first sight.

More details can be found in [1], especially around how hugetlb pages
cannot really be overcommitted, and why we don't particularly care about
these vmsplice() leaks for hugetlb -- in contrast to ordinary memory.

[1] https://lore.kernel.org/all/8b42a24d-caf0-46ef-9e15-0f88d47d2f21@redhat.com/


This patch (of 2):

The vmsplice() hugetlb tests have been failing right from the start, and
we documented that in the introducing commit 7dad331b ("selftests/vm:
anon_cow: hugetlb tests"):

	Note that some tests cases still fail. This will, for example, be
	fixed once vmsplice properly uses FOLL_PIN instead of FOLL_GET for
	pinning. With 2 MiB and 1 GiB hugetlb on x86_64, the expected
	failures are:

Until vmsplice() is changed, these tests will likely keep failing: hugetlb
COW reuse logic is harder to change, because using the same COW reuse
logic as we use for !hugetlb could harm other (sane) users when running
out of free hugetlb pages.

More details can be found in [1], especially around how hugetlb pages
cannot really be overcommitted, and why we don't particularly care about
these vmsplice() leaks for hugetlb -- in contrast to ordinary memory.

These (expected) failures keep confusing people, so flag them accordingly.

Before:
	$ ./cow
	[...]
	Bail out! 8 out of 778 tests failed
	# Totals: pass:769 fail:8 xfail:0 xpass:0 skip:1 error:0
	$ echo $?
	1

After:
	$ ./cow
	[...]
	# Totals: pass:769 fail:0 xfail:8 xpass:0 skip:1 error:0
	$ echo $?
	0

[1] https://lore.kernel.org/all/8b42a24d-caf0-46ef-9e15-0f88d47d2f21@redhat.com/

Link: https://lkml.kernel.org/r/20240502085259.103784-1-david@redhat.com
Link: https://lkml.kernel.org/r/20240502085259.103784-2-david@redhat.comSigned-off-by: default avatarDavid Hildenbrand <david@redhat.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Peter Xu <peterx@redhat.com>
Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 5ee9562c
......@@ -199,7 +199,7 @@ static int child_vmsplice_memcmp_fn(char *mem, size_t size,
typedef int (*child_fn)(char *mem, size_t size, struct comm_pipes *comm_pipes);
static void do_test_cow_in_parent(char *mem, size_t size, bool do_mprotect,
child_fn fn)
child_fn fn, bool xfail)
{
struct comm_pipes comm_pipes;
char buf;
......@@ -247,33 +247,47 @@ static void do_test_cow_in_parent(char *mem, size_t size, bool do_mprotect,
else
ret = -EINVAL;
ksft_test_result(!ret, "No leak from parent into child\n");
if (!ret) {
ksft_test_result_pass("No leak from parent into child\n");
} else if (xfail) {
/*
* With hugetlb, some vmsplice() tests are currently expected to
* fail because (a) harder to fix and (b) nobody really cares.
* Flag them as expected failure for now.
*/
ksft_test_result_xfail("Leak from parent into child\n");
} else {
ksft_test_result_fail("Leak from parent into child\n");
}
close_comm_pipes:
close_comm_pipes(&comm_pipes);
}
static void test_cow_in_parent(char *mem, size_t size)
static void test_cow_in_parent(char *mem, size_t size, bool is_hugetlb)
{
do_test_cow_in_parent(mem, size, false, child_memcmp_fn);
do_test_cow_in_parent(mem, size, false, child_memcmp_fn, false);
}
static void test_cow_in_parent_mprotect(char *mem, size_t size)
static void test_cow_in_parent_mprotect(char *mem, size_t size, bool is_hugetlb)
{
do_test_cow_in_parent(mem, size, true, child_memcmp_fn);
do_test_cow_in_parent(mem, size, true, child_memcmp_fn, false);
}
static void test_vmsplice_in_child(char *mem, size_t size)
static void test_vmsplice_in_child(char *mem, size_t size, bool is_hugetlb)
{
do_test_cow_in_parent(mem, size, false, child_vmsplice_memcmp_fn);
do_test_cow_in_parent(mem, size, false, child_vmsplice_memcmp_fn,
is_hugetlb);
}
static void test_vmsplice_in_child_mprotect(char *mem, size_t size)
static void test_vmsplice_in_child_mprotect(char *mem, size_t size,
bool is_hugetlb)
{
do_test_cow_in_parent(mem, size, true, child_vmsplice_memcmp_fn);
do_test_cow_in_parent(mem, size, true, child_vmsplice_memcmp_fn,
is_hugetlb);
}
static void do_test_vmsplice_in_parent(char *mem, size_t size,
bool before_fork)
bool before_fork, bool xfail)
{
struct iovec iov = {
.iov_base = mem,
......@@ -355,8 +369,18 @@ static void do_test_vmsplice_in_parent(char *mem, size_t size,
}
}
ksft_test_result(!memcmp(old, new, transferred),
"No leak from child into parent\n");
if (!memcmp(old, new, transferred)) {
ksft_test_result_pass("No leak from child into parent\n");
} else if (xfail) {
/*
* With hugetlb, some vmsplice() tests are currently expected to
* fail because (a) harder to fix and (b) nobody really cares.
* Flag them as expected failure for now.
*/
ksft_test_result_xfail("Leak from child into parent\n");
} else {
ksft_test_result_fail("Leak from child into parent\n");
}
close_pipe:
close(fds[0]);
close(fds[1]);
......@@ -367,14 +391,14 @@ static void do_test_vmsplice_in_parent(char *mem, size_t size,
free(new);
}
static void test_vmsplice_before_fork(char *mem, size_t size)
static void test_vmsplice_before_fork(char *mem, size_t size, bool is_hugetlb)
{
do_test_vmsplice_in_parent(mem, size, true);
do_test_vmsplice_in_parent(mem, size, true, is_hugetlb);
}
static void test_vmsplice_after_fork(char *mem, size_t size)
static void test_vmsplice_after_fork(char *mem, size_t size, bool is_hugetlb)
{
do_test_vmsplice_in_parent(mem, size, false);
do_test_vmsplice_in_parent(mem, size, false, is_hugetlb);
}
#ifdef LOCAL_CONFIG_HAVE_LIBURING
......@@ -529,12 +553,12 @@ static void do_test_iouring(char *mem, size_t size, bool use_fork)
close_comm_pipes(&comm_pipes);
}
static void test_iouring_ro(char *mem, size_t size)
static void test_iouring_ro(char *mem, size_t size, bool is_hugetlb)
{
do_test_iouring(mem, size, false);
}
static void test_iouring_fork(char *mem, size_t size)
static void test_iouring_fork(char *mem, size_t size, bool is_hugetlb)
{
do_test_iouring(mem, size, true);
}
......@@ -678,37 +702,41 @@ static void do_test_ro_pin(char *mem, size_t size, enum ro_pin_test test,
free(tmp);
}
static void test_ro_pin_on_shared(char *mem, size_t size)
static void test_ro_pin_on_shared(char *mem, size_t size, bool is_hugetlb)
{
do_test_ro_pin(mem, size, RO_PIN_TEST_SHARED, false);
}
static void test_ro_fast_pin_on_shared(char *mem, size_t size)
static void test_ro_fast_pin_on_shared(char *mem, size_t size, bool is_hugetlb)
{
do_test_ro_pin(mem, size, RO_PIN_TEST_SHARED, true);
}
static void test_ro_pin_on_ro_previously_shared(char *mem, size_t size)
static void test_ro_pin_on_ro_previously_shared(char *mem, size_t size,
bool is_hugetlb)
{
do_test_ro_pin(mem, size, RO_PIN_TEST_PREVIOUSLY_SHARED, false);
}
static void test_ro_fast_pin_on_ro_previously_shared(char *mem, size_t size)
static void test_ro_fast_pin_on_ro_previously_shared(char *mem, size_t size,
bool is_hugetlb)
{
do_test_ro_pin(mem, size, RO_PIN_TEST_PREVIOUSLY_SHARED, true);
}
static void test_ro_pin_on_ro_exclusive(char *mem, size_t size)
static void test_ro_pin_on_ro_exclusive(char *mem, size_t size,
bool is_hugetlb)
{
do_test_ro_pin(mem, size, RO_PIN_TEST_RO_EXCLUSIVE, false);
}
static void test_ro_fast_pin_on_ro_exclusive(char *mem, size_t size)
static void test_ro_fast_pin_on_ro_exclusive(char *mem, size_t size,
bool is_hugetlb)
{
do_test_ro_pin(mem, size, RO_PIN_TEST_RO_EXCLUSIVE, true);
}
typedef void (*test_fn)(char *mem, size_t size);
typedef void (*test_fn)(char *mem, size_t size, bool hugetlb);
static void do_run_with_base_page(test_fn fn, bool swapout)
{
......@@ -740,7 +768,7 @@ static void do_run_with_base_page(test_fn fn, bool swapout)
}
}
fn(mem, pagesize);
fn(mem, pagesize, false);
munmap:
munmap(mem, pagesize);
}
......@@ -904,7 +932,7 @@ static void do_run_with_thp(test_fn fn, enum thp_run thp_run, size_t thpsize)
break;
}
fn(mem, size);
fn(mem, size, false);
munmap:
munmap(mmap_mem, mmap_size);
if (mremap_mem != MAP_FAILED)
......@@ -997,7 +1025,7 @@ static void run_with_hugetlb(test_fn fn, const char *desc, size_t hugetlbsize)
}
munmap(dummy, hugetlbsize);
fn(mem, hugetlbsize);
fn(mem, hugetlbsize, true);
munmap:
munmap(mem, hugetlbsize);
}
......@@ -1036,7 +1064,7 @@ static const struct test_case anon_test_cases[] = {
*/
{
"vmsplice() + unmap in child",
test_vmsplice_in_child
test_vmsplice_in_child,
},
/*
* vmsplice() test, but do an additional mprotect(PROT_READ)+
......@@ -1044,7 +1072,7 @@ static const struct test_case anon_test_cases[] = {
*/
{
"vmsplice() + unmap in child with mprotect() optimization",
test_vmsplice_in_child_mprotect
test_vmsplice_in_child_mprotect,
},
/*
* vmsplice() [R/O GUP] in parent before fork(), unmap in parent after
......@@ -1322,23 +1350,31 @@ static void do_test_anon_thp_collapse(char *mem, size_t size,
close_comm_pipes(&comm_pipes);
}
static void test_anon_thp_collapse_unshared(char *mem, size_t size)
static void test_anon_thp_collapse_unshared(char *mem, size_t size,
bool is_hugetlb)
{
assert(!is_hugetlb);
do_test_anon_thp_collapse(mem, size, ANON_THP_COLLAPSE_UNSHARED);
}
static void test_anon_thp_collapse_fully_shared(char *mem, size_t size)
static void test_anon_thp_collapse_fully_shared(char *mem, size_t size,
bool is_hugetlb)
{
assert(!is_hugetlb);
do_test_anon_thp_collapse(mem, size, ANON_THP_COLLAPSE_FULLY_SHARED);
}
static void test_anon_thp_collapse_lower_shared(char *mem, size_t size)
static void test_anon_thp_collapse_lower_shared(char *mem, size_t size,
bool is_hugetlb)
{
assert(!is_hugetlb);
do_test_anon_thp_collapse(mem, size, ANON_THP_COLLAPSE_LOWER_SHARED);
}
static void test_anon_thp_collapse_upper_shared(char *mem, size_t size)
static void test_anon_thp_collapse_upper_shared(char *mem, size_t size,
bool is_hugetlb)
{
assert(!is_hugetlb);
do_test_anon_thp_collapse(mem, size, ANON_THP_COLLAPSE_UPPER_SHARED);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment