On Sat, Aug 15, 2026 at 02:58:49AM +0100, Kiryl Shutsemau wrote: > From: "Kiryl Shutsemau (Meta)" <[email protected]> > > Checking that an address range is backed by a folio of a given order is > useful to any test that builds or collapses large folios. mTHP collapse > coverage in the khugepaged selftest needs exactly that. > > split_huge_page_test.c already has the building block: > is_backed_by_folio() reads the compound head and tail flags from > /proc/kpageflags to classify the folio behind a page. > > Move it into vm_util so other tests can use it. No functional change. > > Assisted-by: Claude-Code:claude-opus-5 > Acked-by: Mike Rapoport (Microsoft) <[email protected]> > Tested-by: Muhammad Usama Anjum <[email protected]> > Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
LGTM so: Acked-by: Lorenzo Stoakes (ARM) <[email protected]> > --- > .../selftests/mm/split_huge_page_test.c | 62 ------------------- > tools/testing/selftests/mm/vm_util.c | 62 +++++++++++++++++++ > tools/testing/selftests/mm/vm_util.h | 2 + > 3 files changed, 64 insertions(+), 62 deletions(-) > > diff --git a/tools/testing/selftests/mm/split_huge_page_test.c > b/tools/testing/selftests/mm/split_huge_page_test.c > index 86a603692826..0adfe7dde7e5 100644 > --- a/tools/testing/selftests/mm/split_huge_page_test.c > +++ b/tools/testing/selftests/mm/split_huge_page_test.c > @@ -42,68 +42,6 @@ const char *kpageflags_proc = "/proc/kpageflags"; > int pagemap_fd; > int kpageflags_fd; > > -static bool is_backed_by_folio(char *vaddr, int order, int pagemap_fd, > - int kpageflags_fd) > -{ > - const uint64_t folio_head_flags = KPF_THP | KPF_COMPOUND_HEAD; > - const uint64_t folio_tail_flags = KPF_THP | KPF_COMPOUND_TAIL; > - const unsigned long nr_pages = 1UL << order; > - unsigned long pfn_head; > - uint64_t pfn_flags; > - unsigned long pfn; > - unsigned long i; > - > - pfn = pagemap_get_pfn(pagemap_fd, vaddr); > - > - /* non present page */ > - if (pfn == -1UL) > - return false; > - > - if (pageflags_get(pfn, kpageflags_fd, &pfn_flags)) > - goto fail; > - > - /* check for order-0 pages */ > - if (!order) { > - if (pfn_flags & (folio_head_flags | folio_tail_flags)) > - return false; > - return true; > - } > - > - /* non THP folio */ > - if (!(pfn_flags & KPF_THP)) > - return false; > - > - pfn_head = pfn & ~(nr_pages - 1); > - > - if (pageflags_get(pfn_head, kpageflags_fd, &pfn_flags)) > - goto fail; > - > - /* head PFN has no compound_head flag set */ > - if ((pfn_flags & folio_head_flags) != folio_head_flags) > - return false; > - > - /* check all tail PFN flags */ > - for (i = 1; i < nr_pages; i++) { > - if (pageflags_get(pfn_head + i, kpageflags_fd, &pfn_flags)) > - goto fail; > - if ((pfn_flags & folio_tail_flags) != folio_tail_flags) > - return false; > - } > - > - /* > - * check the PFN after this folio, but if its flags cannot be obtained, > - * assume this folio has the expected order > - */ > - if (pageflags_get(pfn_head + nr_pages, kpageflags_fd, &pfn_flags)) > - return true; > - > - /* If we find another tail page, then the folio is larger. */ > - return (pfn_flags & folio_tail_flags) != folio_tail_flags; > -fail: > - ksft_exit_fail_msg("Failed to get folio info\n"); > - return false; > -} > - > static int check_after_split_folio_orders(char *vaddr_start, size_t len, > int pagemap_fd, int kpageflags_fd, int orders[], int nr_orders) > { > diff --git a/tools/testing/selftests/mm/vm_util.c > b/tools/testing/selftests/mm/vm_util.c > index 80bc9f597b52..5db1a7774f49 100644 > --- a/tools/testing/selftests/mm/vm_util.c > +++ b/tools/testing/selftests/mm/vm_util.c > @@ -494,6 +494,68 @@ int pageflags_get(unsigned long pfn, int kpageflags_fd, > uint64_t *flags) > return 0; > } > > +bool is_backed_by_folio(char *vaddr, int order, int pagemap_fd, > + int kpageflags_fd) > +{ > + const uint64_t folio_head_flags = KPF_THP | KPF_COMPOUND_HEAD; > + const uint64_t folio_tail_flags = KPF_THP | KPF_COMPOUND_TAIL; > + const unsigned long nr_pages = 1UL << order; > + unsigned long pfn_head; > + uint64_t pfn_flags; > + unsigned long pfn; > + unsigned long i; > + > + pfn = pagemap_get_pfn(pagemap_fd, vaddr); > + > + /* non present page */ > + if (pfn == -1UL) > + return false; > + > + if (pageflags_get(pfn, kpageflags_fd, &pfn_flags)) > + goto fail; > + > + /* check for order-0 pages */ > + if (!order) { > + if (pfn_flags & (folio_head_flags | folio_tail_flags)) > + return false; > + return true; > + } > + > + /* non THP folio */ > + if (!(pfn_flags & KPF_THP)) > + return false; > + > + pfn_head = pfn & ~(nr_pages - 1); > + > + if (pageflags_get(pfn_head, kpageflags_fd, &pfn_flags)) > + goto fail; > + > + /* head PFN has no compound_head flag set */ > + if ((pfn_flags & folio_head_flags) != folio_head_flags) > + return false; > + > + /* check all tail PFN flags */ > + for (i = 1; i < nr_pages; i++) { > + if (pageflags_get(pfn_head + i, kpageflags_fd, &pfn_flags)) > + goto fail; > + if ((pfn_flags & folio_tail_flags) != folio_tail_flags) > + return false; > + } > + > + /* > + * check the PFN after this folio, but if its flags cannot be obtained, > + * assume this folio has the expected order > + */ > + if (pageflags_get(pfn_head + nr_pages, kpageflags_fd, &pfn_flags)) > + return true; > + > + /* If we find another tail page, then the folio is larger. */ > + return (pfn_flags & folio_tail_flags) != folio_tail_flags; > +fail: > + ksft_exit_fail_msg("Failed to get folio info\n"); > + return false; > +} > + > /* If `ioctls' non-NULL, the allowed ioctls will be returned into the var */ > int uffd_register_with_ioctls(int uffd, void *addr, uint64_t len, > bool miss, bool wp, bool minor, uint64_t *ioctls) > diff --git a/tools/testing/selftests/mm/vm_util.h > b/tools/testing/selftests/mm/vm_util.h > index 9a49af88702e..56a28ce7d029 100644 > --- a/tools/testing/selftests/mm/vm_util.h > +++ b/tools/testing/selftests/mm/vm_util.h > @@ -97,6 +97,8 @@ int64_t allocate_transhuge(void *ptr, int pagemap_fd); > int pageflags_get(unsigned long pfn, int kpageflags_fd, uint64_t *flags); > int gather_folio_orders(char *vaddr_start, size_t len, > int pagemap_fd, int kpageflags_fd, int orders[], int nr_orders); > +bool is_backed_by_folio(char *vaddr, int order, int pagemap_fd, > + int kpageflags_fd); > > int uffd_register(int uffd, void *addr, uint64_t len, > bool miss, bool wp, bool minor); > -- > 2.54.0 > -- Cheers, Lorenzo

