On 9/21/26 12:40, 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. > > Instead of relying on /proc/self/smaps, use /proc/self/pagemap and > /proc/kpageflags to detect huge-page mappings and large folios: > > 1. If hpage_size == pmd_pagesize, check PAGE_IS_HUGE instead of > using check_large_folios(), since only the mapping type matters. > This identifies PMD-mapped huge pages. > 2. Otherwise, use check_large_folios() to detect large folios. This > covers mTHP cases. > 3. Check the folio flags according to the type of huge page. > > Since shmem pages are also file-backed, simply check whether the page > is file-backed. > > Suggested-by: David Hildenbrand (Arm) <[email protected]> > Suggested-by: Zi Yan <[email protected]>
Do we need a Fixes: tag? > Signed-off-by: Yeoreum Yun <[email protected]> > --- > tools/testing/selftests/mm/vm_util.c | 137 > +++++++++++++++++++++-------------- > 1 file changed, 84 insertions(+), 53 deletions(-) > > diff --git a/tools/testing/selftests/mm/vm_util.c > b/tools/testing/selftests/mm/vm_util.c > index 4821a35630363..a7c5caf6925e0 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) The function used two tab indent for a reason ;) Use two tabs also in the functions you change below. [...] > > -bool check_huge_file(void *addr, size_t len, int nr_hpages, uint64_t > hpage_size) > +static bool __check_huge(void *addr, size_t len, int nr_hpages, > + uint64_t hpage_size, enum check_huge_type type) > { > - uint64_t pmd_pagesize = read_pmd_pagesize(); > + bool ret = false; > + int pagemap_fd, kpageflags_fd; > + int nr_pmd_mappings = 0; > + uint64_t pmd_pagesize, scan_mapping_size; > + uint64_t categories, kpf; > + unsigned long pfn; > + bool check_pmd_mapping, allow_nonpresent; > + 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, "FilePmdMapped:", nr_hpages, > hpage_size); > + check_pmd_mapping = (hpage_size == pmd_pagesize); No need for () > + scan_mapping_size = (nr_hpages > 0) ? hpage_size : psize(); > + /* Some mTHP tests check a partially populated PMD-sized range. */ > + allow_nonpresent = (uint64_t)nr_hpages * hpage_size < len; > > - return check_large_folios(addr, len, nr_hpages, hpage_size); > + pagemap_fd = open(PAGEMAP_PATH, O_RDONLY); > + if (pagemap_fd < 0) > + ksft_exit_fail_msg("open pagemap fail\n"); > + > + kpageflags_fd = open(KPAGEFLAGS_PATH, O_RDONLY); > + if (kpageflags_fd < 0) > + ksft_exit_fail_msg("open kpageflags fail\n"); > + > + if (!check_pmd_mapping && > + !check_large_folios(pagemap_fd, kpageflags_fd, > + addr, len, nr_hpages, hpage_size)) > + goto out; > + > + for (; start < end; start += scan_mapping_size) { > + categories = pagemap_scan_get_categories(pagemap_fd, start); > + pfn = pagemap_get_pfn(pagemap_fd, start); > + if (pfn == -1UL) { > + if (!allow_nonpresent) > + goto out; > + else > + continue; > + } > + if (pageflags_get(pfn, kpageflags_fd, &kpf)) > + ksft_exit_fail_msg("read kpageflags: %s\n", > strerror(errno)); > + if (check_pmd_mapping && (categories & PAGE_IS_HUGE)) > + nr_pmd_mappings++; > + if (kpf & KPF_COMPOUND_TAIL) > + continue; > + if (!check_huge_type(categories, kpf, type)) > + goto out; > + } > + > + if (check_pmd_mapping && (nr_pmd_mappings != nr_hpages)) > + goto out; There is way too much happening here, which makes this rather hard to review. Why can't we just focus on the smaps change for now? I.e., something like the following (untested) diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c index 4821a35630363..5d348d6985026 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -351,24 +351,6 @@ 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) { @@ -410,20 +392,34 @@ static bool check_large_folios(void *addr, size_t len, int nr_hpages, return ret; } -bool check_huge_anon(void *addr, size_t len, int nr_hpages, uint64_t hpage_size) +static bool __check_pmds(void *start, size_t len, int expected_file_pmds, + int expected_anon_pmds, uint64_t pmd_pagesize) { - uint64_t pmd_pagesize = read_pmd_pagesize(); + int found_anon_pmds = 0, found_file_pmds = 0; + int pagemap_fd; + void *addr; - if (!pmd_pagesize) - ksft_exit_fail_msg("reading PMD pagesize failed\n"); + pagemap_fd = open(PAGEMAP_PATH, O_RDONLY); + if (pagemap_fd < 0) + ksft_exit_fail_msg("open pagemap fail\n"); - if (hpage_size == pmd_pagesize) - return __check_pmd_huge(addr, "AnonHugePages: ", nr_hpages, hpage_size); + for (addr = start; addr < start + len; addr += pmd_pagesize) { + const uint64_t categories = pagemap_scan_get_categories(pagemap_fd, addr); - return check_large_folios(addr, len, nr_hpages, hpage_size); + if (!(categories & PAGE_IS_HUGE)) + continue; + if (categories & PAGE_IS_FILE) + found_file_pmds++; + else + found_anon_pmds++; + } + + close(pagemap_fd); + return found_anon_pmds == expected_anon_pmds && + found_file_pmds == expected_file_pmds; } -bool check_huge_file(void *addr, size_t len, int nr_hpages, uint64_t hpage_size) +bool check_huge_anon(void *addr, size_t len, int nr_hpages, uint64_t hpage_size) { uint64_t pmd_pagesize = read_pmd_pagesize(); @@ -431,12 +427,12 @@ bool check_huge_file(void *addr, size_t len, int nr_hpages, uint64_t hpage_size) ksft_exit_fail_msg("reading PMD pagesize failed\n"); if (hpage_size == pmd_pagesize) - return __check_pmd_huge(addr, "FilePmdMapped:", nr_hpages, hpage_size); + return __check_pmds(addr, len, 0, nr_hpages, pmd_pagesize); return check_large_folios(addr, len, nr_hpages, hpage_size); } -bool check_huge_shmem(void *addr, size_t len, int nr_hpages, uint64_t hpage_size) +bool check_huge_file(void *addr, size_t len, int nr_hpages, uint64_t hpage_size) { uint64_t pmd_pagesize = read_pmd_pagesize(); @@ -444,11 +440,16 @@ bool check_huge_shmem(void *addr, size_t len, int nr_hpages, uint64_t hpage_size ksft_exit_fail_msg("reading PMD pagesize failed\n"); if (hpage_size == pmd_pagesize) - return __check_pmd_huge(addr, "ShmemPmdMapped:", nr_hpages, hpage_size); + return __check_pmds(addr, len, nr_hpages, 0, pmd_pagesize); return check_large_folios(addr, len, nr_hpages, hpage_size); } +bool check_huge_shmem(void *addr, size_t len, int nr_hpages, uint64_t hpage_size) +{ + return check_huge_file(addr, len, nr_hpages, hpage_size); +} + int64_t allocate_transhuge(void *ptr, int pagemap_fd) { uint64_t ent[2]; -- 2.43.0 -- Cheers, David

