[PATCH v2 1/4] selftests/mm: open pagemap and kpageflags once for check_huge()

From: Kiryl Shutsemau

Date: Fri Oct 09 2026 - 11:32:29 EST


From: "Kiryl Shutsemau (Meta)" <kas@xxxxxxxxxx>

check_huge_anon() and check_huge_file() open /proc/self/pagemap and
/proc/kpageflags on every call. The khugepaged test calls them hundreds
of times.

Open both once and keep the descriptors. A pagemap descriptor is tied
to the mm of the process that opened it, and the khugepaged fork() cases
call check_huge() from the child, so reopen it when getpid() changes.

Assisted-by: LLM
Signed-off-by: Kiryl Shutsemau (Meta) <kas@xxxxxxxxxx>
---
tools/testing/selftests/mm/vm_util.c | 62 ++++++++++++++++++++--------
1 file changed, 45 insertions(+), 17 deletions(-)

diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index 762c31f7dfab..09d9135f0ca8 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -22,6 +22,44 @@
unsigned int __page_size;
unsigned int __page_shift;

+/*
+ * A pagemap file reads the mm of the process that opened it, so a child
+ * inherits a descriptor that describes its parent. Open a new one whenever
+ * the pid changed since the last open.
+ */
+static int pagemap_fd_get(void)
+{
+ static int fd = -1;
+ static pid_t pid;
+
+ if (fd >= 0 && pid == getpid())
+ return fd;
+
+ if (fd >= 0)
+ close(fd);
+
+ fd = open(PAGEMAP_PATH, O_RDONLY);
+ if (fd < 0)
+ ksft_exit_fail_msg("open pagemap fail\n");
+ pid = getpid();
+
+ return fd;
+}
+
+static int kpageflags_fd_get(void)
+{
+ static int fd = -1;
+
+ if (fd >= 0)
+ return fd;
+
+ fd = open(KPAGEFLAGS_PATH, O_RDONLY);
+ if (fd < 0)
+ ksft_exit_fail_msg("open kpageflags fail\n");
+
+ return fd;
+}
+
uint64_t pagemap_get_entry(int fd, char *start)
{
const unsigned long pfn = (unsigned long)start / getpagesize();
@@ -407,7 +445,6 @@ 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)
{
- bool ret = false;
int pagemap_fd, kpageflags_fd;
int nr_pmd_mappings = 0;
uint64_t pmd_pagesize, scan_mapping_size;
@@ -426,42 +463,33 @@ static bool __check_huge(void *addr, size_t len, int nr_hpages,
/* Some mTHP tests check a partially populated PMD-sized range. */
allow_nonpresent = (uint64_t)nr_hpages * hpage_size < len;

- 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");
+ pagemap_fd = pagemap_fd_get();
+ kpageflags_fd = kpageflags_fd_get();

if (!check_pmd_mapping &&
!check_large_folios(pagemap_fd, kpageflags_fd,
addr, len, nr_hpages, hpage_size))
- goto out;
+ return false;

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;
+ return false;
else
continue;
}
if (check_pmd_mapping && (categories & PAGE_IS_HUGE))
nr_pmd_mappings++;
if (!check_huge_type(categories, type))
- goto out;
+ return false;
}

if (check_pmd_mapping && (nr_pmd_mappings != nr_hpages))
- goto out;
- ret = true;
+ return false;

-out:
- close(pagemap_fd);
- close(kpageflags_fd);
- return ret;
+ return true;
}

bool check_huge_anon(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)
--
2.54.0