On 12 Aug 2025, at 23:38, wang lian wrote: >> On Aug 12, 2025, at 23:55, Zi Yan <z...@nvidia.com> wrote: >> >> The helper gathers an folio order statistics of folios within a virtual >> address range and checks it against a given order list. It aims to provide >> a more precise folio order check instead of just checking the existence of >> PMD folios. >> >> Signed-off-by: Zi Yan <z...@nvidia.com> >> --- >> .../selftests/mm/split_huge_page_test.c | 4 +- >> tools/testing/selftests/mm/vm_util.c | 173 ++++++++++++++++++ >> tools/testing/selftests/mm/vm_util.h | 7 + >> 3 files changed, 181 insertions(+), 3 deletions(-) >> >> diff --git a/tools/testing/selftests/mm/split_huge_page_test.c >> b/tools/testing/selftests/mm/split_huge_page_test.c >> index 5d07b0b89226..63ac82f0b9e0 100644 >> --- a/tools/testing/selftests/mm/split_huge_page_test.c >> +++ b/tools/testing/selftests/mm/split_huge_page_test.c >> @@ -34,8 +34,6 @@ uint64_t pmd_pagesize; >> #define PID_FMT_OFFSET "%d,0x%lx,0x%lx,%d,%d" >> #define PATH_FMT "%s,0x%lx,0x%lx,%d" >> >> -#define PFN_MASK ((1UL<<55)-1) >> -#define KPF_THP (1UL<<22) >> #define GET_ORDER(nr_pages) (31 - __builtin_clz(nr_pages)) >> >> int is_backed_by_thp(char *vaddr, int pagemap_file, int kpageflags_file) >> @@ -49,7 +47,7 @@ int is_backed_by_thp(char *vaddr, int pagemap_file, int >> kpageflags_file) >> >> if (kpageflags_file) { >> pread(kpageflags_file, &page_flags, sizeof(page_flags), >> - (paddr & PFN_MASK) * sizeof(page_flags)); >> + PAGEMAP_PFN(paddr) * sizeof(page_flags)); >> >> return !!(page_flags & KPF_THP); >> } >> diff --git a/tools/testing/selftests/mm/vm_util.c >> b/tools/testing/selftests/mm/vm_util.c >> index 6a239aa413e2..4d952d1bc96d 100644 >> --- a/tools/testing/selftests/mm/vm_util.c >> +++ b/tools/testing/selftests/mm/vm_util.c >> @@ -338,6 +338,179 @@ int detect_hugetlb_page_sizes(size_t sizes[], int max) >> return count; >> } >> >> +static int get_pfn_flags(unsigned long pfn, int kpageflags_fd, uint64_t >> *flags) >> +{ >> + size_t count; >> + >> + count = pread(kpageflags_fd, flags, sizeof(*flags), >> + pfn * sizeof(*flags)); >> + >> + if (count != sizeof(*flags)) >> + return -1; >> + >> + return 0; >> +} >> + >> +static int get_page_flags(char *vaddr, int pagemap_fd, int kpageflags_fd, >> + uint64_t *flags) >> +{ >> + unsigned long pfn; >> + >> + pfn = pagemap_get_pfn(pagemap_fd, vaddr); >> + /* >> + * Treat non-present page as a page without any flag, so that >> + * gather_folio_orders() just record the current folio order. >> + */ >> + if (pfn == -1UL) { >> + *flags = 0; >> + return 1; >> + } >> + >> + if (get_pfn_flags(pfn, kpageflags_fd, flags)) >> + return -1; >> + >> + return 0; >> +} >> + >> +/* >> + * gather_folio_orders - scan through [vaddr_start, len) and record folio >> orders >> + * @vaddr_start: start vaddr >> + * @len: range length >> + * @pagemap_fd: file descriptor to /proc/<pid>/pagemap >> + * @kpageflags_fd: file descriptor to /proc/kpageflags >> + * @orders: output folio order array >> + * @nr_orders: folio order array size >> + * >> + * gather_folio_orders() scan through [vaddr_start, len) and check all >> folios >> + * within the range and record their orders. All order-0 pages will be >> recorded. >> + * Non-present vaddr is skipped. >> + * >> + * >> + * Return: 0 - no error, -1 - unhandled cases >> + */ >> +static int gather_folio_orders(char *vaddr_start, size_t len, >> + int pagemap_fd, int kpageflags_fd, >> + int orders[], int nr_orders) >> +{ >> + uint64_t page_flags = 0; >> + int cur_order = -1; >> + char *vaddr; >> + >> + if (!pagemap_fd || !kpageflags_fd) >> + return -1; >> + if (nr_orders <= 0) >> + return -1; >> + >> + for (vaddr = vaddr_start; vaddr < vaddr_start + len;) { >> + char *next_folio_vaddr; >> + int status; >> + >> + status = get_page_flags(vaddr, pagemap_fd, kpageflags_fd, >> + &page_flags); >> + if (status < 0) >> + return -1; >> + >> + /* skip non present vaddr */ >> + if (status == 1) { >> + vaddr += psize(); >> + continue; >> + } >> + >> + /* all order-0 pages with possible false postive (non folio) */ >> + if (!(page_flags & (KPF_COMPOUND_HEAD | KPF_COMPOUND_TAIL))) { >> + orders[0]++; >> + vaddr += psize(); >> + continue; >> + } >> + >> + /* skip non thp compound pages */ >> + if (!(page_flags & KPF_THP)) { >> + vaddr += psize(); >> + continue; >> + } >> + >> + /* vpn points to part of a THP at this point */ >> + if (page_flags & KPF_COMPOUND_HEAD) >> + cur_order = 1; >> + else { >> + /* not a head nor a tail in a THP? */ >> + if (!(page_flags & KPF_COMPOUND_TAIL)) >> + return -1; >> + >> + vaddr += psize(); >> + continue; >> + } >> + >> + next_folio_vaddr = vaddr + (1UL << (cur_order + pshift())); >> + >> + if (next_folio_vaddr >= vaddr_start + len) >> + break; >> + >> + while ((status = get_page_flags(next_folio_vaddr, pagemap_fd, >> + kpageflags_fd, >> + &page_flags)) >= 0) { >> + /* >> + * non present vaddr, next compound head page, or >> + * order-0 page >> + */ >> + if (status == 1 || >> + (page_flags & KPF_COMPOUND_HEAD) || >> + !(page_flags & (KPF_COMPOUND_HEAD | >> KPF_COMPOUND_TAIL))) { >> + if (cur_order < nr_orders) { >> + orders[cur_order]++; >> + cur_order = -1; >> + vaddr = next_folio_vaddr; >> + } >> + break; >> + } >> + >> + /* not a head nor a tail in a THP? */ >> + if (!(page_flags & KPF_COMPOUND_TAIL)) >> + return -1; >> + >> + cur_order++; >> + next_folio_vaddr = vaddr + (1UL << (cur_order + >> pshift())); >> + } >> + >> + if (status < 0) >> + return status; >> + } >> + if (cur_order > 0 && cur_order < nr_orders) >> + orders[cur_order]++; >> + return 0; >> +} >> + >> +int check_folio_orders(char *vaddr_start, size_t len, int pagemap_fd, >> + int kpageflags_fd, int orders[], int nr_orders) >> +{ >> + int *vaddr_orders; >> + int status; >> + int i; >> + >> + vaddr_orders = (int *)malloc(sizeof(int) * nr_orders); >> + >> + if (!vaddr_orders) >> + ksft_exit_fail_msg("Cannot allocate memory for vaddr_orders"); >> + >> + memset(vaddr_orders, 0, sizeof(int) * nr_orders); >> + status = gather_folio_orders(vaddr_start, len, pagemap_fd, >> + kpageflags_fd, vaddr_orders, nr_orders); >> + if (status) >> + goto out; >> + >> + status = 0; > > Nit. > It seems redundant. > Would you consider removing it for a bit more conciseness? > This doesn't block my approval, of course. > Reviewed-by: wang lian <lianux...@gmail.com>
Sure. Thanks. Best Regards, Yan, Zi