Add test for partial mremap on THP which exercises move_page_tables().
This verifies that partial mremap correctly splits the PMD, moves
only the requested page, and preserves data integrity in both the
moved region and the original mapping.

Signed-off-by: Usama Arif <[email protected]>
---
 .../testing/selftests/mm/thp_pmd_split_test.c | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/tools/testing/selftests/mm/thp_pmd_split_test.c 
b/tools/testing/selftests/mm/thp_pmd_split_test.c
index 3c9f05457efec..1f29296759a5b 100644
--- a/tools/testing/selftests/mm/thp_pmd_split_test.c
+++ b/tools/testing/selftests/mm/thp_pmd_split_test.c
@@ -203,4 +203,54 @@ TEST_F(thp_pmd_split, partial_mlock)
                self->split_pmd_failed_before);
 }
 
+/*
+ * Partial mremap (move_page_tables)
+ *
+ * Tests that partial mremap of a THP correctly splits the PMD and
+ * moves only the requested portion. This exercises move_page_tables()
+ * which now handles split failures.
+ */
+TEST_F(thp_pmd_split, partial_mremap)
+{
+       void *new_addr;
+       unsigned long *ptr = (unsigned long *)self->aligned;
+       unsigned long *new_ptr;
+       unsigned long pattern = 0xABCDUL;
+       int ret;
+
+       ret = allocate_thp(self->aligned, self->pmdsize);
+       if (ret)
+               SKIP(return, "Failed to allocate THP");
+
+       /* Write pattern to the page we'll move */
+       ptr[self->pagesize / sizeof(unsigned long)] = pattern;
+
+       /* Also write to first and last page to verify they stay intact */
+       ptr[0] = 0x1234UL;
+       ptr[(self->pmdsize - self->pagesize) / sizeof(unsigned long)] = 
0x4567UL;
+
+       /* Partial mremap - move one base page from the THP */
+       new_addr = mremap((char *)self->aligned + self->pagesize, 
self->pagesize,
+                         self->pagesize, MREMAP_MAYMOVE);
+       if (new_addr == MAP_FAILED) {
+               if (errno == ENOMEM)
+                       SKIP(return, "mremap failed with ENOMEM");
+               ASSERT_NE(new_addr, MAP_FAILED);
+       }
+
+       /* Verify data was moved correctly */
+       new_ptr = (unsigned long *)new_addr;
+       ASSERT_EQ(new_ptr[0], pattern);
+
+       /* Verify surrounding data is intact */
+       ASSERT_EQ(ptr[0], 0x1234UL);
+       ASSERT_EQ(ptr[(self->pmdsize - self->pagesize) / sizeof(unsigned 
long)], 0x4567UL);
+
+       /* Cleanup the moved page */
+       munmap(new_addr, self->pagesize);
+
+       log_and_check_pmd_split(_metadata, self->split_pmd_before,
+               self->split_pmd_failed_before);
+}
+
 TEST_HARNESS_MAIN
-- 
2.47.3


Reply via email to