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

khugepaged.c checks collapse results in two ways.  Generic cases go
through the mem_ops check_huge() callback.  collapse_order_* cases call
is_range_backed_by_order() on descriptors of their own.  Baolin Wang
found that confusing.  The split only existed because check_huge()
counted folios instead of windows.

Now that check_huge() checks windows, the two give the same answer.
Use the callback for the collapse_order_* cases and drop the private
descriptors.

Convert khugepaged_sync_check and folio_order_check the same way.  The
latter still checks that each order is detected as that order, not as
the one below and not as order 0, only now through check_huge_anon().
At the PMD order that means the PMD-mapping check rather than the
page-flag walk.

is_range_backed_by_order() has no users outside vm_util.c left.  Make it
static and let it use the cached descriptors.

Assisted-by: LLM
Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
---
 .../testing/selftests/mm/folio_order_check.c  | 28 +++--------
 tools/testing/selftests/mm/khugepaged.c       | 47 ++++++++-----------
 .../selftests/mm/khugepaged_sync_check.c      |  7 +--
 tools/testing/selftests/mm/vm_util.c          | 19 +++-----
 tools/testing/selftests/mm/vm_util.h          |  2 -
 5 files changed, 34 insertions(+), 69 deletions(-)

diff --git a/tools/testing/selftests/mm/folio_order_check.c 
b/tools/testing/selftests/mm/folio_order_check.c
index 5eafbcc1b4f3..aa0586047620 100644
--- a/tools/testing/selftests/mm/folio_order_check.c
+++ b/tools/testing/selftests/mm/folio_order_check.c
@@ -1,13 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Self-check for the vm_util folio-order helpers, is_backed_by_folio() and
- * is_range_backed_by_order(), which the khugepaged mTHP cases use to detect
- * collapse results.  For every anon THP order the kernel supports, fault
- * memory in with only that order enabled and require the helpers to report
- * exactly that order.
+ * Self-check for check_huge_anon(), which the khugepaged mTHP cases use to
+ * tell collapse results.  For every anon THP order the kernel supports,
+ * fault memory in with only that order enabled and require the check to
+ * report exactly that order: not the order below it, and not order 0.
  */
 #define _GNU_SOURCE
-#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/mman.h>
@@ -17,9 +15,6 @@
 #include "vm_util.h"
 #include <mm/hugepage_settings.h>
 
-static int pagemap_fd;
-static int kpageflags_fd;
-
 static char *alloc_aligned(size_t size)
 {
        size_t len = size * 2;
@@ -56,22 +51,20 @@ static void check_order(int order)
        p = alloc_aligned(size);
        *p = 1;
 
-       if (!is_range_backed_by_order(p, size, order, pagemap_fd, 
kpageflags_fd)) {
+       if (!check_huge_anon(p, size, 1, size)) {
                ksft_print_msg("order %d not detected after fault\n", order);
                ok = false;
        }
 
        /* A lower order must be rejected: the folio is larger */
-       if (order && is_range_backed_by_order(p, size, order - 1,
-                                             pagemap_fd, kpageflags_fd)) {
+       if (order && check_huge_anon(p, size, 2, size / 2)) {
                ksft_print_msg("order %d also reported as order %d\n",
                               order, order - 1);
                ok = false;
        }
 
        /* A large folio must not pass as order 0 */
-       if (order && is_range_backed_by_order(p, size, 0,
-                                             pagemap_fd, kpageflags_fd)) {
+       if (order && check_huge_anon(p, size, 1 << order, psize())) {
                ksft_print_msg("order %d also reported as order 0\n", order);
                ok = false;
        }
@@ -93,13 +86,6 @@ int main(void)
        if (!thp_available())
                ksft_exit_skip("Transparent Hugepages not available\n");
 
-       pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
-       if (pagemap_fd < 0)
-               ksft_exit_fail_perror("open(/proc/self/pagemap)");
-       kpageflags_fd = open("/proc/kpageflags", O_RDONLY);
-       if (kpageflags_fd < 0)
-               ksft_exit_skip("open(/proc/kpageflags) requires root\n");
-
        orders = thp_supported_orders();
        if (!orders)
                ksft_exit_skip("No supported THP orders\n");
diff --git a/tools/testing/selftests/mm/khugepaged.c 
b/tools/testing/selftests/mm/khugepaged.c
index 61bd69d604d2..a5b682eca888 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -33,8 +33,6 @@ static int collapse_order;
 static bool collapse_order_set;
 static int collapse_orders[NR_ORDERS];
 static int nr_collapse_orders;
-static int pagemap_fd = -1;
-static int kpageflags_fd = -1;
 
 #define PID_SMAPS "/proc/self/smaps"
 #define TEST_FILE "collapse_test_file"
@@ -1330,19 +1328,20 @@ static void mthp_push_target_order(void)
        thp_push_settings(&settings);
 }
 
-static bool all_windows_at_order(void *p, size_t len)
+static bool all_windows_at_order(struct mem_ops *ops, void *p, size_t len)
 {
-       return is_range_backed_by_order(p, len, collapse_order,
-                                       pagemap_fd, kpageflags_fd);
+       size_t window = mthp_window_size();
+
+       return ops->check_huge(p, len, len / window, window);
 }
 
-static bool any_window_at_order(void *p, size_t len)
+static bool any_window_at_order(struct mem_ops *ops, void *p, size_t len)
 {
        size_t window = mthp_window_size();
        char *addr = p;
 
        for (; len >= window; addr += window, len -= window) {
-               if (all_windows_at_order(addr, window))
+               if (ops->check_huge(addr, window, 1, window))
                        return true;
        }
        return false;
@@ -1358,7 +1357,7 @@ static void collapse_order_single_window(struct 
collapse_context *c,
 
        p = ops->setup_area(1);
        ops->fault(p, window, 2 * window);
-       if (any_window_at_order(p, hpage_pmd_size))
+       if (any_window_at_order(ops, p, hpage_pmd_size))
                ksft_exit_fail_msg("Unexpected large folio after fault\n");
 
        if (madvise(p, hpage_pmd_size, MADV_HUGEPAGE))
@@ -1366,9 +1365,9 @@ static void collapse_order_single_window(struct 
collapse_context *c,
        ksft_print_msg("Collapse one fully populated window...");
        if (!khugepaged_full_pass(MTHP_PASS_TIMEOUT_S))
                fail("Timeout");
-       else if (all_windows_at_order(p + window, window) &&
-                !any_window_at_order(p, window) &&
-                !any_window_at_order(p + 2 * window,
+       else if (all_windows_at_order(ops, p + window, window) &&
+                !any_window_at_order(ops, p, window) &&
+                !any_window_at_order(ops, p + 2 * window,
                                      hpage_pmd_size - 2 * window))
                success("OK");
        else
@@ -1389,7 +1388,7 @@ static void collapse_order_partial_window(struct 
collapse_context *c,
 
        p = ops->setup_area(1);
        ops->fault(p, 0, page_size);
-       if (any_window_at_order(p, hpage_pmd_size))
+       if (any_window_at_order(ops, p, hpage_pmd_size))
                ksft_exit_fail_msg("Unexpected large folio after fault\n");
 
        if (madvise(p, hpage_pmd_size, MADV_HUGEPAGE))
@@ -1397,7 +1396,7 @@ static void collapse_order_partial_window(struct 
collapse_context *c,
        ksft_print_msg("Collapse window with single PTE entry present...");
        if (!khugepaged_full_pass(MTHP_PASS_TIMEOUT_S))
                fail("Timeout");
-       else if (all_windows_at_order(p, mthp_window_size()))
+       else if (all_windows_at_order(ops, p, mthp_window_size()))
                success("OK");
        else
                fail("Fail");
@@ -1422,7 +1421,7 @@ static void collapse_order_max_ptes_none(struct 
collapse_context *c,
 
        p = ops->setup_area(1);
        ops->fault(p, 0, 2 * window - page_size);
-       if (any_window_at_order(p, hpage_pmd_size))
+       if (any_window_at_order(ops, p, hpage_pmd_size))
                ksft_exit_fail_msg("Unexpected large folio after fault\n");
 
        if (madvise(p, hpage_pmd_size, MADV_HUGEPAGE))
@@ -1430,8 +1429,8 @@ static void collapse_order_max_ptes_none(struct 
collapse_context *c,
        ksft_print_msg("Collapse full window, not the one missing a page...");
        if (!khugepaged_full_pass(MTHP_PASS_TIMEOUT_S))
                fail("Timeout");
-       else if (all_windows_at_order(p, window) &&
-                !any_window_at_order(p + window, window))
+       else if (all_windows_at_order(ops, p, window) &&
+                !any_window_at_order(ops, p + window, window))
                success("OK");
        else
                fail("Fail");
@@ -1447,6 +1446,7 @@ static void collapse_order_mixed_sources(struct 
collapse_context *c,
                                         struct mem_ops *ops)
 {
        int source_order = anon_order ? anon_order : MIN_MTHP_ORDER;
+       size_t source_size = page_size << source_order;
        struct thp_settings settings;
        void *p;
 
@@ -1470,8 +1470,8 @@ static void collapse_order_mixed_sources(struct 
collapse_context *c,
         * The allocator can fall back to smaller folios under fragmentation;
         * having nothing to collapse from is not a failure.
         */
-       if (!is_range_backed_by_order(p, hpage_pmd_size, source_order,
-                                     pagemap_fd, kpageflags_fd)) {
+       if (!ops->check_huge(p, hpage_pmd_size, hpage_pmd_size / source_size,
+                            source_size)) {
                ksft_print_msg("No order-%d sources to collapse...", 
source_order);
                skip("Skip");
                ops->cleanup_area(p, hpage_pmd_size);
@@ -1486,7 +1486,7 @@ static void collapse_order_mixed_sources(struct 
collapse_context *c,
                       source_order);
        if (!khugepaged_full_pass(MTHP_PASS_TIMEOUT_S))
                fail("Timeout");
-       else if (all_windows_at_order(p, hpage_pmd_size))
+       else if (all_windows_at_order(ops, p, hpage_pmd_size))
                success("OK");
        else
                fail("Fail");
@@ -1715,15 +1715,6 @@ int main(int argc, char **argv)
                }
        }
 
-       if (mthp_khugepaged_context) {
-               pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
-               if (pagemap_fd < 0)
-                       ksft_exit_fail_perror("open(/proc/self/pagemap)");
-               kpageflags_fd = open("/proc/kpageflags", O_RDONLY);
-               if (kpageflags_fd < 0)
-                       ksft_exit_fail_perror("open(/proc/kpageflags)");
-       }
-
        setbuf(stdout, NULL);
 
        /*
diff --git a/tools/testing/selftests/mm/khugepaged_sync_check.c 
b/tools/testing/selftests/mm/khugepaged_sync_check.c
index 28a9b1ff5d44..40cba121a987 100644
--- a/tools/testing/selftests/mm/khugepaged_sync_check.c
+++ b/tools/testing/selftests/mm/khugepaged_sync_check.c
@@ -26,7 +26,6 @@
 #define PASS_TIMEOUT_S 30
 
 static int pagemap_fd;
-static int kpageflags_fd;
 static int trace_events_fd = -1;
 static unsigned long hpage_pmd_size;
 
@@ -116,8 +115,7 @@ static void one_step(int iteration)
        if (!passed)
                ksft_exit_fail_msg("khugepaged did not complete a full pass\n");
 
-       collapsed = is_range_backed_by_order(p, window, TARGET_ORDER,
-                                            pagemap_fd, kpageflags_fd);
+       collapsed = check_huge_anon(p, window, 1, window);
        attributed = count_attributed(pfns, nr_pages, TARGET_ORDER);
 
        ksft_test_result(collapsed && attributed == 1,
@@ -146,9 +144,6 @@ int main(void)
        pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
        if (pagemap_fd < 0)
                ksft_exit_fail_perror("open(/proc/self/pagemap)");
-       kpageflags_fd = open("/proc/kpageflags", O_RDONLY);
-       if (kpageflags_fd < 0)
-               ksft_exit_skip("open(/proc/kpageflags) requires root\n");
        trace_events_fd = tracing_events_open("huge_memory");
        if (trace_events_fd < 0)
                ksft_exit_skip("huge_memory events require tracefs and root\n");
diff --git a/tools/testing/selftests/mm/vm_util.c 
b/tools/testing/selftests/mm/vm_util.c
index 0a4b85e29e14..4c0d0e6f2553 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -401,8 +401,6 @@ char *__get_smap_entry(void *addr, const char *pattern, 
char *buf, size_t len)
  * @start: start of the range, a multiple of the folio size
  * @len: length of the range in bytes, a multiple of the folio size
  * @order: the folio order to check for
- * @pagemap_fd: open /proc/<pid>/pagemap of the range's owner
- * @kpageflags_fd: open /proc/kpageflags
  *
  * Every folio-sized, folio-aligned part of the range must map one folio of
  * @order, head to tail, with the head at the start of the part.  A part
@@ -411,11 +409,12 @@ char *__get_smap_entry(void *addr, const char *pattern, 
char *buf, size_t len)
  *
  * Returns: true if the whole range is backed that way, false otherwise.
  */
-bool is_range_backed_by_order(char *start, size_t len, int order,
-                             int pagemap_fd, int kpageflags_fd)
+static bool is_range_backed_by_order(char *start, size_t len, int order)
 {
        const unsigned long nr_pages = 1UL << order;
        const size_t folio_size = nr_pages * psize();
+       const int pagemap_fd = pagemap_fd_get();
+       const int kpageflags_fd = kpageflags_fd_get();
        char *vaddr;
 
        if ((uintptr_t)start % folio_size || len % folio_size)
@@ -448,16 +447,14 @@ bool is_range_backed_by_order(char *start, size_t len, 
int order,
  * size each, with the folio's head at the window start.  A folio mapped off
  * its alignment or split across two windows counts for neither.
  */
-static int count_windows_at_order(char *start, size_t len, uint64_t hpage_size,
-                                 int pagemap_fd, int kpageflags_fd)
+static int count_windows_at_order(char *start, size_t len, uint64_t hpage_size)
 {
        const int order = sz2ord(hpage_size, psize());
        int nr_windows = 0;
        char *addr;
 
        for (addr = start; addr + hpage_size <= start + len; addr += 
hpage_size) {
-               if (is_range_backed_by_order(addr, hpage_size, order,
-                                            pagemap_fd, kpageflags_fd))
+               if (is_range_backed_by_order(addr, hpage_size, order))
                        nr_windows++;
        }
 
@@ -486,7 +483,7 @@ static bool check_huge_type(uint64_t categories, enum 
check_huge_type type)
 static bool __check_huge(void *addr, size_t len, int nr_hpages,
                uint64_t hpage_size, enum check_huge_type type)
 {
-       int pagemap_fd, kpageflags_fd;
+       int pagemap_fd;
        int nr_pmd_mappings = 0;
        uint64_t pmd_pagesize, scan_mapping_size;
        uint64_t categories;
@@ -505,11 +502,9 @@ static bool __check_huge(void *addr, size_t len, int 
nr_hpages,
        allow_nonpresent = (uint64_t)nr_hpages * hpage_size < len;
 
        pagemap_fd = pagemap_fd_get();
-       kpageflags_fd = kpageflags_fd_get();
 
        if (!check_pmd_mapping &&
-           nr_hpages != count_windows_at_order(start, len, hpage_size,
-                                               pagemap_fd, kpageflags_fd))
+           nr_hpages != count_windows_at_order(start, len, hpage_size))
                return false;
 
        for (; start < end; start += scan_mapping_size) {
diff --git a/tools/testing/selftests/mm/vm_util.h 
b/tools/testing/selftests/mm/vm_util.h
index b5d59729d432..2bf64d5b42aa 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -102,8 +102,6 @@ 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);
-bool is_range_backed_by_order(char *start, size_t len, 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