Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests/mm: split_huge_page_test: cleanups for split_pte_mapped_thp test

There is room for improvement, so let's clean up a bit:

(1) Define "4" as a constant.

(2) SKIP if we fail to allocate all THPs (e.g., fragmented) and add
recovery code for all other failure cases: no need to exit the test.

(3) Rename "len" to thp_area_size, and "one_page" to "thp_area".

(4) Allocate a new area "page_area" into which we will mremap the
pages; add "page_area_size". Now we can easily merge the two
mremap instances into a single one.

(5) Iterate THPs instead of bytes when checking for missed THPs after
mremap.

(6) Rename "pte_mapped2" to "tmp", used to verify mremap(MAP_FIXED)
result.

(7) Split the corruption test from the failed-split test, so we can just
iterate bytes vs. thps naturally.

(8) Extend comments and clarify why we are using mremap in the first
place.

Link: https://lkml.kernel.org/r/20250903070253.34556-3-david@redhat.com
Signed-off-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Wei Yang <richard.weiyang@gmail.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Mariano Pache <npache@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

David Hildenbrand and committed by
Andrew Morton
24a3c7af 0d0e03d5

+75 -50
+75 -50
tools/testing/selftests/mm/split_huge_page_test.c
··· 389 389 390 390 static void split_pte_mapped_thp(void) 391 391 { 392 - char *one_page, *pte_mapped, *pte_mapped2; 393 - size_t len = 4 * pmd_pagesize; 394 - uint64_t thp_size; 392 + const size_t nr_thps = 4; 393 + const size_t thp_area_size = nr_thps * pmd_pagesize; 394 + const size_t page_area_size = nr_thps * pagesize; 395 + char *thp_area, *tmp, *page_area = MAP_FAILED; 395 396 size_t i; 396 397 397 - one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE, 398 + thp_area = mmap((void *)(1UL << 30), thp_area_size, PROT_READ | PROT_WRITE, 398 399 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 399 - if (one_page == MAP_FAILED) 400 - ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno)); 401 - 402 - madvise(one_page, len, MADV_HUGEPAGE); 403 - 404 - for (i = 0; i < len; i++) 405 - one_page[i] = (char)i; 406 - 407 - if (!check_huge_anon(one_page, 4, pmd_pagesize)) 408 - ksft_exit_fail_msg("No THP is allocated\n"); 409 - 410 - /* remap the first pagesize of first THP */ 411 - pte_mapped = mremap(one_page, pagesize, pagesize, MREMAP_MAYMOVE); 412 - 413 - /* remap the Nth pagesize of Nth THP */ 414 - for (i = 1; i < 4; i++) { 415 - pte_mapped2 = mremap(one_page + pmd_pagesize * i + pagesize * i, 416 - pagesize, pagesize, 417 - MREMAP_MAYMOVE|MREMAP_FIXED, 418 - pte_mapped + pagesize * i); 419 - if (pte_mapped2 == MAP_FAILED) 420 - ksft_exit_fail_msg("mremap failed: %s\n", strerror(errno)); 400 + if (thp_area == MAP_FAILED) { 401 + ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno)); 402 + return; 421 403 } 422 404 423 - /* smap does not show THPs after mremap, use kpageflags instead */ 424 - thp_size = 0; 425 - for (i = 0; i < pagesize * 4; i++) 426 - if (i % pagesize == 0 && 427 - is_backed_by_folio(&pte_mapped[i], pmd_order, pagemap_fd, kpageflags_fd)) 428 - thp_size++; 405 + madvise(thp_area, thp_area_size, MADV_HUGEPAGE); 429 406 430 - if (thp_size != 4) 431 - ksft_exit_fail_msg("Some THPs are missing during mremap\n"); 407 + for (i = 0; i < thp_area_size; i++) 408 + thp_area[i] = (char)i; 432 409 433 - /* split all remapped THPs */ 434 - write_debugfs(PID_FMT, getpid(), (uint64_t)pte_mapped, 435 - (uint64_t)pte_mapped + pagesize * 4, 0); 436 - 437 - /* smap does not show THPs after mremap, use kpageflags instead */ 438 - thp_size = 0; 439 - for (i = 0; i < pagesize * 4; i++) { 440 - if (pte_mapped[i] != (char)i) 441 - ksft_exit_fail_msg("%ld byte corrupted\n", i); 442 - 443 - if (i % pagesize == 0 && 444 - !is_backed_by_folio(&pte_mapped[i], 0, pagemap_fd, kpageflags_fd)) 445 - thp_size++; 410 + if (!check_huge_anon(thp_area, nr_thps, pmd_pagesize)) { 411 + ksft_test_result_skip("Not all THPs allocated\n"); 412 + goto out; 446 413 } 447 414 448 - if (thp_size) 449 - ksft_exit_fail_msg("Still %ld THPs not split\n", thp_size); 415 + /* 416 + * To challenge spitting code, we will mremap a single page of each 417 + * THP (page[i] of thp[i]) in the thp_area into page_area. This will 418 + * replace the PMD mappings in the thp_area by PTE mappings first, 419 + * but leaving the THP unsplit, to then create a page-sized hole in 420 + * the thp_area. 421 + * We will then manually trigger splitting of all THPs through the 422 + * single mremap'ed pages of each THP in the page_area. 423 + */ 424 + page_area = mmap(NULL, page_area_size, PROT_READ | PROT_WRITE, 425 + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 426 + if (page_area == MAP_FAILED) { 427 + ksft_test_result_fail("Fail to allocate memory: %s\n", strerror(errno)); 428 + goto out; 429 + } 430 + 431 + for (i = 0; i < nr_thps; i++) { 432 + tmp = mremap(thp_area + pmd_pagesize * i + pagesize * i, 433 + pagesize, pagesize, MREMAP_MAYMOVE|MREMAP_FIXED, 434 + page_area + pagesize * i); 435 + if (tmp != MAP_FAILED) 436 + continue; 437 + ksft_test_result_fail("mremap failed: %s\n", strerror(errno)); 438 + goto out; 439 + } 440 + 441 + /* 442 + * Verify that our THPs were not split yet. Note that 443 + * check_huge_anon() cannot be used as it checks for PMD mappings. 444 + */ 445 + for (i = 0; i < nr_thps; i++) { 446 + if (is_backed_by_folio(page_area + i * pagesize, pmd_order, 447 + pagemap_fd, kpageflags_fd)) 448 + continue; 449 + ksft_test_result_fail("THP %zu missing after mremap\n", i); 450 + goto out; 451 + } 452 + 453 + /* Split all THPs through the remapped pages. */ 454 + write_debugfs(PID_FMT, getpid(), (uint64_t)page_area, 455 + (uint64_t)page_area + page_area_size, 0); 456 + 457 + /* Corruption during mremap or split? */ 458 + for (i = 0; i < page_area_size; i++) { 459 + if (page_area[i] == (char)i) 460 + continue; 461 + ksft_test_result_fail("%zu byte corrupted\n", i); 462 + goto out; 463 + } 464 + 465 + /* Split failed? */ 466 + for (i = 0; i < nr_thps; i++) { 467 + if (is_backed_by_folio(page_area + i * pagesize, 0, 468 + pagemap_fd, kpageflags_fd)) 469 + continue; 470 + ksft_test_result_fail("THP %zu not split\n", i); 471 + } 450 472 451 473 ksft_test_result_pass("Split PTE-mapped huge pages successful\n"); 452 - munmap(one_page, len); 474 + out: 475 + munmap(thp_area, thp_area_size); 476 + if (page_area != MAP_FAILED) 477 + munmap(page_area, page_area_size); 453 478 } 454 479 455 480 static void split_file_backed_thp(int order)