Add test for partial mprotect on THP which exercises change_pmd_range(). This verifies that partial mprotect correctly splits the PMD, applies protection only to the requested portion, and leaves the rest of the mapping writable.
Signed-off-by: Usama Arif <[email protected]> --- .../testing/selftests/mm/thp_pmd_split_test.c | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tools/testing/selftests/mm/thp_pmd_split_test.c b/tools/testing/selftests/mm/thp_pmd_split_test.c index 0f54ac04760d5..4944a5a516da9 100644 --- a/tools/testing/selftests/mm/thp_pmd_split_test.c +++ b/tools/testing/selftests/mm/thp_pmd_split_test.c @@ -146,4 +146,35 @@ TEST_F(thp_pmd_split, partial_munmap) self->split_pmd_failed_before); } +/* + * Partial mprotect on THP (change_pmd_range) + * + * Tests that partial mprotect of a THP correctly splits the PMD and + * applies protection only to the requested portion. This exercises + * the mprotect path which now handles split failures. + */ +TEST_F(thp_pmd_split, partial_mprotect) +{ + 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"); + + /* Partial mprotect - make middle page read-only */ + ret = mprotect((char *)self->aligned + self->pagesize, self->pagesize, PROT_READ); + ASSERT_EQ(ret, 0); + + /* Verify we can still write to non-protected pages */ + ptr[0] = 0xDD; + ptr[self->pmdsize - 1] = 0xEE; + + ASSERT_EQ(ptr[0], (unsigned char)0xDD); + ASSERT_EQ(ptr[self->pmdsize - 1], (unsigned char)0xEE); + + log_and_check_pmd_split(_metadata, self->split_pmd_before, + self->split_pmd_failed_before); +} + TEST_HARNESS_MAIN -- 2.47.3
