kselftest: mm: fix some failure of split_huge_page_test
Subsystems (5)
v9 cover kselftest: mm: fix some failure of split_huge_page_test
split_huge_page_test can fail for the following reasons:
1. During the test, khugepaged may collapse previously split pages again, causing intermittent failures.
2. 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(). Moreover, a subsequent madvise(MADV_HUGEPAGE) call does not split the VMA because it already has the same advice.
This causes the 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.
Address these issues by applying MADV_NOHUGEPAGE after faulting in the huge page, preventing khugepaged from collapsing it again, and 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 check_huge_shmem() was required to distinguish shmem huge pages because /proc/self/smaps reports them using a dedicated “ShmemPmdMapped” entry, as opposed to “FilePmdMapped” for file-backed huge pages.
Now that /proc/self/smaps is no longer used to detect huge pages and /proc/kpageflags is used instead, it is sufficient to distinguish
between file-backed and anonymous pages since the ShmemPmdMapped is also
kind of file-backed.
Therefore, remove check_huge_shmem() and use check_huge_file() instead.
This patch based on mm-unstable
---
Changes in v9:
- fix some typos in comment and Fixes tag.
- separating huge and type checking.
- add r-b tags.
- Link to v8: https://lore.kernel.org/r/[email protected]
Changes in v8:
- add intermediate patch for __check_pmd_huge().
- add r-b, a-b tags.
- Link to v7: https://lore.kernel.org/r/[email protected]
Changes in v7:
- change khugepaged's check_huge() callback.
- Link to v6: https://lore.kernel.org/r/[email protected]
Changes in v6:
- drop alloc_isolated_mem() patch.
- remove check_huge_shmem().
- Link to v5: https://lore.kernel.org/r/[email protected]
Changes in v5:
- rename madv_nohuge() to disable_khugepaged().
- Link to v4: https://lore.kernel.org/r/[email protected]
Changes in v4:
- reparse commit message.
- introduce alloc_isolated_mem().
- make madv_nohuge() helper according to suggestion.
- Link to v3: https://lore.kernel.org/r/[email protected]
Changes in v3:
- change message in case of failure of madvise() with MADV_NOHUGEPAGE.
- fix collapse_single_mthp (mthp_khugepaged:anon) test case failure.
- Link to v2: https://lore.kernel.org/all/[email protected]/
Changes in v2:
- rebase to mm-unstable.
- add message in case of failure of madvise() with MADV_NOHUGEPAGE.
- fix wrong setup expected_huge in check_huge_shmem().
- Link to v1: https://lore.kernel.org/r/[email protected]
---
Yeoreum Yun (4):
kselftest: mm: prevent random failure of huge page split for khugepaged
kselftest: mm: replace usage of /proc/self/smaps for __check_pmd_huge()
kselftest: mm: integrate huge page checks
kselftest: mm: remove check_huge_shmem()
tools/testing/selftests/mm/folio_split_race_test.c | 2 +- tools/testing/selftests/mm/khugepaged.c | 38 ++----- tools/testing/selftests/mm/split_huge_page_test.c | 16 +++ tools/testing/selftests/mm/uffd-common.c | 4 +- tools/testing/selftests/mm/vm_util.c | 113 ++++++++++++++------- tools/testing/selftests/mm/vm_util.h | 1 - 6 files changed, 100 insertions(+), 74 deletions(-)
---
base-commit: e8d0f6a1b2a447d02845984fa6288787543cb03c
change-id: 20260820-fix_split-f44939ec44b8
Best regards,
Signature · 2 lines
Sincerely, Yeoreum Yun
PATCH v9 1/4 kselftest: mm: prevent random failure of huge page split for khugepaged
There're some random failure for split_huge_page_test when khugepaged collapses pages into pmd again which had split by the test.
Prevent the khugepaged's collapses for split page by setting the mapped pmd-huge-page with MADV_NOHUGEPAGE before split.
--- tools/testing/selftests/mm/split_huge_page_test.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
tools/testing/selftests/mm/split_huge_page_test.c +16 -0
@@ -108,6 +108,15 @@ static char *allocate_zero_filled_hugepage(size_t len)return result; } +static void disable_khugepaged (void *addr,size_t len) +{ +/* Disables khugepaged from collapsing pages in range into THPs */ +if (!madvise (addr, len,MADV_NOHUGEPAGE )) +return ; + +ksft_exit_fail_perror ("MADV_NOHUGEPAGE failed" ); +} +static void verify_rss_anon_split_huge_page_all_zeroes (char *one_page,int nr_hpages,size_t len) {unsigned long rss_anon_before, rss_anon_after;
@@ -120,6 +129,8 @@ static void verify_rss_anon_split_huge_page_all_zeroes(char *one_page, int nr_hpif (!rss_anon_before)ksft_exit_fail_msg ("No RssAnon is allocated before split\n" ); +disable_khugepaged (one_page, len); +/* split all THPs */ write_debugfs (PID_FMT ,getpid (), (uint64_t )one_page, (uint64_t )one_page + len,0 );
@@ -167,6 +178,8 @@ static void split_pmd_thp_to_order(int order)if (!check_huge_anon (one_page,4 * pmd_pagesize,4 , pmd_pagesize))ksft_exit_fail_msg ("No THP is allocated\n" ); +disable_khugepaged (one_page, len); +/* split all THPs */ write_debugfs (PID_FMT ,getpid (), (uint64_t )one_page, (uint64_t )one_page + len, order);
@@ -215,6 +228,8 @@ static void split_pte_mapped_thp(void) goto out; } +disable_khugepaged (thp_area, thp_area_size); +/* * To challenge spitting code, we will mremap a single page of each * THP (page[i] of thp[i]) in the thp_area into page_area. This will
@@ -482,6 +497,7 @@ static int create_pagecache_thp_and_fd(const char *testfile, size_t fd_size,ksft_test_result_skip ("Pagecache folio split skipped\n" );return -2 ; } +disable_khugepaged (*addr, fd_size);return 0 ; err_out_close:close (*fd);
Signature · 1 line
2.43.0
PATCH v9 2/4 kselftest: mm: replace usage of /proc/self/smaps for __check_pmd_huge()
In reply to Yeoreum YunSince 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_pmd_huge() 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 checking PAGE_IS_HUGE and PAGE_IS_FILE according to type of huge page.
Since shmem pages are also file-backed, simply check whether the page is file-backed.
--- tools/testing/selftests/mm/vm_util.c | 78 ++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 29 deletions(-)
tools/testing/selftests/mm/vm_util.c +49 -29
@@ -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,51 @@ 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) +enum check_huge_type { +CHECK_HUGE_ANON , +CHECK_HUGE_FILE , +}; + +static bool check_huge_type (uint64_t categories,enum check_huge_type type) { -uint64_t pmd_pagesize =read_pmd_pagesize (); +const bool file = categories &PAGE_IS_FILE ; -if (!pmd_pagesize) -ksft_exit_fail_msg ("reading PMD pagesize failed\n" ); +switch (type) { +case CHECK_HUGE_ANON : +return !file; +case CHECK_HUGE_FILE : +return file; + } -if (hpage_size == pmd_pagesize) -return __check_pmd_huge (addr,"AnonHugePages: " , nr_hpages, hpage_size); +return false; +} -return check_large_folios (addr, len, nr_hpages, hpage_size); +static bool __check_pmd_huge (void *addr,size_t len,int nr_hpages, +uint64_t hpage_size,enum check_huge_type type) +{ +int pagemap_fd; +int nr_pmd_mappings =0 ; +uint64_t categories; +char *start = addr; +char *end = start + len; + + pagemap_fd =open (PAGEMAP_PATH ,O_RDONLY ); +if (pagemap_fd <0 ) +ksft_exit_fail_perror ("open pagemap" ); + +for (; start < end; start += hpage_size) { + categories =pagemap_scan_get_categories (pagemap_fd, start); +if (!(categories &PAGE_IS_HUGE )) +continue ; +if (check_huge_type (categories, type)) + nr_pmd_mappings++; + } +close (pagemap_fd); + +return nr_hpages == nr_pmd_mappings; } -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 +444,13 @@ 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_pmd_huge (addr, len, nr_hpages, hpage_size, +CHECK_HUGE_ANON );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 +458,17 @@ bool check_huge_shmem(void *addr, size_t len, int nr_hpages, uint64_t hpage_sizeksft_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_pmd_huge (addr, len, nr_hpages, hpage_size, +CHECK_HUGE_FILE );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 ];
Signature · 1 line
2.43.0
Re: [PATCH v9 2/4] kselftest: mm: replace usage of /proc/self/smaps for __check_pmd_huge()
Quoted 20 lines · Yeoreum Yun
Since glibc commit
321e1fc73f(“malloc: Enable 2MB THP by default on AArch64”), glibc may callmadvise(MADV_HUGEPAGE)for sufficiently large allocations made bymemalign().The underlying VMA may start at a different address from the aligned address returned by
memalign(). Furthermore, a subsequentmadvise(MADV_HUGEPAGE)call does not split the VMA because the flag is already set.This causes
split_huge_page_testto fail because thecheck_pmd_huge()helpers incorrectly require the address returned bymemalign()to match the VMA start address reported in/proc/self/smaps.Instead of relying on
/proc/self/smaps, use/proc/self/pagemapand/proc/kpageflagsto detect huge-page mappings checkingPAGE_IS_HUGEandPAGE_IS_FILEaccording to type of huge page.Since shmem pages are also file-backed, simply check whether the page is file-backed.
Quoted 7 lines
Fixes 642bc52aed9c ("selftests: vm: bring common functions to a new file")Suggested-by David Hildenbrand (Arm) <[email protected]>Reviewed-by Sarthak Sharma <[email protected]>Reviewed-by Baolin Wang <[email protected]>Tested-by Baolin Wang <[email protected]>Signed-off-by Yeoreum Yun <[email protected]>
LGTM so:
Thanks for doing this! :)
Quoted 130 lines
--- tools/testing/selftests/mm/vm_util.c | 78 ++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 29 deletions(-)tools/testing/selftests/mm/vm_util.c +49
-30@@ -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,51 @@ 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) +enum check_huge_type { +CHECK_HUGE_ANON , +CHECK_HUGE_FILE , +}; + +static bool check_huge_type (uint64_t categories,enum check_huge_type type) { -uint64_t pmd_pagesize =read_pmd_pagesize (); +const bool file = categories &PAGE_IS_FILE ; -if (!pmd_pagesize) -ksft_exit_fail_msg ("reading PMD pagesize failed\n" ); +switch (type) { +case CHECK_HUGE_ANON : +return !file; +case CHECK_HUGE_FILE : +return file; + } -if (hpage_size == pmd_pagesize) -return __check_pmd_huge (addr,"AnonHugePages: " , nr_hpages, hpage_size); +return false; +} -return check_large_folios (addr, len, nr_hpages, hpage_size); +static bool __check_pmd_huge (void *addr,size_t len,int nr_hpages, +uint64_t hpage_size,enum check_huge_type type) +{ +int pagemap_fd; +int nr_pmd_mappings =0 ; +uint64_t categories; +char *start = addr; +char *end = start + len; + + pagemap_fd =open (PAGEMAP_PATH ,O_RDONLY ); +if (pagemap_fd <0 ) +ksft_exit_fail_perror ("open pagemap" ); + +for (; start < end; start += hpage_size) { + categories =pagemap_scan_get_categories (pagemap_fd, start); +if (!(categories &PAGE_IS_HUGE )) +continue ; +if (check_huge_type (categories, type)) + nr_pmd_mappings++; + } +close (pagemap_fd); + +return nr_hpages == nr_pmd_mappings; } -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 +444,13 @@ 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_pmd_huge (addr, len, nr_hpages, hpage_size, +CHECK_HUGE_ANON );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 +458,17 @@ bool check_huge_shmem(void *addr, size_t len, int nr_hpages, uint64_t hpage_sizeksft_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_pmd_huge (addr, len, nr_hpages, hpage_size, +CHECK_HUGE_FILE );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 ]; --
Quoted 2 lines
2.43.0
--
Cheers, Lorenzo
Re: [PATCH v9 2/4] kselftest: mm: replace usage of /proc/self/smaps for __check_pmd_huge()
In reply to Yeoreum YunQuoted 27 lines · Yeoreum Yun
Since glibc commit
321e1fc73f(“malloc: Enable 2MB THP by default on AArch64”), glibc may callmadvise(MADV_HUGEPAGE)for sufficiently large allocations made bymemalign().The underlying VMA may start at a different address from the aligned address returned by
memalign(). Furthermore, a subsequentmadvise(MADV_HUGEPAGE)call does not split the VMA because the flag is already set.This causes
split_huge_page_testto fail because thecheck_pmd_huge()helpers incorrectly require the address returned bymemalign()to match the VMA start address reported in/proc/self/smaps.Instead of relying on
/proc/self/smaps, use/proc/self/pagemapand/proc/kpageflagsto detect huge-page mappings checkingPAGE_IS_HUGEandPAGE_IS_FILEaccording to type of huge page.Since shmem pages are also file-backed, simply check whether the page is file-backed.
Fixes 642bc52aed9c ("selftests: vm: bring common functions to a new file")Suggested-by David Hildenbrand (Arm) <[email protected]>Reviewed-by Sarthak Sharma <[email protected]>Reviewed-by Baolin Wang <[email protected]>Tested-by Baolin Wang <[email protected]>Signed-off-by Yeoreum Yun <[email protected]>
Quoted 4 lines
--- tools/testing/selftests/mm/vm_util.c | 78 ++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 29 deletions(-)
LGTM.
Best Regards,
Yan, Zi
PATCH v9 3/4 kselftest: mm: integrate huge page checks
In reply to Yeoreum Yuncheck_large_folios() only checks for large folios without distinguishing between anonymous and file-backed huge pages.
To add huge page type checking, integrate the huge page checks into __check_huge() and __check_type():
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 huge page type via
__check_type()
--- tools/testing/selftests/mm/vm_util.c | 90 ++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 34 deletions(-)
tools/testing/selftests/mm/vm_util.c +56 -34
@@ -392,76 +392,98 @@ static bool check_large_folios(void *addr, size_t len, int nr_hpages,return ret; } -enum check_huge_type { -CHECK_HUGE_ANON , -CHECK_HUGE_FILE , +enum check_type { +CHECK_TYPE_ANON , +CHECK_TYPE_FILE , }; -static bool check_huge_type (uint64_t categories,enum check_huge_type type) +static bool __check_type (void *addr,size_t len,uint64_t page_size, +enum check_type type) { -const bool file = categories &PAGE_IS_FILE ; +bool ret = false; +int pagemap_fd; +char *start = addr; +char *end = start + len; +uint64_t categories; -switch (type) { -case CHECK_HUGE_ANON : -return !file; -case CHECK_HUGE_FILE : -return file; + pagemap_fd =open (PAGEMAP_PATH ,O_RDONLY ); +if (pagemap_fd <0 ) +ksft_exit_fail_perror ("open pagemap" ); + +for (; start < end; start += page_size) { + categories =pagemap_scan_get_categories (pagemap_fd, start); +if ((categories &PAGE_IS_PRESENT ) !=PAGE_IS_PRESENT ) +continue ; + +if ((type ==CHECK_TYPE_FILE ) != !!(categories &PAGE_IS_FILE )) + goto out; } -return false; + ret = true; + +out: +close (pagemap_fd); +return ret; } -static bool __check_pmd_huge (void *addr,size_t len,int nr_hpages, -uint64_t hpage_size,enum check_huge_type type) +static bool __check_huge (void *addr,size_t len,int nr_hpages, +uint64_t hpage_size) { +bool ret = false;int pagemap_fd;int nr_pmd_mappings =0 ; +uint64_t pmd_pagesize;uint64_t categories;char *start = addr;char *end = start + len; + pmd_pagesize =read_pmd_pagesize (); +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_perror ("open pagemap" ); +if (hpage_size != pmd_pagesize) { + ret =check_large_folios (addr, len, nr_hpages, hpage_size); + goto out; + } +for (; start < end; start += hpage_size) { categories =pagemap_scan_get_categories (pagemap_fd, start); -if (!(categories &PAGE_IS_HUGE )) -continue ; -if (check_huge_type (categories, type)) +if (categories &PAGE_IS_HUGE ) nr_pmd_mappings++; } -close (pagemap_fd); -return nr_hpages == nr_pmd_mappings; +if (nr_pmd_mappings != nr_hpages) + goto out; + + ret = true; + +out: +close (pagemap_fd); +return ret; }bool check_huge_anon (void *addr,size_t len,int nr_hpages,uint64_t hpage_size) { -uint64_t pmd_pagesize =read_pmd_pagesize (); - -if (!pmd_pagesize) -ksft_exit_fail_msg ("reading PMD pagesize failed\n" ); +const uint64_t scan_mapping_size = (nr_hpages >0 ) ? hpage_size :psize (); -if (hpage_size == pmd_pagesize) -return __check_pmd_huge (addr, len, nr_hpages, hpage_size, -CHECK_HUGE_ANON ); +if (!__check_huge (addr, len, nr_hpages, hpage_size)) +return false; -return check_large_folios (addr, len, nr_hpages, hpage_size); +return __check_type (addr, len, scan_mapping_size,CHECK_TYPE_ANON ); }bool check_huge_file (void *addr,size_t len,int nr_hpages,uint64_t hpage_size) { -uint64_t pmd_pagesize =read_pmd_pagesize (); +const uint64_t scan_mapping_size = (nr_hpages >0 ) ? hpage_size :psize (); -if (!pmd_pagesize) -ksft_exit_fail_msg ("reading PMD pagesize failed\n" ); - -if (hpage_size == pmd_pagesize) -return __check_pmd_huge (addr, len, nr_hpages, hpage_size, -CHECK_HUGE_FILE ); +if (!__check_huge (addr, len, nr_hpages, hpage_size)) +return false; -return check_large_folios (addr, len, nr_hpages, hpage_size); +return __check_type (addr, len, scan_mapping_size,CHECK_TYPE_FILE ); }bool check_huge_shmem (void *addr,size_t len,int nr_hpages,uint64_t hpage_size)
Signature · 1 line
2.43.0
Re: [PATCH v9 3/4] kselftest: mm: integrate huge page checks
Quoted 14 lines · Yeoreum Yun
check_large_folios()only checks for large folios without distinguishing between anonymous and file-backed huge pages.To add huge page type checking, integrate the huge page checks into
__check_huge()and__check_type():1. If
hpage_size==pmd_pagesize, checkPAGE_IS_HUGEinstead of usingcheck_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 huge page type via
Quoted 9 lines
__check_type()Suggested-by David Hildenbrand (Arm) <[email protected]>Suggested-by Zi Yan <[email protected]>Signed-off-by Yeoreum Yun <[email protected]>--- tools/testing/selftests/mm/vm_util.c | 90 ++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 34 deletions(-)
LGTM.
Best Regards,
Yan, Zi
PATCH v9 4/4 kselftest: mm: remove check_huge_shmem()
In reply to Yeoreum Yuncheck_huge_shmem() was required to distinguish shmem huge pages because /proc/self/smaps reports them using a dedicated “ShmemPmdMapped” entry, as opposed to “FilePmdMapped” for file-backed huge pages.
Now that /proc/self/smaps is no longer used to detect huge pages and /proc/kpageflags is used instead, it is sufficient to distinguish between file-backed and anonymous pages since the ShmemPmdMapped is also kind of file-backed.
Therefore, remove check_huge_shmem() and use check_huge_file() instead and cleanup khugepaged's check_huge operation in mem_ops.
--- tools/testing/selftests/mm/folio_split_race_test.c | 2 +- tools/testing/selftests/mm/khugepaged.c | 38 ++++------------------ tools/testing/selftests/mm/uffd-common.c | 4 +-- tools/testing/selftests/mm/vm_util.c | 5 --- tools/testing/selftests/mm/vm_util.h | 1 - 5 files changed, 9 insertions(+), 41 deletions(-)
tools/testing/selftests/mm/folio_split_race_test.c +1 -1
@@ -181,7 +181,7 @@ static uint64_t run_iteration(void)for (i =0 ; i <TOTAL_PAGES ; i++)fill_page (mmap_base, i); -if (!check_huge_shmem (mmap_base,FILE_SIZE ,NR_PMD_PAGE , pmd_pagesize)) +if (!check_huge_file (mmap_base,FILE_SIZE ,NR_PMD_PAGE , pmd_pagesize))ksft_exit_fail_msg ("No shmem THP is allocated\n" );if (pthread_barrier_init (&ctl.barrier,NULL ,NUM_READER_THREADS +1 ) !=0 )
tools/testing/selftests/mm/khugepaged.c +6 -32
@@ -57,7 +57,7 @@ struct mem_ops {void *(*setup_area)(int nr_hpages);void (*cleanup_area)(void *p,unsigned long size);void (*fault)(void *p,unsigned long start,unsigned long end); -bool (*check_huge)(void *addr,size_t len,int nr_hpages,unsigned long hpage_size); +bool (*check_huge)(void *addr,size_t len,int nr_hpages,uint64_t hpage_size);const char *name; };
@@ -343,12 +343,6 @@ static void anon_fault(void *p, unsigned long start, unsigned long end)fill_memory (p, start, end); } -static bool anon_check_huge (void *addr,size_t len,int nr_hpages, -unsigned long hpage_size) -{ -return check_huge_anon (addr, len, nr_hpages, hpage_size); -} -static void *file_setup_area_common (int nr_hpages,enum file_setup_ops setup) {const int open_opt = setup ==FILE_SETUP_READ_ONLY_FS ?O_RDONLY :O_RDWR ;
@@ -444,20 +438,6 @@ static void file_fault_write(void *p, unsigned long start, unsigned long end)ksft_exit_fail_perror ("madvise(MADV_POPULATE_WRITE)" ); } -static bool file_check_huge (void *addr,size_t len,int nr_hpages, -unsigned long hpage_size) -{ -switch (finfo.type) { -case VMA_FILE : -return check_huge_file (addr, len, nr_hpages, hpage_size); -case VMA_SHMEM : -return check_huge_shmem (addr, len, nr_hpages, hpage_size); -default : -ksft_exit_fail_msg ("Unknown VMA type\n" ); -return false; - } -} -static void *shmem_setup_area (int nr_hpages) {void *p;
@@ -481,17 +461,11 @@ static void shmem_cleanup_area(void *p, unsigned long size)close (finfo.fd); } -static bool shmem_check_huge (void *addr,size_t len,int nr_hpages, -unsigned long hpage_size) -{ -return check_huge_shmem (addr, len, nr_hpages, hpage_size); -} -static struct mem_ops __anon_ops = { .setup_area = &anon_setup_area, .cleanup_area = &anon_cleanup_area, .fault = &anon_fault, - .check_huge = &anon_check_huge, + .check_huge = &check_huge_anon, .name ="anon" , };
@@ -499,7 +473,7 @@ static struct mem_ops __read_only_file_ops = { .setup_area = &file_setup_read_only_area, .cleanup_area = &file_cleanup_area, .fault = &file_fault_read, - .check_huge = &file_check_huge, + .check_huge = &check_huge_file, .name = "file", };
@@ -507,7 +481,7 @@ static struct mem_ops __read_write_file_read_ops = { .setup_area = &file_setup_read_write_fs_read_area, .cleanup_area = &file_cleanup_area, .fault = &file_fault_read_and_flush, - .check_huge = &file_check_huge, + .check_huge = &check_huge_file, .name = "file", };
@@ -515,7 +489,7 @@ static struct mem_ops __read_write_file_write_ops = { .setup_area = &file_setup_read_write_fs_write_area, .cleanup_area = &file_cleanup_area, .fault = &file_fault_write, - .check_huge = &file_check_huge, + .check_huge = &check_huge_file, .name = "file", };
@@ -523,7 +497,7 @@ static struct mem_ops __shmem_ops = { .setup_area = &shmem_setup_area, .cleanup_area = &shmem_cleanup_area, .fault = &anon_fault, - .check_huge = &shmem_check_huge, + .check_huge = &check_huge_file, .name = "shmem", };
tools/testing/selftests/mm/uffd-common.c +2 -2
@@ -196,8 +196,8 @@ static void shmem_check_pmd_mapping(uffd_global_test_opts_t *gopts, void *p, int {size_t len = expect_nr_hpages *read_pmd_pagesize (); -if (!check_huge_shmem (gopts->area_dst_alias, len, expect_nr_hpages, -read_pmd_pagesize ())) +if (!check_huge_file (gopts->area_dst_alias, len, expect_nr_hpages, +read_pmd_pagesize ()))err ("Did not find expected %d number of hugepages" , expect_nr_hpages); }
tools/testing/selftests/mm/vm_util.c +0 -5
@@ -486,11 +486,6 @@ bool check_huge_file(void *addr, size_t len, int nr_hpages, uint64_t hpage_size)return __check_type (addr, len, scan_mapping_size,CHECK_TYPE_FILE ); } -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 ];
tools/testing/selftests/mm/vm_util.h +0 -1
@@ -96,7 +96,6 @@ uint64_t read_pmd_pagesize(void);unsigned long rss_anon (void );bool check_huge_anon (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); -bool check_huge_shmem (void *addr,size_t len,int nr_hpages,uint64_t hpage_size);int64_t allocate_transhuge (void *ptr,int pagemap_fd);int pageflags_get (unsigned long pfn,int kpageflags_fd,uint64_t *flags); int gather_folio_orders(char *vaddr_start, size_t len,
Signature · 1 line
2.43.0
Andrew Morton
maintainerQuoted 12 lines · On Thu, 01 Oct 2026 22:17:50 +0100 Yeoreum Yun <[email protected]> wrote:
split_huge_page_testcan fail for the following reasons:1. During the test, khugepaged may collapse previously split pages again, causing intermittent failures.
2. Since glibc commit
321e1fc73f(“malloc: Enable 2MB THP by default on AArch64”), glibc may callmadvise(MADV_HUGEPAGE)for sufficiently large allocations made bymemalign(). The underlying VMA may start at a different address from the aligned address returned bymemalign(). Moreover, a subsequentmadvise(MADV_HUGEPAGE)call does not split the VMA because it already has the same advice.
Quoted 8 lines
This causes the test to fail because the
check_huge_xxx()helpers incorrectly require the address returned bymemalign()to match the VMA start address reported in/proc/self/smaps.Address these issues by applying
MADV_NOHUGEPAGEafter faulting in the huge page, preventing khugepaged from collapsing it again, and instead of relying on/proc/self/smaps, use/proc/self/pagemapand/proc/kpageflagsto detect huge-page mappings and large folios:
Thanks, I've updated mm.git's mm-unstable branch to this version.
Quoted 4 lines
Changes in v9:
- fix some typos in comment and Fixes tag.
- separating huge and type checking.
- add r-b tags.
Here's how v9 altered mm.git:
tools/testing/selftests/mm/split_huge_page_test.c | 7 tools/testing/selftests/mm/vm_util.c | 108 ++++++------ 2 files changed, 64 insertions(+), 51 deletions(-)
tools/testing/selftests/mm/split_huge_page_test.c renamed from tools/testing/selftests/mm/split_huge_page_test.c~b +2 -5
@@ -110,14 +110,11 @@ static char *allocate_zero_filled_hugepastatic void disable_khugepaged (void *addr,size_t len) { -/* -* Disables khugepaged from collapsing THPs in range, existing THP -* pages remain. -*/ +/* Disables khugepaged from collapsing pages in range into THPs */ if (!madvise (addr, len,MADV_NOHUGEPAGE ))return ; -ksft_exit_fail_msg ("MADV_NOHUGEPAGE failed, err=%d\n" , errno); +ksft_exit_fail_perror ("MADV_NOHUGEPAGE failed" ); }static void verify_rss_anon_split_huge_page_all_zeroes (char *one_page,int nr_hpages,size_t len)
tools/testing/selftests/mm/vm_util.c renamed from tools/testing/selftests/mm/vm_util.c~b +62 -46
176 lines not on this page · raw message
_