From: "Kiryl Shutsemau (Meta)" <[email protected]> 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) <[email protected]> --- 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

