From: "Kiryl Shutsemau (Meta)" <[email protected]> The mm selftests had two ways to check that a range came out as folios of a given order. check_huge_anon() and check_huge_file() counted folios of the order in the range. is_range_backed_by_order() checked each window for a folio with its head at the window start. Baolin found the two sets in khugepaged.c confusing [1], and the answer at the time was to merge them once Yeoreum's rewrite of check_huge_*() on top of pagemap and kpageflags landed. It is in mm-new now.
Make check_huge() check windows below the PMD size, route every caller through it, and make is_range_backed_by_order() an internal of vm_util.c. The split test's count-based check goes the same way, which also makes it notice a split at the wrong offset. On the way check_huge() stops reopening pagemap and kpageflags on every call, which was the other reason the separate helper existed. Yeoreum's HPAGE_SIZE series [2] renames read_pmd_pagesize() to pmd_psize(); the only overlap is the one call in __check_huge(). Tested on mm-new 2589c5593c20 with KASAN, in 16G guests, x86-64/4K under KVM and arm64/64K under TCG: the khugepaged matrix at every order, split_huge_page_test, pagemap_ioctl and khugepaged all:all on tmpfs pass with the same counts as before. v2: - Drop the PMD size caching from patch 1; Yeoreum's series caches it in pmd_psize() (Zi) - folio_order_check: skip again when /proc/kpageflags is not readable (Sashiko) - kpageflags_fd_get(): return early instead of nesting the open v1: https://lore.kernel.org/all/[email protected]/ [1] https://lore.kernel.org/all/[email protected]/ [2] https://lore.kernel.org/all/[email protected]/ Kiryl Shutsemau (Meta) (4): selftests/mm: open pagemap and kpageflags once for check_huge() selftests/mm: check sub-PMD ranges window by window in check_huge() selftests/mm: check collapse results through check_huge() only selftests/mm: check split results by position, drop gather_folio_orders() .../testing/selftests/mm/folio_order_check.c | 29 +- tools/testing/selftests/mm/khugepaged.c | 47 ++- .../selftests/mm/khugepaged_sync_check.c | 7 +- .../selftests/mm/split_huge_page_test.c | 104 +++--- tools/testing/selftests/mm/vm_util.c | 314 ++++++------------ tools/testing/selftests/mm/vm_util.h | 7 +- 6 files changed, 173 insertions(+), 335 deletions(-) Range-diff against v1: 1: 887d475288bf ! 1: 058de2172bde selftests/mm: open pagemap and kpageflags once for check_huge() @@ Commit message selftests/mm: open pagemap and kpageflags once for check_huge() check_huge_anon() and check_huge_file() open /proc/self/pagemap and - /proc/kpageflags on every call and read the PMD size from sysfs on top. - The khugepaged test calls them hundreds of times. + /proc/kpageflags on every call. The khugepaged test calls them hundreds + of times. Open both once and keep the descriptors. A pagemap descriptor is tied to the mm of the process that opened it, and the khugepaged fork() cases call check_huge() from the child, so reopen it when getpid() changes. - Cache the PMD size in read_pmd_pagesize() as well. - Assisted-by: LLM Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]> @@ tools/testing/selftests/mm/vm_util.c +{ + static int fd = -1; + -+ if (fd < 0) { -+ fd = open(KPAGEFLAGS_PATH, O_RDONLY); -+ if (fd < 0) -+ ksft_exit_fail_msg("open kpageflags fail\n"); -+ } ++ if (fd >= 0) ++ return fd; ++ ++ fd = open(KPAGEFLAGS_PATH, O_RDONLY); ++ if (fd < 0) ++ ksft_exit_fail_msg("open kpageflags fail\n"); + + return fd; +} @@ tools/testing/selftests/mm/vm_util.c uint64_t pagemap_get_entry(int fd, char *start) { const unsigned long pfn = (unsigned long)start / getpagesize(); -@@ tools/testing/selftests/mm/vm_util.c: bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len) - - uint64_t read_pmd_pagesize(void) - { -+ static uint64_t pmd_pagesize; - int fd; - char buf[20]; - ssize_t num_read; - -+ if (pmd_pagesize) -+ return pmd_pagesize; -+ - fd = open(PMD_SIZE_FILE_PATH, O_RDONLY); - if (fd == -1) - return 0; -@@ tools/testing/selftests/mm/vm_util.c: uint64_t read_pmd_pagesize(void) - buf[num_read] = '\0'; - close(fd); - -- return strtoul(buf, NULL, 10); -+ pmd_pagesize = strtoul(buf, NULL, 10); -+ return pmd_pagesize; - } - - unsigned long rss_anon(void) @@ tools/testing/selftests/mm/vm_util.c: static bool check_huge_type(uint64_t categories, enum check_huge_type type) static bool __check_huge(void *addr, size_t len, int nr_hpages, uint64_t hpage_size, enum check_huge_type type) 2: e89550a21307 = 2: a95eb5e9e2c8 selftests/mm: check sub-PMD ranges window by window in check_huge() 3: 3988e8ff5c3b ! 3: 40aa2e377b65 selftests/mm: check collapse results through check_huge() only @@ tools/testing/selftests/mm/folio_order_check.c: int main(void) - kpageflags_fd = open("/proc/kpageflags", O_RDONLY); - if (kpageflags_fd < 0) - ksft_exit_skip("open(/proc/kpageflags) requires root\n"); -- ++ if (access("/proc/kpageflags", R_OK)) ++ ksft_exit_skip("/proc/kpageflags requires root\n"); + orders = thp_supported_orders(); if (!orders) - ksft_exit_skip("No supported THP orders\n"); ## tools/testing/selftests/mm/khugepaged.c ## @@ tools/testing/selftests/mm/khugepaged.c: static int collapse_order; 4: 898256c09252 = 4: 405414814409 selftests/mm: check split results by position, drop gather_folio_orders() base-commit: 2589c5593c200e5146db848730baa1d7dd0c9f4e -- 2.54.0

