Instead of just checking the existence of PMD folios before and after folio split tests, use check_folio_orders() to check after-split folio orders. The following tests are not changed: 1. split_pte_mapped_thp: the test already uses kpageflags to check; 2. split_file_backed_thp: no vaddr available. Signed-off-by: Zi Yan --- .../selftests/mm/split_huge_page_test.c | 98 ++++++++++++++----- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 5ab488fab1cd..161108717f1c 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -25,6 +25,10 @@ uint64_t pagesize; unsigned int pageshift; uint64_t pmd_pagesize; +unsigned int pmd_order; +unsigned int max_order; + +#define NR_ORDERS (max_order + 1) #define SPLIT_DEBUGFS "/sys/kernel/debug/split_huge_pages" #define SMAP_PATH "/proc/self/smaps" @@ -36,6 +40,11 @@ uint64_t pmd_pagesize; #define GET_ORDER(nr_pages) (31 - __builtin_clz(nr_pages)) +const char *pagemap_proc = "/proc/self/pagemap"; +const char *kpageflags_proc = "/proc/kpageflags"; +int pagemap_fd; +int kpageflags_fd; + int is_backed_by_thp(char *vaddr, int pagemap_file, int kpageflags_file) { uint64_t paddr; @@ -151,6 +160,11 @@ void split_pmd_thp_to_order(int order) char *one_page; size_t len = 4 * pmd_pagesize; size_t i; + int *orders; + + orders = (int *)malloc(sizeof(int) * NR_ORDERS); + if (!orders) + ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno)); one_page = memalign(pmd_pagesize, len); if (!one_page) @@ -172,12 +186,20 @@ void split_pmd_thp_to_order(int order) if (one_page[i] != (char)i) ksft_exit_fail_msg("%ld byte corrupted\n", i); + memset(orders, 0, sizeof(int) * NR_ORDERS); + /* set expected orders */ + orders[order] = 4 << (pmd_order - order); + + if (check_folio_orders(one_page, len, pagemap_fd, kpageflags_fd, + orders, NR_ORDERS)) + ksft_exit_fail_msg("Unexpected THP split\n"); if (!check_huge_anon(one_page, 0, pmd_pagesize)) ksft_exit_fail_msg("Still AnonHugePages not split\n"); ksft_test_result_pass("Split huge pages to order %d successful\n", order); free(one_page); + free(orders); } void split_pte_mapped_thp(void) @@ -186,22 +208,6 @@ void split_pte_mapped_thp(void) size_t len = 4 * pmd_pagesize; uint64_t thp_size; size_t i; - const char *pagemap_template = "/proc/%d/pagemap"; - const char *kpageflags_proc = "/proc/kpageflags"; - char pagemap_proc[255]; - int pagemap_fd; - int kpageflags_fd; - - if (snprintf(pagemap_proc, 255, pagemap_template, getpid()) < 0) - ksft_exit_fail_msg("get pagemap proc error: %s\n", strerror(errno)); - - pagemap_fd = open(pagemap_proc, O_RDONLY); - if (pagemap_fd == -1) - ksft_exit_fail_msg("read pagemap: %s\n", strerror(errno)); - - kpageflags_fd = open(kpageflags_proc, O_RDONLY); - if (kpageflags_fd == -1) - ksft_exit_fail_msg("read kpageflags: %s\n", strerror(errno)); one_page = mmap((void *)(1UL << 30), len, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); @@ -259,8 +265,6 @@ void split_pte_mapped_thp(void) ksft_test_result_pass("Split PTE-mapped huge pages successful\n"); munmap(one_page, len); - close(pagemap_fd); - close(kpageflags_fd); } void split_file_backed_thp(int order) @@ -463,10 +467,16 @@ void split_thp_in_pagecache_to_order_at(size_t fd_size, const char *fs_loc, int order, int offset) { int fd; + char *split_addr; char *addr; size_t i; char testfile[INPUT_MAX]; int err = 0; + int *orders; + + orders = (int *)malloc(sizeof(int) * NR_ORDERS); + if (!orders) + ksft_exit_fail_msg("Fail to allocate memory: %s\n", strerror(errno)); err = snprintf(testfile, INPUT_MAX, "%s/test", fs_loc); @@ -474,16 +484,32 @@ void split_thp_in_pagecache_to_order_at(size_t fd_size, const char *fs_loc, ksft_exit_fail_msg("cannot generate right test file name\n"); err = create_pagecache_thp_and_fd(testfile, fd_size, &fd, &addr); - if (err) + if (err) { + free(orders); return; + } err = 0; - if (offset == -1) - write_debugfs(PID_FMT, getpid(), (uint64_t)addr, - (uint64_t)addr + fd_size, order); - else - write_debugfs(PID_FMT_OFFSET, getpid(), (uint64_t)addr, - (uint64_t)addr + fd_size, order, offset); + memset(orders, 0, sizeof(int) * NR_ORDERS); + if (offset == -1) { + for (split_addr = addr; split_addr < addr + fd_size; split_addr += pmd_pagesize) + write_debugfs(PID_FMT, getpid(), (uint64_t)split_addr, + (uint64_t)split_addr + pagesize, order); + + /* set expected orders */ + orders[order] = fd_size / (pagesize << order); + } else { + int times = fd_size / pmd_pagesize; + + for (split_addr = addr; split_addr < addr + fd_size; split_addr += pmd_pagesize) + write_debugfs(PID_FMT_OFFSET, getpid(), (uint64_t)split_addr, + (uint64_t)split_addr + pagesize, order, offset); + + /* set expected orders */ + for (i = order + 1; i < pmd_order; i++) + orders[i] = times; + orders[order] = 2 * times; + } for (i = 0; i < fd_size; i++) if (*(addr + i) != (char)i) { @@ -492,6 +518,14 @@ void split_thp_in_pagecache_to_order_at(size_t fd_size, const char *fs_loc, goto out; } + if (check_folio_orders(addr, fd_size, pagemap_fd, kpageflags_fd, orders, + NR_ORDERS)) { + ksft_print_msg("Unexpected THP split\n"); + err = 1; + goto out; + } + + if (!check_huge_file(addr, 0, pmd_pagesize)) { ksft_print_msg("Still FilePmdMapped not split\n"); err = EXIT_FAILURE; @@ -499,6 +533,7 @@ void split_thp_in_pagecache_to_order_at(size_t fd_size, const char *fs_loc, } out: + free(orders); munmap(addr, fd_size); close(fd); unlink(testfile); @@ -522,7 +557,6 @@ int main(int argc, char **argv) const char *fs_loc; bool created_tmp; int offset; - unsigned int max_order; unsigned int nr_pages; unsigned int tests; @@ -539,6 +573,7 @@ int main(int argc, char **argv) pagesize = getpagesize(); pageshift = ffs(pagesize) - 1; pmd_pagesize = read_pmd_pagesize(); + pmd_order = GET_ORDER(pmd_pagesize / pagesize); if (!pmd_pagesize) ksft_exit_fail_msg("Reading PMD pagesize failed\n"); @@ -547,6 +582,14 @@ int main(int argc, char **argv) tests = 2 + (max_order - 1) + (2 * max_order) + (max_order - 1) * 4 + 2; ksft_set_plan(tests); + pagemap_fd = open(pagemap_proc, O_RDONLY); + if (pagemap_fd == -1) + ksft_exit_fail_msg("read pagemap: %s\n", strerror(errno)); + + kpageflags_fd = open(kpageflags_proc, O_RDONLY); + if (kpageflags_fd == -1) + ksft_exit_fail_msg("read kpageflags: %s\n", strerror(errno)); + fd_size = 2 * pmd_pagesize; split_pmd_zero_pages(); @@ -571,6 +614,9 @@ int main(int argc, char **argv) split_thp_in_pagecache_to_order_at(fd_size, fs_loc, i, offset); cleanup_thp_fs(fs_loc, created_tmp); + close(pagemap_fd); + close(kpageflags_fd); + ksft_finished(); return 0; -- 2.47.2