Several HMM tests hardcode TWOMEG as the THP size. This is wrong on
architectures where the PMD size is not 2MB such as arm64 with 64K base
pages where THP is 512MB. Fix this by using read_pmd_pagesize() from
vm_util instead.
While here also replace the custom file_read_ulong() helper used to
parse the default hugetlbfs page size from /proc/meminfo with the
existing default_huge_page_size() from vm_util.
[1] https://lore.kernel.org/linux-mm/8bd0396a-8997-4d2e-a13f-5aac033083d7@linux.dev/
Fixes: fee9f6d1b8df ("mm/hmm/test: add selftests for HMM")
Fixes: 519071529d2a ("selftests/mm/hmm-tests: new tests for zone device THP migration")
Reported-by: Zenghui Yu <zenghui.yu@linux.dev>
Closes: https://lore.kernel.org/linux-mm/8bd0396a-8997-4d2e-a13f-5aac033083d7@linux.dev/
Signed-off-by: Alistair Popple <apopple@nvidia.com>
---
tools/testing/selftests/mm/hmm-tests.c | 83 +++++---------------------
1 file changed, 16 insertions(+), 67 deletions(-)
diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c
index e8328c89d855..788689497e92 100644
--- a/tools/testing/selftests/mm/hmm-tests.c
+++ b/tools/testing/selftests/mm/hmm-tests.c
@@ -34,6 +34,7 @@
*/
#include <lib/test_hmm_uapi.h>
#include <mm/gup_test.h>
+#include <mm/vm_util.h>
struct hmm_buffer {
void *ptr;
@@ -548,7 +549,7 @@ TEST_F(hmm, anon_write_child)
for (migrate = 0; migrate < 2; ++migrate) {
for (use_thp = 0; use_thp < 2; ++use_thp) {
- npages = ALIGN(use_thp ? TWOMEG : HMM_BUFFER_SIZE,
+ npages = ALIGN(use_thp ? read_pmd_pagesize() : HMM_BUFFER_SIZE,
self->page_size) >> self->page_shift;
ASSERT_NE(npages, 0);
size = npages << self->page_shift;
@@ -728,7 +729,7 @@ TEST_F(hmm, anon_write_huge)
int *ptr;
int ret;
- size = 2 * TWOMEG;
+ size = 2 * read_pmd_pagesize();
buffer = malloc(sizeof(*buffer));
ASSERT_NE(buffer, NULL);
@@ -744,7 +745,7 @@ TEST_F(hmm, anon_write_huge)
buffer->fd, 0);
ASSERT_NE(buffer->ptr, MAP_FAILED);
- size = TWOMEG;
+ size /= 2;
npages = size >> self->page_shift;
map = (void *)ALIGN((uintptr_t)buffer->ptr, size);
ret = madvise(map, size, MADV_HUGEPAGE);
@@ -770,54 +771,6 @@ TEST_F(hmm, anon_write_huge)
hmm_buffer_free(buffer);
}
-/*
- * Read numeric data from raw and tagged kernel status files. Used to read
- * /proc and /sys data (without a tag) and from /proc/meminfo (with a tag).
- */
-static long file_read_ulong(char *file, const char *tag)
-{
- int fd;
- char buf[2048];
- int len;
- char *p, *q;
- long val;
-
- fd = open(file, O_RDONLY);
- if (fd < 0) {
- /* Error opening the file */
- return -1;
- }
-
- len = read(fd, buf, sizeof(buf));
- close(fd);
- if (len < 0) {
- /* Error in reading the file */
- return -1;
- }
- if (len == sizeof(buf)) {
- /* Error file is too large */
- return -1;
- }
- buf[len] = '\0';
-
- /* Search for a tag if provided */
- if (tag) {
- p = strstr(buf, tag);
- if (!p)
- return -1; /* looks like the line we want isn't there */
- p += strlen(tag);
- } else
- p = buf;
-
- val = strtol(p, &q, 0);
- if (*q != ' ') {
- /* Error parsing the file */
- return -1;
- }
-
- return val;
-}
-
/*
* Write huge TLBFS page.
*/
@@ -826,15 +779,13 @@ TEST_F(hmm, anon_write_hugetlbfs)
struct hmm_buffer *buffer;
unsigned long npages;
unsigned long size;
- unsigned long default_hsize;
+ unsigned long default_hsize = default_huge_page_size();
unsigned long i;
int *ptr;
int ret;
- default_hsize = file_read_ulong("/proc/meminfo", "Hugepagesize:");
- if (default_hsize < 0 || default_hsize*1024 < default_hsize)
+ if (!default_hsize)
SKIP(return, "Huge page size could not be determined");
- default_hsize = default_hsize*1024; /* KB to B */
size = ALIGN(TWOMEG, default_hsize);
npages = size >> self->page_shift;
@@ -1606,7 +1557,7 @@ TEST_F(hmm, compound)
struct hmm_buffer *buffer;
unsigned long npages;
unsigned long size;
- unsigned long default_hsize;
+ unsigned long default_hsize = default_huge_page_size();
int *ptr;
unsigned char *m;
int ret;
@@ -1614,10 +1565,8 @@ TEST_F(hmm, compound)
/* Skip test if we can't allocate a hugetlbfs page. */
- default_hsize = file_read_ulong("/proc/meminfo", "Hugepagesize:");
- if (default_hsize < 0 || default_hsize*1024 < default_hsize)
+ if (!default_hsize)
SKIP(return, "Huge page size could not be determined");
- default_hsize = default_hsize*1024; /* KB to B */
size = ALIGN(TWOMEG, default_hsize);
npages = size >> self->page_shift;
@@ -2106,7 +2055,7 @@ TEST_F(hmm, migrate_anon_huge_empty)
int *ptr;
int ret;
- size = TWOMEG;
+ size = read_pmd_pagesize();
buffer = malloc(sizeof(*buffer));
ASSERT_NE(buffer, NULL);
@@ -2158,7 +2107,7 @@ TEST_F(hmm, migrate_anon_huge_zero)
int ret;
int val;
- size = TWOMEG;
+ size = read_pmd_pagesize();
buffer = malloc(sizeof(*buffer));
ASSERT_NE(buffer, NULL);
@@ -2221,7 +2170,7 @@ TEST_F(hmm, migrate_anon_huge_free)
int *ptr;
int ret;
- size = TWOMEG;
+ size = read_pmd_pagesize();
buffer = malloc(sizeof(*buffer));
ASSERT_NE(buffer, NULL);
@@ -2280,7 +2229,7 @@ TEST_F(hmm, migrate_anon_huge_fault)
int *ptr;
int ret;
- size = TWOMEG;
+ size = read_pmd_pagesize();
buffer = malloc(sizeof(*buffer));
ASSERT_NE(buffer, NULL);
@@ -2332,7 +2281,7 @@ TEST_F(hmm, migrate_partial_unmap_fault)
{
struct hmm_buffer *buffer;
unsigned long npages;
- unsigned long size = TWOMEG;
+ unsigned long size = read_pmd_pagesize();
unsigned long i;
void *old_ptr;
void *map;
@@ -2398,7 +2347,7 @@ TEST_F(hmm, migrate_remap_fault)
{
struct hmm_buffer *buffer;
unsigned long npages;
- unsigned long size = TWOMEG;
+ unsigned long size = read_pmd_pagesize();
unsigned long i;
void *old_ptr, *new_ptr = NULL;
void *map;
@@ -2498,7 +2447,7 @@ TEST_F(hmm, migrate_anon_huge_err)
int *ptr;
int ret;
- size = TWOMEG;
+ size = read_pmd_pagesize();
buffer = malloc(sizeof(*buffer));
ASSERT_NE(buffer, NULL);
@@ -2593,7 +2542,7 @@ TEST_F(hmm, migrate_anon_huge_zero_err)
int *ptr;
int ret;
- size = TWOMEG;
+ size = read_pmd_pagesize();
buffer = malloc(sizeof(*buffer));
ASSERT_NE(buffer, NULL);
--
2.53.0
On Tue, Mar 31, 2026 at 05:34:44PM +1100, Alistair Popple wrote:
> Several HMM tests hardcode TWOMEG as the THP size. This is wrong on
> architectures where the PMD size is not 2MB such as arm64 with 64K base
+1
But one question…
Can’t the THP size be derived via HPAGE_PMD_ORDER?
If not, then some DRM common code I’ve written will break on arm64.
Matt
> pages where THP is 512MB. Fix this by using read_pmd_pagesize() from
> vm_util instead.
>
> While here also replace the custom file_read_ulong() helper used to
> parse the default hugetlbfs page size from /proc/meminfo with the
> existing default_huge_page_size() from vm_util.
>
> [1] https://lore.kernel.org/linux-mm/8bd0396a-8997-4d2e-a13f-5aac033083d7@linux.dev/
>
> Fixes: fee9f6d1b8df ("mm/hmm/test: add selftests for HMM")
> Fixes: 519071529d2a ("selftests/mm/hmm-tests: new tests for zone device THP migration")
> Reported-by: Zenghui Yu <zenghui.yu@linux.dev>
> Closes: https://lore.kernel.org/linux-mm/8bd0396a-8997-4d2e-a13f-5aac033083d7@linux.dev/
> Signed-off-by: Alistair Popple <apopple@nvidia.com>
> ---
> tools/testing/selftests/mm/hmm-tests.c | 83 +++++---------------------
> 1 file changed, 16 insertions(+), 67 deletions(-)
>
> diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c
> index e8328c89d855..788689497e92 100644
> --- a/tools/testing/selftests/mm/hmm-tests.c
> +++ b/tools/testing/selftests/mm/hmm-tests.c
> @@ -34,6 +34,7 @@
> */
> #include <lib/test_hmm_uapi.h>
> #include <mm/gup_test.h>
> +#include <mm/vm_util.h>
>
> struct hmm_buffer {
> void *ptr;
> @@ -548,7 +549,7 @@ TEST_F(hmm, anon_write_child)
>
> for (migrate = 0; migrate < 2; ++migrate) {
> for (use_thp = 0; use_thp < 2; ++use_thp) {
> - npages = ALIGN(use_thp ? TWOMEG : HMM_BUFFER_SIZE,
> + npages = ALIGN(use_thp ? read_pmd_pagesize() : HMM_BUFFER_SIZE,
> self->page_size) >> self->page_shift;
> ASSERT_NE(npages, 0);
> size = npages << self->page_shift;
> @@ -728,7 +729,7 @@ TEST_F(hmm, anon_write_huge)
> int *ptr;
> int ret;
>
> - size = 2 * TWOMEG;
> + size = 2 * read_pmd_pagesize();
>
> buffer = malloc(sizeof(*buffer));
> ASSERT_NE(buffer, NULL);
> @@ -744,7 +745,7 @@ TEST_F(hmm, anon_write_huge)
> buffer->fd, 0);
> ASSERT_NE(buffer->ptr, MAP_FAILED);
>
> - size = TWOMEG;
> + size /= 2;
> npages = size >> self->page_shift;
> map = (void *)ALIGN((uintptr_t)buffer->ptr, size);
> ret = madvise(map, size, MADV_HUGEPAGE);
> @@ -770,54 +771,6 @@ TEST_F(hmm, anon_write_huge)
> hmm_buffer_free(buffer);
> }
>
> -/*
> - * Read numeric data from raw and tagged kernel status files. Used to read
> - * /proc and /sys data (without a tag) and from /proc/meminfo (with a tag).
> - */
> -static long file_read_ulong(char *file, const char *tag)
> -{
> - int fd;
> - char buf[2048];
> - int len;
> - char *p, *q;
> - long val;
> -
> - fd = open(file, O_RDONLY);
> - if (fd < 0) {
> - /* Error opening the file */
> - return -1;
> - }
> -
> - len = read(fd, buf, sizeof(buf));
> - close(fd);
> - if (len < 0) {
> - /* Error in reading the file */
> - return -1;
> - }
> - if (len == sizeof(buf)) {
> - /* Error file is too large */
> - return -1;
> - }
> - buf[len] = '\0';
> -
> - /* Search for a tag if provided */
> - if (tag) {
> - p = strstr(buf, tag);
> - if (!p)
> - return -1; /* looks like the line we want isn't there */
> - p += strlen(tag);
> - } else
> - p = buf;
> -
> - val = strtol(p, &q, 0);
> - if (*q != ' ') {
> - /* Error parsing the file */
> - return -1;
> - }
> -
> - return val;
> -}
> -
> /*
> * Write huge TLBFS page.
> */
> @@ -826,15 +779,13 @@ TEST_F(hmm, anon_write_hugetlbfs)
> struct hmm_buffer *buffer;
> unsigned long npages;
> unsigned long size;
> - unsigned long default_hsize;
> + unsigned long default_hsize = default_huge_page_size();
> unsigned long i;
> int *ptr;
> int ret;
>
> - default_hsize = file_read_ulong("/proc/meminfo", "Hugepagesize:");
> - if (default_hsize < 0 || default_hsize*1024 < default_hsize)
> + if (!default_hsize)
> SKIP(return, "Huge page size could not be determined");
> - default_hsize = default_hsize*1024; /* KB to B */
>
> size = ALIGN(TWOMEG, default_hsize);
> npages = size >> self->page_shift;
> @@ -1606,7 +1557,7 @@ TEST_F(hmm, compound)
> struct hmm_buffer *buffer;
> unsigned long npages;
> unsigned long size;
> - unsigned long default_hsize;
> + unsigned long default_hsize = default_huge_page_size();
> int *ptr;
> unsigned char *m;
> int ret;
> @@ -1614,10 +1565,8 @@ TEST_F(hmm, compound)
>
> /* Skip test if we can't allocate a hugetlbfs page. */
>
> - default_hsize = file_read_ulong("/proc/meminfo", "Hugepagesize:");
> - if (default_hsize < 0 || default_hsize*1024 < default_hsize)
> + if (!default_hsize)
> SKIP(return, "Huge page size could not be determined");
> - default_hsize = default_hsize*1024; /* KB to B */
>
> size = ALIGN(TWOMEG, default_hsize);
> npages = size >> self->page_shift;
> @@ -2106,7 +2055,7 @@ TEST_F(hmm, migrate_anon_huge_empty)
> int *ptr;
> int ret;
>
> - size = TWOMEG;
> + size = read_pmd_pagesize();
>
> buffer = malloc(sizeof(*buffer));
> ASSERT_NE(buffer, NULL);
> @@ -2158,7 +2107,7 @@ TEST_F(hmm, migrate_anon_huge_zero)
> int ret;
> int val;
>
> - size = TWOMEG;
> + size = read_pmd_pagesize();
>
> buffer = malloc(sizeof(*buffer));
> ASSERT_NE(buffer, NULL);
> @@ -2221,7 +2170,7 @@ TEST_F(hmm, migrate_anon_huge_free)
> int *ptr;
> int ret;
>
> - size = TWOMEG;
> + size = read_pmd_pagesize();
>
> buffer = malloc(sizeof(*buffer));
> ASSERT_NE(buffer, NULL);
> @@ -2280,7 +2229,7 @@ TEST_F(hmm, migrate_anon_huge_fault)
> int *ptr;
> int ret;
>
> - size = TWOMEG;
> + size = read_pmd_pagesize();
>
> buffer = malloc(sizeof(*buffer));
> ASSERT_NE(buffer, NULL);
> @@ -2332,7 +2281,7 @@ TEST_F(hmm, migrate_partial_unmap_fault)
> {
> struct hmm_buffer *buffer;
> unsigned long npages;
> - unsigned long size = TWOMEG;
> + unsigned long size = read_pmd_pagesize();
> unsigned long i;
> void *old_ptr;
> void *map;
> @@ -2398,7 +2347,7 @@ TEST_F(hmm, migrate_remap_fault)
> {
> struct hmm_buffer *buffer;
> unsigned long npages;
> - unsigned long size = TWOMEG;
> + unsigned long size = read_pmd_pagesize();
> unsigned long i;
> void *old_ptr, *new_ptr = NULL;
> void *map;
> @@ -2498,7 +2447,7 @@ TEST_F(hmm, migrate_anon_huge_err)
> int *ptr;
> int ret;
>
> - size = TWOMEG;
> + size = read_pmd_pagesize();
>
> buffer = malloc(sizeof(*buffer));
> ASSERT_NE(buffer, NULL);
> @@ -2593,7 +2542,7 @@ TEST_F(hmm, migrate_anon_huge_zero_err)
> int *ptr;
> int ret;
>
> - size = TWOMEG;
> + size = read_pmd_pagesize();
>
> buffer = malloc(sizeof(*buffer));
> ASSERT_NE(buffer, NULL);
> --
> 2.53.0
>
On 3/31/26 17:34, Alistair Popple wrote:
> Several HMM tests hardcode TWOMEG as the THP size. This is wrong on
> architectures where the PMD size is not 2MB such as arm64 with 64K base
> pages where THP is 512MB. Fix this by using read_pmd_pagesize() from
> vm_util instead.
>
> While here also replace the custom file_read_ulong() helper used to
> parse the default hugetlbfs page size from /proc/meminfo with the
> existing default_huge_page_size() from vm_util.
>
> [1] https://lore.kernel.org/linux-mm/8bd0396a-8997-4d2e-a13f-5aac033083d7@linux.dev/
>
> Fixes: fee9f6d1b8df ("mm/hmm/test: add selftests for HMM")
> Fixes: 519071529d2a ("selftests/mm/hmm-tests: new tests for zone device THP migration")
> Reported-by: Zenghui Yu <zenghui.yu@linux.dev>
> Closes: https://lore.kernel.org/linux-mm/8bd0396a-8997-4d2e-a13f-5aac033083d7@linux.dev/
> Signed-off-by: Alistair Popple <apopple@nvidia.com>
> ---
> tools/testing/selftests/mm/hmm-tests.c | 83 +++++---------------------
> 1 file changed, 16 insertions(+), 67 deletions(-)
>
Reviewed-by: Balbir Singh <balbirs@nvidia.com>
© 2016 - 2026 Red Hat, Inc.