On 7/28/26 4:13 PM, Baolin Wang wrote:
Implement mTHP-sized hugepage checking helpers using gather_folio_orders().
Also rename the existing PMD-sized huge page check function to
__check_pmd_huge() for clarity.
Signed-off-by: Baolin Wang <[email protected]>
---
tools/testing/selftests/mm/vm_util.c | 55 ++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/mm/vm_util.c
b/tools/testing/selftests/mm/vm_util.c
index 09e5d5cabe21..a4ffaa0ca6fa 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -15,6 +15,10 @@
#define SMAP_FILE_PATH "/proc/self/smaps"
#define STATUS_FILE_PATH "/proc/self/status"
#define MAX_LINE_LENGTH 500
+#define PAGEMAP_PATH "/proc/self/pagemap"
+#define KPAGEFLAGS_PATH "/proc/kpageflags"
+#define GET_ORDER(nr_pages) (31 - __builtin_clz(nr_pages))
sashiko comment:
"Is there a risk of undefined behavior here if nr_pages evaluates to 0?
If check_large_folios() is called with an hpage_size smaller than the
system page size, the division hpage_size / pagesize will yield 0.
Calling __builtin_clz(0) results in undefined behavior."
This doesn't happen now. But for code robustness, I'll add a hpage_size
check in check_large_folios().
+#define NR_ORDERS 20
unsigned int __page_size;
unsigned int __page_shift;
@@ -348,7 +352,7 @@ char *__get_smap_entry(void *addr, const char *pattern,
char *buf, size_t len)
return entry;
}
-bool __check_huge(void *addr, char *pattern, int nr_hpages,
+static bool __check_pmd_huge(void *addr, char *pattern, int nr_hpages,
uint64_t hpage_size)
{
char buffer[MAX_LINE_LENGTH];
@@ -366,19 +370,62 @@ bool __check_huge(void *addr, char *pattern, int
nr_hpages,
return thp == (nr_hpages * (hpage_size >> 10));
}
+static bool check_large_folios(void *addr, unsigned long size, int nr_hpages, uint64_t hpage_size)
+{
+ int pagesize = getpagesize();
+ int order = GET_ORDER(hpage_size / pagesize);
+ int pagemap_fd, kpageflags_fd;
+ int orders[NR_ORDERS], status;
+ bool ret = false;
+
+ memset(orders, 0, sizeof(int) * NR_ORDERS);
+
+ pagemap_fd = open(PAGEMAP_PATH, O_RDONLY);
+ if (pagemap_fd == -1)
+ ksft_exit_fail_msg("read pagemap fail\n");
+
+ kpageflags_fd = open(KPAGEFLAGS_PATH, O_RDONLY);
+ if (kpageflags_fd == -1) {
+ close(pagemap_fd);
+ ksft_exit_fail_msg("read kpageflags fail\n");
+ }
+
+ status = gather_folio_orders(addr, size, pagemap_fd,
+ kpageflags_fd, orders, NR_ORDERS);
+ if (status)
+ goto out;
+
+ if (orders[order] == nr_hpages)
+ ret = true;
sashiko comment:
"Does this code overflow the orders[] stack array if the calculated
order is 20 or greater?
For example, on architectures supporting very large huge pages (like
16GB huge pages on PowerPC), the order could be 22. It looks like
indexing orders[order] here without bounds checking could cause an
out-of-bounds stack read."
This doesn't look like the mTHP order size, but I'll add an order check.