On 8/27/26 10:28, Baolin Wang wrote: > > > On 8/26/26 8:24 PM, Yeoreum Yun wrote: >> Since glibc commit 321e1fc73f (“malloc: Enable 2MB THP by default on >> AArch64”), >> glibc may call madvise(MADV_HUGEPAGE) for sufficiently large allocations >> made by memalign(). >> >> The underlying VMA may start at a different address from the aligned >> address returned by memalign(). Furthermore, a subsequent >> madvise(MADV_HUGEPAGE) call does not split the VMA because the flag is >> already set. >> >> This causes split_huge_page_test to fail because the check_huge_xxx() >> helpers incorrectly require the address returned by memalign() to >> match the VMA start address reported in /proc/self/smaps. >> >> Fix this by using /proc/self/pagemap and /proc/kpageflags instead of >> /proc/self/smaps to detect huge pages. >> >> Reported-by: David Hildenbrand (Arm) <[email protected]> >> Signed-off-by: Yeoreum Yun <[email protected]> >> --- >> tools/testing/selftests/mm/vm_util.c | 130 >> ++++++++++++++++++++--------------- >> tools/testing/selftests/mm/vm_util.h | 1 + >> 2 files changed, 77 insertions(+), 54 deletions(-) >> >> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/ >> mm/vm_util.c >> index 4821a3563036..1d0959b3b9e8 100644 >> --- a/tools/testing/selftests/mm/vm_util.c >> +++ b/tools/testing/selftests/mm/vm_util.c >> @@ -351,31 +351,13 @@ char *__get_smap_entry(void *addr, const char *pattern, >> char *buf, size_t len) >> return entry; >> } >> -static bool __check_pmd_huge(void *addr, char *pattern, int nr_hpages, >> - uint64_t hpage_size) >> -{ >> - char buffer[MAX_LINE_LENGTH]; >> - uint64_t thp = -1; >> - char *entry; >> - >> - entry = __get_smap_entry(addr, pattern, buffer, sizeof(buffer)); >> - if (!entry) >> - goto err_out; >> - >> - if (sscanf(entry, "%9" SCNu64 " kB", &thp) != 1) >> - ksft_exit_fail_msg("Reading smap error\n"); >> - >> -err_out: >> - return thp == (nr_hpages * (hpage_size >> 10)); >> -} >> - >> -static bool check_large_folios(void *addr, size_t len, int nr_hpages, >> - uint64_t hpage_size) >> +static bool check_large_folios(int pagemap_fd, int kpageflags_fd, >> + void *addr, size_t len, int nr_hpages, >> + uint64_t hpage_size) >> { >> int order = 0, pagesize = getpagesize(); >> unsigned int nr_pages = hpage_size / pagesize; >> int orders[MAX_NR_ORDERS], status; >> - int pagemap_fd, kpageflags_fd; >> bool ret = false; >> if (!nr_pages) >> @@ -386,15 +368,6 @@ static bool check_large_folios(void *addr, size_t len, >> int nr_hpages, >> ksft_exit_fail_msg("invalid order\n"); >> memset(orders, 0, sizeof(int) * MAX_NR_ORDERS); >> - pagemap_fd = open(PAGEMAP_PATH, O_RDONLY); >> - if (pagemap_fd == -1) >> - ksft_exit_fail_msg("read pagemap fail\n"); >> - >> - kpageflags_fd = open(KPAGEFLAGS_PATH, O_RDONLY); >> - if (kpageflags_fd == -1) { >> - close(pagemap_fd); >> - ksft_exit_fail_msg("read kpageflags fail\n"); >> - } >> status = gather_folio_orders(addr, len, pagemap_fd, >> kpageflags_fd, orders, MAX_NR_ORDERS); >> @@ -405,48 +378,97 @@ static bool check_large_folios(void *addr, size_t len, >> int nr_hpages, >> ret = true; >> out: >> - close(pagemap_fd); >> - close(kpageflags_fd); >> return ret; >> } >> -bool check_huge_anon(void *addr, size_t len, int nr_hpages, uint64_t >> hpage_size) >> +enum check_huge_type { >> + CHECK_HUGE_ANON, >> + CHECK_HUGE_FILE, >> + CHECK_HUGE_SHMEM, >> +}; >> + >> +static bool __check_pmd_huge(void *addr, size_t len, int nr_hpages, >> + uint64_t hpage_size, enum check_huge_type type) > > The original __check_pmd_huge() is only for PMD-sized large folios, but now it > not only checks PMD-sized large folios but also mTHP large folios, which I > find > confusing. Please keep its original semantics, and only check PMD-sized large > folios. > >> { >> - uint64_t pmd_pagesize = read_pmd_pagesize(); >> + int pagemap_fd, kpageflags_fd; >> + uint64_t pmd_pagesize, granule; >> + uint64_t categories, kpf; >> + unsigned long pfn; >> + bool check_large, huge_mapped; >> + char *start = addr; >> + char *end = start + len; >> + pmd_pagesize = read_pmd_pagesize(); >> if (!pmd_pagesize) >> ksft_exit_fail_msg("reading PMD pagesize failed\n"); >> - if (hpage_size == pmd_pagesize) >> - return __check_pmd_huge(addr, "AnonHugePages: ", nr_hpages, >> hpage_size); >> + if (nr_hpages > 0) { >> + check_large = true; >> + granule = hpage_size; >> + } else { >> + check_large = false; >> + granule = psize(); >> + } > > This is incorrect for the mTHP large folio check. I already hit a selftest > failure. Please test your patches before sending them out. > > [root@]./khugepaged -c 4 mthp_khugepaged:anon > TAP version 13 > # Save THP and khugepaged settings... OK > 1..4 > # Allocate huge page on fault... OK > # Split huge PMD on MADV_DONTNEED... OK > ok 1 allocate on fault and split > # > # Run test: collapse_full (mthp_khugepaged:anon) > # Collapse multiple fully populated PTE table.... OK > ok 2 collapse_full > # > # Run test: collapse_empty (mthp_khugepaged:anon) > # Do not collapse empty PTE table.... OK > ok 3 collapse_empty > # > # Run test: collapse_single_mthp (mthp_khugepaged:anon) > # Collapse PTE table with half PTE entries present.... Fail > not ok 4 collapse_single_mthp > # Totals: pass:3 fail:1 xfail:0 xpass:0 skip:0 error:0
FWIW, the CI flags this as well: https://github.com/linux-mm/linux-mm/actions/runs/33028595020/job/98375618491 -- Cheers, David

