Add test for partial MADV_DONTNEED on THP. This verifies that MADV_DONTNEED correctly triggers a PMD split, discards only the requested page (which becomes zero-filled), and preserves data in the surrounding pages.
Signed-off-by: Usama Arif <[email protected]> --- .../testing/selftests/mm/thp_pmd_split_test.c | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tools/testing/selftests/mm/thp_pmd_split_test.c b/tools/testing/selftests/mm/thp_pmd_split_test.c index 1f29296759a5b..060ca1e341b75 100644 --- a/tools/testing/selftests/mm/thp_pmd_split_test.c +++ b/tools/testing/selftests/mm/thp_pmd_split_test.c @@ -253,4 +253,38 @@ TEST_F(thp_pmd_split, partial_mremap) self->split_pmd_failed_before); } +/* + * MADV_DONTNEED on THP + * + * Tests that MADV_DONTNEED on a partial THP correctly handles + * the PMD split and discards only the requested pages. + */ +TEST_F(thp_pmd_split, partial_madv_dontneed) +{ + volatile unsigned char *ptr = (volatile unsigned char *)self->aligned; + int ret; + + ret = allocate_thp(self->aligned, self->pmdsize); + if (ret) + SKIP(return, "Failed to allocate THP"); + + /* Write pattern */ + memset(self->aligned, 0xDD, self->pmdsize); + + /* Partial MADV_DONTNEED - discard middle page */ + ret = madvise((char *)self->aligned + self->pagesize, self->pagesize, MADV_DONTNEED); + ASSERT_EQ(ret, 0); + + /* Verify non-discarded pages still have data */ + ASSERT_EQ(ptr[0], (unsigned char)0xDD); + ASSERT_EQ(ptr[2 * self->pagesize], (unsigned char)0xDD); + ASSERT_EQ(ptr[self->pmdsize - 1], (unsigned char)0xDD); + + /* Discarded page should be zero */ + ASSERT_EQ(ptr[self->pagesize], (unsigned char)0x00); + + log_and_check_pmd_split(_metadata, self->split_pmd_before, + self->split_pmd_failed_before); +} + TEST_HARNESS_MAIN -- 2.47.3
