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

From: Kiryl Shutsemau

Date: Tue Sep 29 2026 - 09:22:38 EST


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

check_huge_anon() and check_huge_file() open /proc/self/pagemap and
/proc/kpageflags on every call and read the PMD size from sysfs on top.
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.

Cache the PMD size in read_pmd_pagesize() as well.

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

diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index 762c31f7dfab..e284e378d806 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -22,6 +22,43 @@
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) {
+ 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();
@@ -161,10 +198,14 @@ bool check_for_pattern(FILE *fp, const char *pattern, char *buf, size_t len)

uint64_t read_pmd_pagesize(void)
{
+ static uint64_t pmd_pagesize;
int fd;
char buf[20];
ssize_t num_read;

+ if (pmd_pagesize)
+ return pmd_pagesize;
+
fd = open(PMD_SIZE_FILE_PATH, O_RDONLY);
if (fd == -1)
return 0;
@@ -177,7 +218,8 @@ uint64_t read_pmd_pagesize(void)
buf[num_read] = '\0';
close(fd);

- return strtoul(buf, NULL, 10);
+ pmd_pagesize = strtoul(buf, NULL, 10);
+ return pmd_pagesize;
}

unsigned long rss_anon(void)
@@ -407,7 +449,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 +467,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