From: "Kiryl Shutsemau (Meta)" <[email protected]>

The khugepaged selftest is about to gain mTHP collapse coverage, which
needs to verify that a VA range is backed by a folio of a given order.
split_huge_page_test.c already has the building block for that:
is_backed_by_folio() classifies the folio backing a page via
/proc/kpageflags compound head/tail flags.

Move it into vm_util so other tests can use it. No functional change.

Assisted-by: Claude-Code:claude-opus-5
Signed-off-by: Kiryl Shutsemau (Meta) <[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 32b991472f74..9b3885bd001b 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 vaddr_pageflags_get(char *vaddr, int pagemap_fd, int kpageflags_fd,
                uint64_t *flags)
 {
diff --git a/tools/testing/selftests/mm/vm_util.c 
b/tools/testing/selftests/mm/vm_util.c
index ef1ea11981a7..343a15e25a9f 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -303,6 +303,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 7799154b67ee..5eb90e0d1d13 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -95,6 +95,8 @@ bool check_huge_file(void *addr, int nr_hpages, uint64_t 
hpage_size);
 bool check_huge_shmem(void *addr, int nr_hpages, uint64_t hpage_size);
 int64_t allocate_transhuge(void *ptr, int pagemap_fd);
 int pageflags_get(unsigned long pfn, int kpageflags_fd, uint64_t *flags);
+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


Reply via email to