From: "David Hildenbrand (Arm)" <david@kernel.org>
To: Yeoreum Yun <yeoreum.yun@arm.com>,
Andrew Morton <akpm@linux-foundation.org>,
Lorenzo Stoakes <ljs@kernel.org>, Zi Yan <ziy@nvidia.com>,
Baolin Wang <baolin.wang@linux.alibaba.com>,
"Liam R. Howlett" <liam@infradead.org>,
Nico Pache <nico.pache@linux.dev>,
Ryan Roberts <ryan.roberts@arm.com>, Dev Jain <dev.jain@arm.com>,
Barry Song <baohua@kernel.org>, Lance Yang <lance.yang@linux.dev>,
Usama Arif <usama.arif@linux.dev>,
Vlastimil Babka <vbabka@kernel.org>,
Mike Rapoport <rppt@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>, Shuah Khan <shuah@kernel.org>,
Kevin Brodsky <kevin.brodsky@arm.com>
Cc: linux-mm@kvack.org, linux-kselftest@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v7 2/3] kselftest: mm: replace usage of /proc/self/smaps for check_huge_xxx() helper
Date: Mon, 21 Sep 2026 17:27:57 +0200 [thread overview]
Message-ID: <36465f31-59e2-43a5-8cd8-f8bb1844da3c@kernel.org> (raw)
In-Reply-To: <20260921-fix_split-v7-2-d25ec991159f@arm.com>
On 9/21/26 12:40, Yeoreum Yun wrote:
> Since glibc commit 321e1fc73f (“malloc: Enable 2MB THP by default on AArch64”),
> glibc may call madvise(MADV_HUGEPAGE) for sufficiently large allocations
> made by memalign().
>
> The underlying VMA may start at a different address from the aligned
> address returned by memalign(). Furthermore, a subsequent
> madvise(MADV_HUGEPAGE) call does not split the VMA because the flag is
> already set.
>
> This causes split_huge_page_test to fail because the check_huge_xxx()
> helpers incorrectly require the address returned by memalign() to
> match the VMA start address reported in /proc/self/smaps.
>
> Instead of relying on /proc/self/smaps, use /proc/self/pagemap and
> /proc/kpageflags to detect huge-page mappings and large folios:
>
> 1. If hpage_size == pmd_pagesize, check PAGE_IS_HUGE instead of
> using check_large_folios(), since only the mapping type matters.
> This identifies PMD-mapped huge pages.
> 2. Otherwise, use check_large_folios() to detect large folios. This
> covers mTHP cases.
> 3. Check the folio flags according to the type of huge page.
>
> Since shmem pages are also file-backed, simply check whether the page
> is file-backed.
>
> Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
> Suggested-by: Zi Yan <ziy@nvidia.com>
Do we need a Fixes: tag?
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> tools/testing/selftests/mm/vm_util.c | 137 +++++++++++++++++++++--------------
> 1 file changed, 84 insertions(+), 53 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
> index 4821a35630363..a7c5caf6925e0 100644
> --- a/tools/testing/selftests/mm/vm_util.c
> +++ b/tools/testing/selftests/mm/vm_util.c
> @@ -351,31 +351,13 @@ char *__get_smap_entry(void *addr, const char *pattern, char *buf, size_t len)
> return entry;
> }
>
> -static bool __check_pmd_huge(void *addr, char *pattern, int nr_hpages,
> - uint64_t hpage_size)
> -{
> - char buffer[MAX_LINE_LENGTH];
> - uint64_t thp = -1;
> - char *entry;
> -
> - entry = __get_smap_entry(addr, pattern, buffer, sizeof(buffer));
> - if (!entry)
> - goto err_out;
> -
> - if (sscanf(entry, "%9" SCNu64 " kB", &thp) != 1)
> - ksft_exit_fail_msg("Reading smap error\n");
> -
> -err_out:
> - return thp == (nr_hpages * (hpage_size >> 10));
> -}
> -
> -static bool check_large_folios(void *addr, size_t len, int nr_hpages,
> - uint64_t hpage_size)
> +static bool check_large_folios(int pagemap_fd, int kpageflags_fd,
> + void *addr, size_t len, int nr_hpages,
> + uint64_t hpage_size)
The function used two tab indent for a reason ;)
Use two tabs also in the functions you change below.
[...]
>
> -bool check_huge_file(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)
> +static bool __check_huge(void *addr, size_t len, int nr_hpages,
> + uint64_t hpage_size, enum check_huge_type type)
> {
> - uint64_t pmd_pagesize = read_pmd_pagesize();
> + bool ret = false;
> + int pagemap_fd, kpageflags_fd;
> + int nr_pmd_mappings = 0;
> + uint64_t pmd_pagesize, scan_mapping_size;
> + uint64_t categories, kpf;
> + unsigned long pfn;
> + bool check_pmd_mapping, allow_nonpresent;
> + char *start = addr;
> + char *end = start + len;
>
> + pmd_pagesize = read_pmd_pagesize();
> if (!pmd_pagesize)
> ksft_exit_fail_msg("reading PMD pagesize failed\n");
>
> - if (hpage_size == pmd_pagesize)
> - return __check_pmd_huge(addr, "FilePmdMapped:", nr_hpages, hpage_size);
> + check_pmd_mapping = (hpage_size == pmd_pagesize);
No need for ()
> + scan_mapping_size = (nr_hpages > 0) ? hpage_size : psize();
> + /* Some mTHP tests check a partially populated PMD-sized range. */
> + allow_nonpresent = (uint64_t)nr_hpages * hpage_size < len;
>
> - return check_large_folios(addr, len, nr_hpages, hpage_size);
> + 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");
> +
> + if (!check_pmd_mapping &&
> + !check_large_folios(pagemap_fd, kpageflags_fd,
> + addr, len, nr_hpages, hpage_size))
> + goto out;
> +
> + 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;
> + else
> + continue;
> + }
> + if (pageflags_get(pfn, kpageflags_fd, &kpf))
> + ksft_exit_fail_msg("read kpageflags: %s\n", strerror(errno));
> + if (check_pmd_mapping && (categories & PAGE_IS_HUGE))
> + nr_pmd_mappings++;
> + if (kpf & KPF_COMPOUND_TAIL)
> + continue;
> + if (!check_huge_type(categories, kpf, type))
> + goto out;
> + }
> +
> + if (check_pmd_mapping && (nr_pmd_mappings != nr_hpages))
> + goto out;
There is way too much happening here, which makes this rather hard to review.
Why can't we just focus on the smaps change for now?
I.e., something like the following (untested)
diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index 4821a35630363..5d348d6985026 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -351,24 +351,6 @@ char *__get_smap_entry(void *addr, const char *pattern, char *buf, size_t len)
return entry;
}
-static bool __check_pmd_huge(void *addr, char *pattern, int nr_hpages,
- uint64_t hpage_size)
-{
- char buffer[MAX_LINE_LENGTH];
- uint64_t thp = -1;
- char *entry;
-
- entry = __get_smap_entry(addr, pattern, buffer, sizeof(buffer));
- if (!entry)
- goto err_out;
-
- if (sscanf(entry, "%9" SCNu64 " kB", &thp) != 1)
- ksft_exit_fail_msg("Reading smap error\n");
-
-err_out:
- return thp == (nr_hpages * (hpage_size >> 10));
-}
-
static bool check_large_folios(void *addr, size_t len, int nr_hpages,
uint64_t hpage_size)
{
@@ -410,20 +392,34 @@ static bool check_large_folios(void *addr, size_t len, int nr_hpages,
return ret;
}
-bool check_huge_anon(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)
+static bool __check_pmds(void *start, size_t len, int expected_file_pmds,
+ int expected_anon_pmds, uint64_t pmd_pagesize)
{
- uint64_t pmd_pagesize = read_pmd_pagesize();
+ int found_anon_pmds = 0, found_file_pmds = 0;
+ int pagemap_fd;
+ void *addr;
- if (!pmd_pagesize)
- ksft_exit_fail_msg("reading PMD pagesize failed\n");
+ pagemap_fd = open(PAGEMAP_PATH, O_RDONLY);
+ if (pagemap_fd < 0)
+ ksft_exit_fail_msg("open pagemap fail\n");
- if (hpage_size == pmd_pagesize)
- return __check_pmd_huge(addr, "AnonHugePages: ", nr_hpages, hpage_size);
+ for (addr = start; addr < start + len; addr += pmd_pagesize) {
+ const uint64_t categories = pagemap_scan_get_categories(pagemap_fd, addr);
- return check_large_folios(addr, len, nr_hpages, hpage_size);
+ if (!(categories & PAGE_IS_HUGE))
+ continue;
+ if (categories & PAGE_IS_FILE)
+ found_file_pmds++;
+ else
+ found_anon_pmds++;
+ }
+
+ close(pagemap_fd);
+ return found_anon_pmds == expected_anon_pmds &&
+ found_file_pmds == expected_file_pmds;
}
-bool check_huge_file(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)
+bool check_huge_anon(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)
{
uint64_t pmd_pagesize = read_pmd_pagesize();
@@ -431,12 +427,12 @@ bool check_huge_file(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)
ksft_exit_fail_msg("reading PMD pagesize failed\n");
if (hpage_size == pmd_pagesize)
- return __check_pmd_huge(addr, "FilePmdMapped:", nr_hpages, hpage_size);
+ return __check_pmds(addr, len, 0, nr_hpages, pmd_pagesize);
return check_large_folios(addr, len, nr_hpages, hpage_size);
}
-bool check_huge_shmem(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)
+bool check_huge_file(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)
{
uint64_t pmd_pagesize = read_pmd_pagesize();
@@ -444,11 +440,16 @@ bool check_huge_shmem(void *addr, size_t len, int nr_hpages, uint64_t hpage_size
ksft_exit_fail_msg("reading PMD pagesize failed\n");
if (hpage_size == pmd_pagesize)
- return __check_pmd_huge(addr, "ShmemPmdMapped:", nr_hpages, hpage_size);
+ return __check_pmds(addr, len, nr_hpages, 0, pmd_pagesize);
return check_large_folios(addr, len, nr_hpages, hpage_size);
}
+bool check_huge_shmem(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)
+{
+ return check_huge_file(addr, len, nr_hpages, hpage_size);
+}
+
int64_t allocate_transhuge(void *ptr, int pagemap_fd)
{
uint64_t ent[2];
--
2.43.0
--
Cheers,
David
next prev parent reply other threads:[~2026-09-21 15:28 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 10:40 [PATCH v7 0/3] kselftest: mm: fix some failure of split_huge_page_test Yeoreum Yun
2026-09-21 10:40 ` [PATCH v7 1/3] kselftest: mm: prevent random failure of huge page split for khugepaged Yeoreum Yun
2026-09-21 10:40 ` [PATCH v7 2/3] kselftest: mm: replace usage of /proc/self/smaps for check_huge_xxx() helper Yeoreum Yun
2026-09-21 15:27 ` David Hildenbrand (Arm) [this message]
2026-09-21 18:48 ` Yeoreum Yun
2026-09-21 21:05 ` David Hildenbrand (Arm)
2026-09-22 7:00 ` Yeoreum Yun
2026-09-21 10:40 ` [PATCH v7 3/3] kselftest: mm: remove check_huge_shmem() Yeoreum Yun
2026-09-21 15:28 ` David Hildenbrand (Arm)
2026-09-21 15:47 ` Lorenzo Stoakes (ARM)
2026-09-22 1:31 ` Zi Yan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=36465f31-59e2-43a5-8cd8-f8bb1844da3c@kernel.org \
--to=david@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=dev.jain@arm.com \
--cc=kevin.brodsky@arm.com \
--cc=lance.yang@linux.dev \
--cc=liam@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=mhocko@suse.com \
--cc=nico.pache@linux.dev \
--cc=rppt@kernel.org \
--cc=ryan.roberts@arm.com \
--cc=shuah@kernel.org \
--cc=surenb@google.com \
--cc=usama.arif@linux.dev \
--cc=vbabka@kernel.org \
--cc=yeoreum.yun@arm.com \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®