* [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements
@ 2026-04-06 9:19 Sayali Patil
2026-04-06 9:19 ` [PATCH v4 01/15] selftests/mm: restore default nr_hugepages value via EXIT trap in charge_reserved_hugetlb.sh Sayali Patil
` (14 more replies)
0 siblings, 15 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
Hi all,
Powerpc systems with a 64K base page size exposed several issues while
running mm selftests. Some tests assume specific hugetlb configurations,
use incorrect interfaces, or fail instead of skipping when the required
kernel features are not available.
This series fixes these issues and improves test robustness.
Please review the patches and provide any feedback or suggestions for
improvement.
Thanks,
Sayali
---
v3->v4
- selftests/mm: restore default nr_hugepages value via EXIT
trap in charge_reserved_hugetlb.sh:
Updated to use an EXIT trap to restore the original nr_hugepages
once at script termination, ensuring reliable restoration on all
exit paths.
- selftest/mm: fix cgroup task placement and drop memory.current checks
in hugetlb_reparenting_test.sh:
Updated to use a deterministic synchronization method by migrating the
workload process within a wrapper subshell before calling exec() to
ensure correct cgroup accounting.
- selftest/mm: align memory size to huge page size in hugepage-mremap
test:
Update test code directly to align memory allocations to the hugepage
size, rather than modifying run_vmtests.sh. This replaces the previous
commit “adjust hugepage-mremap test size for large huge pages” with
a cleaner, direct approach in the test itself.
- selftests/mm: ensure destination is hugetlb-backed in hugepage-mremap:
Updated to remove MAP_POPULATE flag for the mmap call as per review
comment.
- selftests/mm: skip uffd-wp-mremap if UFFD write-protect is unsupported:
Updated as per review comment to initialize features to zero and exit
on all uffd_get_features() failures, avoiding spurious test errors.
- selftests/mm: move hwpoison setup into run_test() and silence
modprobe output for memory-failure category:
Declared LOADED_MOD as local variable and avoided a redundant
skip message when the module is not found.
Updated logic to set exitcode to ksft_skip only when no failure has
been recorded.
- selftests/cgroup: extend test_hugetlb_memcg.c to support all huge
page sizes:
Updated to skip on memory constraints instead of returning
EXIT_FAILURE.
Updated the logic to fully account for the scenario when the
per-CPU stock is empty and a refill charges MEMCG_CHARGE_BATCH.
Updated to avoid overflow on 32-bit systems for memory.max value.
- Included "selftests/mm: restore default nr_hugepages value via
EXIT trap in hugetlb_reparenting_test.sh"
- Included "selftests/mm: free dynamically allocated PMD-sized
buffers in split_huge_page_test"
- Included "selftests/mm: clarify alternate unmapping in compaction_test"
- Dropped "selftests/mm: fix double increment in linked list cleanup in
compaction_test":
The behaviour is intentional.
v3: https://lore.kernel.org/all/cover.1774591179.git.sayalip@linux.ibm.com/
---
v2->v3
- selftests/mm: skip uffd-wp-mremap if UFFD write-protect is unsupported:
Rename function to check_uffd_wp_feature_supported() as suggested in review.
- selftest/mm: fix cgroup task placement and drop memory.current checks
in hugetlb_reparenting_test.sh:
Drop memory.current validation from the hugetlb reparenting test.
Keep tolerance at 7MB (reverting earlier increase to 8MB in v1).
- Included "selftests/mm: allow PUD-level entries in compound testcase of hmm
tests" patch:
Extend the compound testcase checks to accept PUD-level mappings.
- Included "selftests/mm: replace hardcoded THP size with runtime PMD page size in
hmm tests" patch:
Use read_pmd_pagesize() instead of TWOMEG and cap maximum THPs in
benchmarks to avoid integer overflow.
v2: https://lore.kernel.org/all/cover.1773305677.git.sayalip@linux.ibm.com/
---
v1->v2
- For "selftests/mm: ensure destination is hugetlb-backed in hugepage-mremap":
update FLAGS definition to MAP_HUGETLB | MAP_SHARED | MAP_POPULATE and
used it for mmap() calls as suggested during review.
v1: https://lore.kernel.org/all/cover.1773134177.git.sayalip@linux.ibm.com/
---
Sayali Patil (15):
selftests/mm: restore default nr_hugepages value via EXIT trap in
charge_reserved_hugetlb.sh
selftests/mm: fix hugetlb pathname construction in
charge_reserved_hugetlb.sh
selftests/mm: restore default nr_hugepages value via EXIT trap in
hugetlb_reparenting_test.sh
selftests/mm: fix hugetlb pathname construction in
hugetlb_reparenting_test.sh
selftests/mm: fix cgroup task placement and drop memory.current checks
in hugetlb_reparenting_test.sh
selftests/mm: size tmpfs according to PMD page size in
split_huge_page_test
selftests/mm: free dynamically allocated PMD-sized buffers in
split_huge_page_test
selftest/mm: align memory size to huge page size in hugepage-mremap
test
selftest/mm: register existing mapping with userfaultfd in
hugepage-mremap
selftests/mm: ensure destination is hugetlb-backed in hugepage-mremap
selftests/mm: skip uffd-wp-mremap if UFFD write-protect is unsupported
selftests/mm: skip uffd-stress test when nr_pages_per_cpu is zero
selftests/mm: move hwpoison setup into run_test() and silence modprobe
output for memory-failure category
selftests/mm: clarify alternate unmapping in compaction_test
selftests/cgroup: extend test_hugetlb_memcg.c to support all huge page
sizes
.../selftests/cgroup/test_hugetlb_memcg.c | 90 ++++++++++++++-----
.../selftests/mm/charge_reserved_hugetlb.sh | 45 ++++++----
tools/testing/selftests/mm/compaction_test.c | 3 +
tools/testing/selftests/mm/hugepage-mremap.c | 42 ++++-----
.../selftests/mm/hugetlb_reparenting_test.sh | 59 ++++++------
tools/testing/selftests/mm/run_vmtests.sh | 52 +++++++----
.../selftests/mm/split_huge_page_test.c | 27 ++++--
tools/testing/selftests/mm/uffd-stress.c | 6 +-
tools/testing/selftests/mm/uffd-wp-mremap.c | 13 +++
9 files changed, 220 insertions(+), 117 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v4 01/15] selftests/mm: restore default nr_hugepages value via EXIT trap in charge_reserved_hugetlb.sh
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 02/15] selftests/mm: fix hugetlb pathname construction " Sayali Patil
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
cleanup() resets nr_hugepages to 0 on every invocation, while the test
reconfigures it again in the next iteration. This leads to repeated
allocation and freeing of large numbers of hugepages, especially when
the original value is high.
Additionally, with set -e, failures in earlier cleanup steps (e.g.,
rmdir or umount returning EBUSY while background activity is still
ongoing) can cause the script to exit before restoring the original
value, leaving the system in a modified state.
Use an EXIT trap to restore the original nr_hugepages once at
script termination. This avoids unnecessary allocation churn and
ensures the original value is reliably restored on all exit paths.
Fixes: 7d695b1c3695b ("selftests/mm: save and restore nr_hugepages value")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/charge_reserved_hugetlb.sh | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh
index 447769657634..ca33ec83ebf2 100755
--- a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh
+++ b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh
@@ -12,6 +12,7 @@ if [[ $(id -u) -ne 0 ]]; then
fi
nr_hugepgs=$(cat /proc/sys/vm/nr_hugepages)
+trap 'echo "$nr_hugepgs" > /proc/sys/vm/nr_hugepages' EXIT
fault_limit_file=limit_in_bytes
reservation_limit_file=rsvd.limit_in_bytes
@@ -65,7 +66,6 @@ function cleanup() {
if [[ -e $cgroup_path/hugetlb_cgroup_test2 ]]; then
rmdir $cgroup_path/hugetlb_cgroup_test2
fi
- echo 0 >/proc/sys/vm/nr_hugepages
echo CLEANUP DONE
}
@@ -594,4 +594,3 @@ if [[ $do_umount ]]; then
rmdir $cgroup_path
fi
-echo "$nr_hugepgs" > /proc/sys/vm/nr_hugepages
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 02/15] selftests/mm: fix hugetlb pathname construction in charge_reserved_hugetlb.sh
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
2026-04-06 9:19 ` [PATCH v4 01/15] selftests/mm: restore default nr_hugepages value via EXIT trap in charge_reserved_hugetlb.sh Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 03/15] selftests/mm: restore default nr_hugepages value via EXIT trap in hugetlb_reparenting_test.sh Sayali Patil
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The charge_reserved_hugetlb.sh script assumes hugetlb cgroup memory
interface file names use the "<size>MB" format
(e.g. hugetlb.1024MB.current).
This assumption breaks on systems with larger huge pages such as 1GB,
where the kernel exposes normalized units:
hugetlb.1GB.current
hugetlb.1GB.max
hugetlb.1GB.rsvd.max
...
As a result, the script attempts to access files like
hugetlb.1024MB.current, which do not exist when the kernel reports the
size in GB.
Normalize the huge page size and construct the pathname using the
appropriate unit (MB or GB), matching the hugetlb controller naming.
Fixes: 209376ed2a84 ("selftests/vm: make charge_reserved_hugetlb.sh work with existing cgroup setting")
Fixes: 29750f71a9b4 ("hugetlb_cgroup: add hugetlb_cgroup reservation tests")
Reviewed-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
.../selftests/mm/charge_reserved_hugetlb.sh | 42 +++++++++++++------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh
index ca33ec83ebf2..4aa7920b533e 100755
--- a/tools/testing/selftests/mm/charge_reserved_hugetlb.sh
+++ b/tools/testing/selftests/mm/charge_reserved_hugetlb.sh
@@ -89,6 +89,15 @@ function get_machine_hugepage_size() {
}
MB=$(get_machine_hugepage_size)
+if (( MB >= 1024 )); then
+ # For 1GB hugepages
+ UNIT="GB"
+ MB_DISPLAY=$((MB / 1024))
+else
+ # For 2MB hugepages
+ UNIT="MB"
+ MB_DISPLAY=$MB
+fi
function setup_cgroup() {
local name="$1"
@@ -98,11 +107,12 @@ function setup_cgroup() {
mkdir $cgroup_path/$name
echo writing cgroup limit: "$cgroup_limit"
- echo "$cgroup_limit" >$cgroup_path/$name/hugetlb.${MB}MB.$fault_limit_file
+ echo "$cgroup_limit" > \
+ $cgroup_path/$name/hugetlb.${MB_DISPLAY}${UNIT}.$fault_limit_file
echo writing reservation limit: "$reservation_limit"
echo "$reservation_limit" > \
- $cgroup_path/$name/hugetlb.${MB}MB.$reservation_limit_file
+ $cgroup_path/$name/hugetlb.${MB_DISPLAY}${UNIT}.$reservation_limit_file
if [ -e "$cgroup_path/$name/cpuset.cpus" ]; then
echo 0 >$cgroup_path/$name/cpuset.cpus
@@ -137,7 +147,7 @@ function wait_for_file_value() {
function wait_for_hugetlb_memory_to_get_depleted() {
local cgroup="$1"
- local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
+ local path="$cgroup_path/$cgroup/hugetlb.${MB_DISPLAY}${UNIT}.$reservation_usage_file"
wait_for_file_value "$path" "0"
}
@@ -145,7 +155,7 @@ function wait_for_hugetlb_memory_to_get_depleted() {
function wait_for_hugetlb_memory_to_get_reserved() {
local cgroup="$1"
local size="$2"
- local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
+ local path="$cgroup_path/$cgroup/hugetlb.${MB_DISPLAY}${UNIT}.$reservation_usage_file"
wait_for_file_value "$path" "$size"
}
@@ -153,7 +163,7 @@ function wait_for_hugetlb_memory_to_get_reserved() {
function wait_for_hugetlb_memory_to_get_written() {
local cgroup="$1"
local size="$2"
- local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file"
+ local path="$cgroup_path/$cgroup/hugetlb.${MB_DISPLAY}${UNIT}.$fault_usage_file"
wait_for_file_value "$path" "$size"
}
@@ -175,8 +185,8 @@ function write_hugetlbfs_and_get_usage() {
hugetlb_difference=0
reserved_difference=0
- local hugetlb_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file
- local reserved_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file
+ local hugetlb_usage=$cgroup_path/$cgroup/hugetlb.${MB_DISPLAY}${UNIT}.$fault_usage_file
+ local reserved_usage=$cgroup_path/$cgroup/hugetlb.${MB_DISPLAY}${UNIT}.$reservation_usage_file
local hugetlb_before=$(cat $hugetlb_usage)
local reserved_before=$(cat $reserved_usage)
@@ -307,8 +317,10 @@ function run_test() {
cleanup_hugetlb_memory "hugetlb_cgroup_test"
- local final_hugetlb=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$fault_usage_file)
- local final_reservation=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$reservation_usage_file)
+ local final_hugetlb=$(cat \
+ $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB_DISPLAY}${UNIT}.$fault_usage_file)
+ local final_reservation=$(cat \
+ $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB_DISPLAY}${UNIT}.$reservation_usage_file)
echo $hugetlb_difference
echo $reserved_difference
@@ -364,10 +376,14 @@ function run_multiple_cgroup_test() {
reservation_failed1=$reservation_failed
oom_killed1=$oom_killed
- local cgroup1_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$fault_usage_file
- local cgroup1_reservation_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$reservation_usage_file
- local cgroup2_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$fault_usage_file
- local cgroup2_reservation_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$reservation_usage_file
+ local cgroup1_hugetlb_usage=\
+ $cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB_DISPLAY}${UNIT}.$fault_usage_file
+ local cgroup1_reservation_usage=\
+ $cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB_DISPLAY}${UNIT}.$reservation_usage_file
+ local cgroup2_hugetlb_usage=\
+ $cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB_DISPLAY}${UNIT}.$fault_usage_file
+ local cgroup2_reservation_usage=\
+ $cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB_DISPLAY}${UNIT}.$reservation_usage_file
local usage_before_second_write=$(cat $cgroup1_hugetlb_usage)
local reservation_usage_before_second_write=$(cat $cgroup1_reservation_usage)
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 03/15] selftests/mm: restore default nr_hugepages value via EXIT trap in hugetlb_reparenting_test.sh
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
2026-04-06 9:19 ` [PATCH v4 01/15] selftests/mm: restore default nr_hugepages value via EXIT trap in charge_reserved_hugetlb.sh Sayali Patil
2026-04-06 9:19 ` [PATCH v4 02/15] selftests/mm: fix hugetlb pathname construction " Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 04/15] selftests/mm: fix hugetlb pathname construction " Sayali Patil
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The test modifies nr_hugepages during execution and restores it from
cleanup() and again reconfigure it setup, which is invoked multiple
times across test flow. This can lead to repeated
allocation/freeing of hugepages.
With set -e, failures in cleanup (e.g., rmdir/umount) can also
cause early exit before restoring the original value at the end.
Move restoration to a single EXIT trap so the original value is
restored reliably on all exit paths while avoiding repeated churn.
Fixes: 585a9145886a ("selftests/mm: restore default nr_hugepages value during cleanup in hugetlb_reparenting_test.sh")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/hugetlb_reparenting_test.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/mm/hugetlb_reparenting_test.sh b/tools/testing/selftests/mm/hugetlb_reparenting_test.sh
index 0dd31892ff67..7ddb370e1572 100755
--- a/tools/testing/selftests/mm/hugetlb_reparenting_test.sh
+++ b/tools/testing/selftests/mm/hugetlb_reparenting_test.sh
@@ -12,6 +12,8 @@ if [[ $(id -u) -ne 0 ]]; then
fi
nr_hugepgs=$(cat /proc/sys/vm/nr_hugepages)
+trap 'echo "$nr_hugepgs" > /proc/sys/vm/nr_hugepages' EXIT
+
usage_file=usage_in_bytes
if [[ "$1" == "-cgroup-v2" ]]; then
@@ -56,7 +58,6 @@ function cleanup() {
rmdir "$CGROUP_ROOT"/a/b 2>/dev/null
rmdir "$CGROUP_ROOT"/a 2>/dev/null
rmdir "$CGROUP_ROOT"/test1 2>/dev/null
- echo $nr_hugepgs >/proc/sys/vm/nr_hugepages
set -e
}
@@ -240,4 +241,3 @@ if [[ $do_umount ]]; then
rm -rf $CGROUP_ROOT
fi
-echo "$nr_hugepgs" > /proc/sys/vm/nr_hugepages
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 04/15] selftests/mm: fix hugetlb pathname construction in hugetlb_reparenting_test.sh
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (2 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 03/15] selftests/mm: restore default nr_hugepages value via EXIT trap in hugetlb_reparenting_test.sh Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 05/15] selftests/mm: fix cgroup task placement and drop memory.current checks " Sayali Patil
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The hugetlb_reparenting_test.sh script constructs hugetlb cgroup
memory interface file names based on the configured huge page size. The
script formats the size only in MB units, which causes mismatches on
systems using larger huge pages where the kernel exposes normalized
units (e.g. "1GB" instead of "1024MB").
As a result, the test fails to locate the corresponding cgroup files
when 1GB huge pages are configured.
Update the script to detect the huge page size and select the
appropriate unit (MB or GB) so that the constructed paths match the
kernel's hugetlb controller naming.
Also print an explicit "Fail" message when a test failure occurs to
improve result visibility.
Fixes: e487a5d513cb ("selftest/mm: make hugetlb_reparenting_test tolerant to async reparenting")
Reviewed-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
.../selftests/mm/hugetlb_reparenting_test.sh | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/mm/hugetlb_reparenting_test.sh b/tools/testing/selftests/mm/hugetlb_reparenting_test.sh
index 7ddb370e1572..00f3f3cd8909 100755
--- a/tools/testing/selftests/mm/hugetlb_reparenting_test.sh
+++ b/tools/testing/selftests/mm/hugetlb_reparenting_test.sh
@@ -48,6 +48,13 @@ function get_machine_hugepage_size() {
}
MB=$(get_machine_hugepage_size)
+if (( MB >= 1024 )); then
+ UNIT="GB"
+ MB_DISPLAY=$((MB / 1024))
+else
+ UNIT="MB"
+ MB_DISPLAY=$MB
+fi
function cleanup() {
echo cleanup
@@ -88,6 +95,7 @@ function assert_with_retry() {
if [[ $elapsed -ge $timeout ]]; then
echo "actual = $((${actual%% *} / 1024 / 1024)) MB"
echo "expected = $((${expected%% *} / 1024 / 1024)) MB"
+ echo FAIL
cleanup
exit 1
fi
@@ -108,11 +116,13 @@ function assert_state() {
fi
assert_with_retry "$CGROUP_ROOT/a/memory.$usage_file" "$expected_a"
- assert_with_retry "$CGROUP_ROOT/a/hugetlb.${MB}MB.$usage_file" "$expected_a_hugetlb"
+ assert_with_retry \
+ "$CGROUP_ROOT/a/hugetlb.${MB_DISPLAY}${UNIT}.$usage_file" "$expected_a_hugetlb"
if [[ -n "$expected_b" && -n "$expected_b_hugetlb" ]]; then
assert_with_retry "$CGROUP_ROOT/a/b/memory.$usage_file" "$expected_b"
- assert_with_retry "$CGROUP_ROOT/a/b/hugetlb.${MB}MB.$usage_file" "$expected_b_hugetlb"
+ assert_with_retry \
+ "$CGROUP_ROOT/a/b/hugetlb.${MB_DISPLAY}${UNIT}.$usage_file" "$expected_b_hugetlb"
fi
}
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 05/15] selftests/mm: fix cgroup task placement and drop memory.current checks in hugetlb_reparenting_test.sh
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (3 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 04/15] selftests/mm: fix hugetlb pathname construction " Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 06/15] selftests/mm: size tmpfs according to PMD page size in split_huge_page_test Sayali Patil
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The test currently moves the calling shell ($$) into the target cgroup
before executing write_to_hugetlbfs. This results in the shell and any
intermediate allocations being charged to the cgroup, introducing noise
and nondeterminism in accounting. It also requires moving the shell back
to the root cgroup after execution.
Spawn a helper process that joins the target cgroup and
exec()'s write_to_hugetlbfs. This ensures that only the workload is
accounted to the cgroup and avoids unintended charging from the shell.
The test currently validates both hugetlb usage and memory.current.
However, memory.current includes internal memcg allocations and
per-CPU batched accounting (MEMCG_CHARGE_BATCH), which are not
synchronized and can vary across systems, leading to
non-deterministic results.
Since hugetlb memory is accounted via hugetlb.<size>.current,
memory.current is not a reliable indicator here. Drop memory.current
checks and rely only on hugetlb controller statistics for stable
and accurate validation.
Fixes: 29750f71a9b4 ("hugetlb_cgroup: add hugetlb_cgroup reservation tests")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
.../selftests/mm/hugetlb_reparenting_test.sh | 41 ++++++++-----------
1 file changed, 17 insertions(+), 24 deletions(-)
diff --git a/tools/testing/selftests/mm/hugetlb_reparenting_test.sh b/tools/testing/selftests/mm/hugetlb_reparenting_test.sh
index 00f3f3cd8909..014201cb6427 100755
--- a/tools/testing/selftests/mm/hugetlb_reparenting_test.sh
+++ b/tools/testing/selftests/mm/hugetlb_reparenting_test.sh
@@ -105,22 +105,17 @@ function assert_with_retry() {
}
function assert_state() {
- local expected_a="$1"
- local expected_a_hugetlb="$2"
- local expected_b=""
+ local expected_a_hugetlb="$1"
local expected_b_hugetlb=""
- if [ ! -z ${3:-} ] && [ ! -z ${4:-} ]; then
- expected_b="$3"
- expected_b_hugetlb="$4"
+ if [ ! -z ${2:-} ]; then
+ expected_b_hugetlb="$2"
fi
- assert_with_retry "$CGROUP_ROOT/a/memory.$usage_file" "$expected_a"
assert_with_retry \
"$CGROUP_ROOT/a/hugetlb.${MB_DISPLAY}${UNIT}.$usage_file" "$expected_a_hugetlb"
- if [[ -n "$expected_b" && -n "$expected_b_hugetlb" ]]; then
- assert_with_retry "$CGROUP_ROOT/a/b/memory.$usage_file" "$expected_b"
+ if [[ -n "$expected_b_hugetlb" ]]; then
assert_with_retry \
"$CGROUP_ROOT/a/b/hugetlb.${MB_DISPLAY}${UNIT}.$usage_file" "$expected_b_hugetlb"
fi
@@ -154,18 +149,16 @@ write_hugetlbfs() {
local size="$3"
if [[ $cgroup2 ]]; then
- echo $$ >$CGROUP_ROOT/$cgroup/cgroup.procs
+ cg_file="$CGROUP_ROOT/$cgroup/cgroup.procs"
else
echo 0 >$CGROUP_ROOT/$cgroup/cpuset.mems
echo 0 >$CGROUP_ROOT/$cgroup/cpuset.cpus
- echo $$ >"$CGROUP_ROOT/$cgroup/tasks"
- fi
- ./write_to_hugetlbfs -p "$path" -s "$size" -m 0 -o
- if [[ $cgroup2 ]]; then
- echo $$ >$CGROUP_ROOT/cgroup.procs
- else
- echo $$ >"$CGROUP_ROOT/tasks"
+ cg_file="$CGROUP_ROOT/$cgroup/tasks"
fi
+
+ # Spawn helper to join cgroup before exec to ensure correct cgroup accounting
+ bash -c "echo \$\$ > '$cg_file'; exec ./write_to_hugetlbfs -p '$path' -s '$size' -m 0 -o" & pid=$!
+ wait "$pid"
echo
}
@@ -203,21 +196,21 @@ if [[ ! $cgroup2 ]]; then
write_hugetlbfs a "$MNT"/test $size
echo Assert memory charged correctly for parent use.
- assert_state 0 $size 0 0
+ assert_state $size 0
write_hugetlbfs a/b "$MNT"/test2 $size
echo Assert memory charged correctly for child use.
- assert_state 0 $(($size * 2)) 0 $size
+ assert_state $(($size * 2)) $size
rmdir "$CGROUP_ROOT"/a/b
echo Assert memory reparent correctly.
- assert_state 0 $(($size * 2))
+ assert_state $(($size * 2))
rm -rf "$MNT"/*
umount "$MNT"
echo Assert memory uncharged correctly.
- assert_state 0 0
+ assert_state 0
cleanup
fi
@@ -231,16 +224,16 @@ echo write
write_hugetlbfs a/b "$MNT"/test2 $size
echo Assert memory charged correctly for child only use.
-assert_state 0 $(($size)) 0 $size
+assert_state $(($size)) $size
rmdir "$CGROUP_ROOT"/a/b
echo Assert memory reparent correctly.
-assert_state 0 $size
+assert_state $size
rm -rf "$MNT"/*
umount "$MNT"
echo Assert memory uncharged correctly.
-assert_state 0 0
+assert_state 0
cleanup
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 06/15] selftests/mm: size tmpfs according to PMD page size in split_huge_page_test
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (4 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 05/15] selftests/mm: fix cgroup task placement and drop memory.current checks " Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 07/15] selftests/mm: free dynamically allocated PMD-sized buffers " Sayali Patil
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The split_file_backed_thp() test mounts a tmpfs with a fixed size of
"4m". This works on systems with smaller PMD page sizes,
but fails on configurations where the PMD huge page size is
larger (e.g. 16MB).
On such systems, the fixed 4MB tmpfs is insufficient to allocate even
a single PMD-sized THP, causing the test to fail.
Fix this by sizing the tmpfs dynamically based on the runtime
pmd_pagesize, allocating space for two PMD-sized pages.
Before patch:
running ./split_huge_page_test /tmp/xfs_dir_YTrI5E
--------------------------------------------------
TAP version 13
1..55
ok 1 Split zero filled huge pages successful
ok 2 Split huge pages to order 0 successful
ok 3 Split huge pages to order 2 successful
ok 4 Split huge pages to order 3 successful
ok 5 Split huge pages to order 4 successful
ok 6 Split huge pages to order 5 successful
ok 7 Split huge pages to order 6 successful
ok 8 Split huge pages to order 7 successful
ok 9 Split PTE-mapped huge pages successful
Please enable pr_debug in split_huge_pages_in_file() for more info.
Failed to write data to testing file: Success (0)
Bail out! Error occurred
Planned tests != run tests (55 != 9)
Totals: pass:9 fail:0 xfail:0 xpass:0 skip:0 error:0
[FAIL]
After patch:
running ./split_huge_page_test /tmp/xfs_dir_bMvj6o
--------------------------------------------------
TAP version 13
1..55
ok 1 Split zero filled huge pages successful
ok 2 Split huge pages to order 0 successful
ok 3 Split huge pages to order 2 successful
ok 4 Split huge pages to order 3 successful
ok 5 Split huge pages to order 4 successful
ok 6 Split huge pages to order 5 successful
ok 7 Split huge pages to order 6 successful
ok 8 Split huge pages to order 7 successful
ok 9 Split PTE-mapped huge pages successful
Please enable pr_debug in split_huge_pages_in_file() for more info.
Please check dmesg for more information
ok 10 File-backed THP split to order 0 test done
Please enable pr_debug in split_huge_pages_in_file() for more info.
Please check dmesg for more information
ok 11 File-backed THP split to order 1 test done
Please enable pr_debug in split_huge_pages_in_file() for more info.
Please check dmesg for more information
ok 12 File-backed THP split to order 2 test done
...
ok 55 Split PMD-mapped pagecache folio to order 7 at
in-folio offset 128 passed
Totals: pass:55 fail:0 xfail:0 xpass:0 skip:0 error:0
[PASS]
ok 1 split_huge_page_test /tmp/xfs_dir_bMvj6o
Fixes: fbe37501b252 ("mm: huge_memory: debugfs for file-backed THP split")
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: David Hildenbrand (Arm) <david@kernel.org>
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/split_huge_page_test.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c
index e0167111bdd1..57e8a1c9647a 100644
--- a/tools/testing/selftests/mm/split_huge_page_test.c
+++ b/tools/testing/selftests/mm/split_huge_page_test.c
@@ -484,6 +484,8 @@ static void split_file_backed_thp(int order)
char tmpfs_template[] = "/tmp/thp_split_XXXXXX";
const char *tmpfs_loc = mkdtemp(tmpfs_template);
char testfile[INPUT_MAX];
+ unsigned long size = 2 * pmd_pagesize;
+ char opts[64];
ssize_t num_written, num_read;
char *file_buf1, *file_buf2;
uint64_t pgoff_start = 0, pgoff_end = 1024;
@@ -503,7 +505,8 @@ static void split_file_backed_thp(int order)
file_buf1[i] = (char)i;
memset(file_buf2, 0, pmd_pagesize);
- status = mount("tmpfs", tmpfs_loc, "tmpfs", 0, "huge=always,size=4m");
+ snprintf(opts, sizeof(opts), "huge=always,size=%lu", size);
+ status = mount("tmpfs", tmpfs_loc, "tmpfs", 0, opts);
if (status)
ksft_exit_fail_msg("Unable to create a tmpfs for testing\n");
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 07/15] selftests/mm: free dynamically allocated PMD-sized buffers in split_huge_page_test
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (5 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 06/15] selftests/mm: size tmpfs according to PMD page size in split_huge_page_test Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 08/15] selftest/mm: align memory size to huge page size in hugepage-mremap test Sayali Patil
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
Dynamically allocated buffers of PMD size for file-backed
THP operations (file_buf1 and file_buf2) were not freed on
the success path and some failure paths. Since the
function is called repeatedly in a loop for each split order,
this can cause significant memory leaks.
On architectures with large PMD sizes, repeated leaks
could exhaust system memory and trigger the OOM killer
during test execution.
Ensure all allocated buffers are freed to maintain
stable repeated test runs.
Fixes: 035a112e5fd5 ("selftests/mm: make file-backed THP split work by writing PMD size data")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
.../selftests/mm/split_huge_page_test.c | 22 ++++++++++++++-----
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c
index 57e8a1c9647a..98319cfaf9a8 100644
--- a/tools/testing/selftests/mm/split_huge_page_test.c
+++ b/tools/testing/selftests/mm/split_huge_page_test.c
@@ -487,12 +487,15 @@ static void split_file_backed_thp(int order)
unsigned long size = 2 * pmd_pagesize;
char opts[64];
ssize_t num_written, num_read;
- char *file_buf1, *file_buf2;
+ char *file_buf1 = NULL, *file_buf2 = NULL;
uint64_t pgoff_start = 0, pgoff_end = 1024;
int i;
ksft_print_msg("Please enable pr_debug in split_huge_pages_in_file() for more info.\n");
+ if (!tmpfs_loc)
+ ksft_exit_fail_msg("mkdtemp failed\n");
+
file_buf1 = (char *)malloc(pmd_pagesize);
file_buf2 = (char *)malloc(pmd_pagesize);
@@ -508,8 +511,10 @@ static void split_file_backed_thp(int order)
snprintf(opts, sizeof(opts), "huge=always,size=%lu", size);
status = mount("tmpfs", tmpfs_loc, "tmpfs", 0, opts);
- if (status)
- ksft_exit_fail_msg("Unable to create a tmpfs for testing\n");
+ if (status) {
+ ksft_print_msg("Unable to create a tmpfs for testing\n");
+ goto out;
+ }
status = snprintf(testfile, INPUT_MAX, "%s/thp_file", tmpfs_loc);
if (status >= INPUT_MAX) {
@@ -561,10 +566,13 @@ static void split_file_backed_thp(int order)
status = umount(tmpfs_loc);
if (status) {
- rmdir(tmpfs_loc);
- ksft_exit_fail_msg("Unable to umount %s\n", tmpfs_loc);
+ ksft_print_msg("Unable to umount %s\n", tmpfs_loc);
+ goto out;
}
+ free(file_buf1);
+ free(file_buf2);
+
status = rmdir(tmpfs_loc);
if (status)
ksft_exit_fail_msg("cannot remove tmp dir: %s\n", strerror(errno));
@@ -577,8 +585,10 @@ static void split_file_backed_thp(int order)
close(fd);
cleanup:
umount(tmpfs_loc);
- rmdir(tmpfs_loc);
out:
+ free(file_buf1);
+ free(file_buf2);
+ rmdir(tmpfs_loc);
ksft_exit_fail_msg("Error occurred\n");
}
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 08/15] selftest/mm: align memory size to huge page size in hugepage-mremap test
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (6 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 07/15] selftests/mm: free dynamically allocated PMD-sized buffers " Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 09/15] selftest/mm: register existing mapping with userfaultfd in hugepage-mremap Sayali Patil
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The hugepage-mremap selftest uses a default mapping size of 10MB
when no argument is provided. This size is not guaranteed to be
aligned to the system hugepage size, which can cause munmap() to fail
and mremap() to succeed where a failure is expected.
Align the mapping length to the runtime hugepage size using
default_huge_page_size() to ensure the mapping is properly
aligned. Also handle the case where
default_huge_page_size() returns 0 by skipping the test.
Before patch:
running ./hugepage-mremap
------------------------------
TAP version 13
1..1
Map haddr: Returned address is 0x7eaa40000000
Map daddr: Returned address is 0x7daa40000000
Map vaddr: Returned address is 0x7faa40000000
Address returned by mmap() = 0x7fffaa600000
Mremap: Returned address is 0x7faa40000000
First hex is 0
First hex is 3020100
Bail out! mremap: Expected failure, but call succeeded
Planned tests != run tests (1 != 0)
Totals: pass:0 fail:0 xfail:0 xpass:0 skip:0 error:0
[FAIL]
not ok 1 hugepage-mremap # exit=1
After patch:
running ./hugepage-mremap
-------------------------
TAP version 13
1..1
Map haddr: Returned address is 0x7eaa40000000
Map daddr: Returned address is 0x7daa40000000
Map vaddr: Returned address is 0x7faa40000000
Address returned by mmap() = 0x7fff13000000
Mremap: Returned address is 0x7faa40000000
First hex is 0
First hex is 3020100
ok 1 Read same data
Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
[PASS]
ok 1 hugepage-mremap
Fixes: f77a286de48c ("mm, hugepages: make memory size variable in hugepage-mremap selftest")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/hugepage-mremap.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/tools/testing/selftests/mm/hugepage-mremap.c b/tools/testing/selftests/mm/hugepage-mremap.c
index b8f7d92e5a35..f66e4d806477 100644
--- a/tools/testing/selftests/mm/hugepage-mremap.c
+++ b/tools/testing/selftests/mm/hugepage-mremap.c
@@ -32,6 +32,7 @@
#define PROTECTION (PROT_READ | PROT_WRITE | PROT_EXEC)
#define FLAGS (MAP_SHARED | MAP_ANONYMOUS)
+#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
static void check_bytes(char *addr)
{
@@ -110,6 +111,7 @@ int main(int argc, char *argv[])
{
size_t length = 0;
int ret = 0, fd;
+ size_t hpage_size;
ksft_print_header();
ksft_set_plan(1);
@@ -126,6 +128,14 @@ int main(int argc, char *argv[])
length = DEFAULT_LENGTH_MB;
length = MB_TO_BYTES(length);
+
+ hpage_size = default_huge_page_size();
+ if (!hpage_size)
+ ksft_exit_skip("Unable to determine huge page size\n");
+
+ /* Ensure length is hugepage aligned */
+ length = ALIGN(length, hpage_size);
+
fd = memfd_create(argv[0], MFD_HUGETLB);
if (fd < 0)
ksft_exit_fail_msg("Open failed: %s\n", strerror(errno));
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 09/15] selftest/mm: register existing mapping with userfaultfd in hugepage-mremap
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (7 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 08/15] selftest/mm: align memory size to huge page size in hugepage-mremap test Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 10/15] selftests/mm: ensure destination is hugetlb-backed " Sayali Patil
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
Previously, register_region_with_uffd() created a new anonymous
mapping and overwrote the address supplied by the caller before
registering the range with userfaultfd.
As a result, userfaultfd was applied to an unrelated anonymous mapping
instead of the hugetlb region used by the test.
Remove the extra mmap() and register the caller-provided address range
directly using UFFDIO_REGISTER_MODE_MISSING, so that faults are
generated for the hugetlb mapping used by the test.
This ensures userfaultfd operates on the actual hugetlb test region and
validates the expected fault handling.
Before patch:
running ./hugepage-mremap
-------------------------
TAP version 13
1..1
Map haddr: Returned address is 0x7eaa40000000
Map daddr: Returned address is 0x7daa40000000
Map vaddr: Returned address is 0x7faa40000000
Address returned by mmap() = 0x7fff9d000000
Mremap: Returned address is 0x7faa40000000
First hex is 0
First hex is 3020100
ok 1 Read same data
Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
[PASS]
ok 1 hugepage-mremap
After patch:
running ./hugepage-mremap
-------------------------
TAP version 13
1..1
Map haddr: Returned address is 0x7eaa40000000
Map daddr: Returned address is 0x7daa40000000
Map vaddr: Returned address is 0x7faa40000000
Registered memory at address 0x7eaa40000000 with userfaultfd
Mremap: Returned address is 0x7faa40000000
First hex is 0
First hex is 3020100
ok 1 Read same data
Totals: pass:1 fail:0 xfail:0 xpass:0 skip:0 error:0
[PASS]
ok 1 hugepage-mremap
Fixes: 12b613206474 ("mm, hugepages: add hugetlb vma mremap() test")
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/hugepage-mremap.c | 21 +++++---------------
1 file changed, 5 insertions(+), 16 deletions(-)
diff --git a/tools/testing/selftests/mm/hugepage-mremap.c b/tools/testing/selftests/mm/hugepage-mremap.c
index f66e4d806477..68c35d1d8a5f 100644
--- a/tools/testing/selftests/mm/hugepage-mremap.c
+++ b/tools/testing/selftests/mm/hugepage-mremap.c
@@ -86,25 +86,14 @@ static void register_region_with_uffd(char *addr, size_t len)
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
ksft_exit_fail_msg("ioctl-UFFDIO_API: %s\n", strerror(errno));
- /* Create a private anonymous mapping. The memory will be
- * demand-zero paged--that is, not yet allocated. When we
- * actually touch the memory, it will be allocated via
- * the userfaultfd.
- */
-
- addr = mmap(NULL, len, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (addr == MAP_FAILED)
- ksft_exit_fail_msg("mmap: %s\n", strerror(errno));
-
- ksft_print_msg("Address returned by mmap() = %p\n", addr);
-
- /* Register the memory range of the mapping we just created for
- * handling by the userfaultfd object. In mode, we request to track
- * missing pages (i.e., pages that have not yet been faulted in).
+ /* Register the passed memory range for handling by the userfaultfd object.
+ * In mode, we request to track missing pages
+ * (i.e., pages that have not yet been faulted in).
*/
if (uffd_register(uffd, addr, len, true, false, false))
ksft_exit_fail_msg("ioctl-UFFDIO_REGISTER: %s\n", strerror(errno));
+
+ ksft_print_msg("Registered memory at address %p with userfaultfd\n", addr);
}
int main(int argc, char *argv[])
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 10/15] selftests/mm: ensure destination is hugetlb-backed in hugepage-mremap
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (8 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 09/15] selftest/mm: register existing mapping with userfaultfd in hugepage-mremap Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 11/15] selftests/mm: skip uffd-wp-mremap if UFFD write-protect is unsupported Sayali Patil
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The hugepage-mremap selftest reserves the destination address using a
anonymous base-page mapping before calling mremap() with MREMAP_FIXED,
while the source region is hugetlb-backed.
When remapping a hugetlb mapping into a base-page VMA may fail with:
mremap: Device or resource busy
This is observed on powerpc hash MMU systems where slice constraints
and page size incompatibilities prevent the remap.
Ensure the destination region is created using MAP_HUGETLB so that both
source and destination VMAs are hugetlb-backed and compatible.
Update the FLAGS macro to include MAP_HUGETLB | MAP_SHARED
so that both mappings are hugetlb-backed and compatible.
Also use the macro for the mmap() calls to avoid repeating
the flag combination.
This ensures the test reliably exercises hugetlb mremap instead of
failing due to VMA type mismatch.
Fixes: 12b613206474 ("mm, hugepages: add hugetlb vma mremap() test")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/hugepage-mremap.c | 11 ++++-------
1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/mm/hugepage-mremap.c b/tools/testing/selftests/mm/hugepage-mremap.c
index 68c35d1d8a5f..a442d01908cc 100644
--- a/tools/testing/selftests/mm/hugepage-mremap.c
+++ b/tools/testing/selftests/mm/hugepage-mremap.c
@@ -31,7 +31,7 @@
#define MB_TO_BYTES(x) (x * 1024 * 1024)
#define PROTECTION (PROT_READ | PROT_WRITE | PROT_EXEC)
-#define FLAGS (MAP_SHARED | MAP_ANONYMOUS)
+#define FLAGS (MAP_HUGETLB | MAP_SHARED)
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
static void check_bytes(char *addr)
@@ -131,23 +131,20 @@ int main(int argc, char *argv[])
/* mmap to a PUD aligned address to hopefully trigger pmd sharing. */
unsigned long suggested_addr = 0x7eaa40000000;
- void *haddr = mmap((void *)suggested_addr, length, PROTECTION,
- MAP_HUGETLB | MAP_SHARED | MAP_POPULATE, fd, 0);
+ void *haddr = mmap((void *)suggested_addr, length, PROTECTION, FLAGS, fd, 0);
ksft_print_msg("Map haddr: Returned address is %p\n", haddr);
if (haddr == MAP_FAILED)
ksft_exit_fail_msg("mmap1: %s\n", strerror(errno));
/* mmap again to a dummy address to hopefully trigger pmd sharing. */
suggested_addr = 0x7daa40000000;
- void *daddr = mmap((void *)suggested_addr, length, PROTECTION,
- MAP_HUGETLB | MAP_SHARED | MAP_POPULATE, fd, 0);
+ void *daddr = mmap((void *)suggested_addr, length, PROTECTION, FLAGS, fd, 0);
ksft_print_msg("Map daddr: Returned address is %p\n", daddr);
if (daddr == MAP_FAILED)
ksft_exit_fail_msg("mmap3: %s\n", strerror(errno));
suggested_addr = 0x7faa40000000;
- void *vaddr =
- mmap((void *)suggested_addr, length, PROTECTION, FLAGS, -1, 0);
+ void *vaddr = mmap((void *)suggested_addr, length, PROTECTION, FLAGS, fd, 0);
ksft_print_msg("Map vaddr: Returned address is %p\n", vaddr);
if (vaddr == MAP_FAILED)
ksft_exit_fail_msg("mmap2: %s\n", strerror(errno));
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 11/15] selftests/mm: skip uffd-wp-mremap if UFFD write-protect is unsupported
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (9 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 10/15] selftests/mm: ensure destination is hugetlb-backed " Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 12/15] selftests/mm: skip uffd-stress test when nr_pages_per_cpu is zero Sayali Patil
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The uffd-wp-mremap test requires the UFFD_FEATURE_PAGEFAULT_FLAG_WP
capability. On systems where userfaultfd write-protect is
not supported, uffd_register() fails and the test reports failures.
Check for the required feature at startup and skip the test when the
UFFD_FEATURE_PAGEFAULT_FLAG_WP capability is not present,
preventing false failures on unsupported configurations.
Before patch:
running ./uffd-wp-mremap
------------------------
[INFO] detected THP size: 256 KiB
[INFO] detected THP size: 512 KiB
[INFO] detected THP size: 1024 KiB
[INFO] detected THP size: 2048 KiB
[INFO] detected hugetlb page size: 2048 KiB
[INFO] detected hugetlb page size: 1048576 KiB
1..24
[RUN] test_one_folio(size=65536, private=false, swapout=false,
hugetlb=false)
not ok 1 uffd_register() failed
[RUN] test_one_folio(size=65536, private=true, swapout=false,
hugetlb=false)
not ok 2 uffd_register() failed
[RUN] test_one_folio(size=65536, private=false, swapout=true,
hugetlb=false)
not ok 3 uffd_register() failed
[RUN] test_one_folio(size=65536, private=true, swapout=true,
hugetlb=false)
not ok 4 uffd_register() failed
[RUN] test_one_folio(size=262144, private=false, swapout=false,
hugetlb=false)
not ok 5 uffd_register() failed
[RUN] test_one_folio(size=524288, private=false, swapout=false,
hugetlb=false)
not ok 6 uffd_register() failed
.
.
.
Bail out! 24 out of 24 tests failed
Totals: pass:0 fail:24 xfail:0 xpass:0 skip:0 error:0
[FAIL]
not ok 1 uffd-wp-mremap # exit=1
After patch:
running ./uffd-wp-mremap
------------------------
1..0 # SKIP uffd-wp feature not supported
[SKIP]
ok 1 uffd-wp-mremap # SKIP
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/uffd-wp-mremap.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/tools/testing/selftests/mm/uffd-wp-mremap.c b/tools/testing/selftests/mm/uffd-wp-mremap.c
index 17186d4a4147..8f288484d5f5 100644
--- a/tools/testing/selftests/mm/uffd-wp-mremap.c
+++ b/tools/testing/selftests/mm/uffd-wp-mremap.c
@@ -19,6 +19,17 @@ static size_t thpsizes[20];
static int nr_hugetlbsizes;
static size_t hugetlbsizes[10];
+static void check_uffd_wp_feature_supported(void)
+{
+ uint64_t features = 0;
+
+ if (uffd_get_features(&features))
+ ksft_exit_skip("failed to get available features (%d)\n", errno);
+
+ if (!(features & UFFD_FEATURE_PAGEFAULT_FLAG_WP))
+ ksft_exit_skip("uffd-wp feature not supported\n");
+}
+
static int detect_thp_sizes(size_t sizes[], int max)
{
int count = 0;
@@ -336,6 +347,8 @@ int main(int argc, char **argv)
struct thp_settings settings;
int i, j, plan = 0;
+ check_uffd_wp_feature_supported();
+
pagesize = getpagesize();
nr_thpsizes = detect_thp_sizes(thpsizes, ARRAY_SIZE(thpsizes));
nr_hugetlbsizes = detect_hugetlb_page_sizes(hugetlbsizes,
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 12/15] selftests/mm: skip uffd-stress test when nr_pages_per_cpu is zero
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (10 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 11/15] selftests/mm: skip uffd-wp-mremap if UFFD write-protect is unsupported Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 13/15] selftests/mm: move hwpoison setup into run_test() and silence modprobe output for memory-failure category Sayali Patil
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
uffd-stress currently fails when the computed nr_pages_per_cpu
evaluates to zero:
nr_pages_per_cpu = bytes / page_size / nr_parallel
This can occur on systems with large hugepage sizes (e.g. 1GB) and a
high number of CPUs, where the total allocated memory is sufficient
overall but not enough to provide at least one page per cpu.
In such cases, the failure is due to insufficient test resources
rather than incorrect kernel behaviour. Update the test
to treat this condition as a test skip instead of reporting an error.
Fixes: db0f1c138f18 ("selftests/mm: print some details when uffd-stress gets bad params")
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Tested-by: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/uffd-stress.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/mm/uffd-stress.c b/tools/testing/selftests/mm/uffd-stress.c
index 700fbaa18d44..b8f22ea859a6 100644
--- a/tools/testing/selftests/mm/uffd-stress.c
+++ b/tools/testing/selftests/mm/uffd-stress.c
@@ -491,9 +491,9 @@ int main(int argc, char **argv)
gopts->nr_pages_per_cpu = bytes / gopts->page_size / gopts->nr_parallel;
if (!gopts->nr_pages_per_cpu) {
- _err("pages_per_cpu = 0, cannot test (%lu / %lu / %lu)",
- bytes, gopts->page_size, gopts->nr_parallel);
- usage();
+ ksft_print_msg("pages_per_cpu = 0, cannot test (%lu / %lu / %lu)\n",
+ bytes, gopts->page_size, gopts->nr_parallel);
+ return KSFT_SKIP;
}
bounces = atoi(argv[3]);
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 13/15] selftests/mm: move hwpoison setup into run_test() and silence modprobe output for memory-failure category
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (11 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 12/15] selftests/mm: skip uffd-stress test when nr_pages_per_cpu is zero Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 14/15] selftests/mm: clarify alternate unmapping in compaction_test Sayali Patil
2026-04-06 9:19 ` [PATCH v4 15/15] selftests/cgroup: extend test_hugetlb_memcg.c to support all huge page sizes Sayali Patil
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
run_vmtests.sh contains special handling to ensure the hwpoison_inject
module is available for the memory-failure tests. This logic was
implemented outside of run_test(), making the setup category-specific
but managed globally.
Move the hwpoison_inject handling into run_test() and restrict it
to the memory-failure category so that:
1. the module is checked and loaded only when memory-failure tests run,
2. the test is skipped if the module or the debugfs interface
(/sys/kernel/debug/hwpoison/) is not available.
3. the module is unloaded after the test if it was loaded by the script.
This localizes category-specific setup and makes the test flow
consistent with other per-category preparations.
While updating this logic, fix the module availability check.
The script previously used:
modprobe -R hwpoison_inject
The -R option prints the resolved module name to stdout, causing every
run to print:
hwpoison_inject
in the test output, even when no action is required, introducing
unnecessary noise.
Replace this with:
modprobe -n hwpoison_inject
which verifies that the module is loadable without producing output,
keeping the selftest logs clean and consistent.
Also, ensure that skipped tests do not override a previously recorded
failure. A skipped test currently sets exitcode to ksft_skip even if a
prior test has failed, which can mask failures in the final exit status.
Update the logic to only set exitcode to ksft_skip when no failure has
been recorded.
Fixes: ff4ef2fbd101 ("selftests/mm: add memory failure anonymous page test")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/run_vmtests.sh | 52 ++++++++++++++---------
1 file changed, 33 insertions(+), 19 deletions(-)
diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh
index afdcfd0d7cef..17c9bd910c47 100755
--- a/tools/testing/selftests/mm/run_vmtests.sh
+++ b/tools/testing/selftests/mm/run_vmtests.sh
@@ -235,6 +235,7 @@ pretty_name() {
run_test() {
if test_selected ${CATEGORY}; then
local skip=0
+ local LOADED_MOD=0
# On memory constrainted systems some tests can fail to allocate hugepages.
# perform some cleanup before the test for a higher success rate.
@@ -250,6 +251,28 @@ run_test() {
fi
fi
+ # Ensure hwpoison_inject is available for memory-failure tests
+ if [ "${CATEGORY}" = "memory-failure" ]; then
+ # Try to load hwpoison_inject if not present.
+ HWPOISON_DIR=/sys/kernel/debug/hwpoison/
+ if [ ! -d "$HWPOISON_DIR" ]; then
+ if ! modprobe -n hwpoison_inject > /dev/null 2>&1; then
+ echo "Module hwpoison_inject not found, skipping..." \
+ | tap_prefix
+ skip=1
+ else
+ modprobe hwpoison_inject > /dev/null 2>&1
+ LOADED_MOD=1
+ if [ ! -d "$HWPOISON_DIR" ]; then
+ echo "hwpoison debugfs interface not present" \
+ | tap_prefix
+ skip=1
+ fi
+ fi
+ fi
+
+ fi
+
local test=$(pretty_name "$*")
local title="running $*"
local sep=$(echo -n "$title" | tr "[:graph:][:space:]" -)
@@ -261,6 +284,12 @@ run_test() {
else
local ret=$ksft_skip
fi
+
+ # Unload hwpoison_inject if we loaded it
+ if [ -n "${LOADED_MOD}" ]; then
+ modprobe -r hwpoison_inject > /dev/null 2>&1
+ fi
+
count_total=$(( count_total + 1 ))
if [ $ret -eq 0 ]; then
count_pass=$(( count_pass + 1 ))
@@ -270,7 +299,9 @@ run_test() {
count_skip=$(( count_skip + 1 ))
echo "[SKIP]" | tap_prefix
echo "ok ${count_total} ${test} # SKIP" | tap_output
- exitcode=$ksft_skip
+ if [ $exitcode -eq 0 ]; then
+ exitcode=$ksft_skip
+ fi
else
count_fail=$(( count_fail + 1 ))
echo "[FAIL]" | tap_prefix
@@ -529,24 +560,7 @@ CATEGORY="page_frag" run_test ./test_page_frag.sh nonaligned
CATEGORY="rmap" run_test ./rmap
-# Try to load hwpoison_inject if not present.
-HWPOISON_DIR=/sys/kernel/debug/hwpoison/
-if [ ! -d "$HWPOISON_DIR" ]; then
- if ! modprobe -q -R hwpoison_inject; then
- echo "Module hwpoison_inject not found, skipping..."
- else
- modprobe hwpoison_inject > /dev/null 2>&1
- LOADED_MOD=1
- fi
-fi
-
-if [ -d "$HWPOISON_DIR" ]; then
- CATEGORY="memory-failure" run_test ./memory-failure
-fi
-
-if [ -n "${LOADED_MOD}" ]; then
- modprobe -r hwpoison_inject > /dev/null 2>&1
-fi
+CATEGORY="memory-failure" run_test ./memory-failure
if [ "${HAVE_HUGEPAGES}" = 1 ]; then
echo "$orig_nr_hugepgs" > /proc/sys/vm/nr_hugepages
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 14/15] selftests/mm: clarify alternate unmapping in compaction_test
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (12 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 13/15] selftests/mm: move hwpoison setup into run_test() and silence modprobe output for memory-failure category Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
2026-04-06 9:19 ` [PATCH v4 15/15] selftests/cgroup: extend test_hugetlb_memcg.c to support all huge page sizes Sayali Patil
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
Add a comment explaining that every other entry in the list is
unmapped to intentionally create fragmentation with
locked pages before invoking check_compaction().
Fixes: bd67d5c15cc1 ("Test compaction of mlocked memory")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
tools/testing/selftests/mm/compaction_test.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/tools/testing/selftests/mm/compaction_test.c b/tools/testing/selftests/mm/compaction_test.c
index 30209c40b697..e1610e2fbdf6 100644
--- a/tools/testing/selftests/mm/compaction_test.c
+++ b/tools/testing/selftests/mm/compaction_test.c
@@ -261,6 +261,9 @@ int main(int argc, char **argv)
mem_fragmentable_MB -= MAP_SIZE_MB;
}
+ /* Unmap every other entry in the list to create fragmentation with
+ * locked pages before invoking check_compaction().
+ */
for (entry = list; entry != NULL; entry = entry->next) {
munmap(entry->map, MAP_SIZE);
if (!entry->next)
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v4 15/15] selftests/cgroup: extend test_hugetlb_memcg.c to support all huge page sizes
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
` (13 preceding siblings ...)
2026-04-06 9:19 ` [PATCH v4 14/15] selftests/mm: clarify alternate unmapping in compaction_test Sayali Patil
@ 2026-04-06 9:19 ` Sayali Patil
14 siblings, 0 replies; 16+ messages in thread
From: Sayali Patil @ 2026-04-06 9:19 UTC (permalink / raw)
To: Andrew Morton, Shuah Khan, linux-mm, linux-kernel,
linux-kselftest, Ritesh Harjani
Cc: David Hildenbrand, Zi Yan, Michal Hocko, Oscar Salvador,
Lorenzo Stoakes, Dev Jain, Liam.Howlett, linuxppc-dev, Miaohe Lin,
Venkat Rao Bagalkote, Sayali Patil
The hugetlb memcg selftest was previously skipped when the configured
huge page size was not 2MB, preventing the test from running on systems
using other default huge page sizes.
Detect the system's configured huge page size at runtime and use it for
the allocation instead of assuming a fixed 2MB size. This allows the
test to run on configurations using non-2MB huge pages and avoids
unnecessary skips.
Fixes: c0dddb7aa5f8 ("selftests: add a selftest to verify hugetlb usage in memcg")
Signed-off-by: Sayali Patil <sayalip@linux.ibm.com>
---
.../selftests/cgroup/test_hugetlb_memcg.c | 90 ++++++++++++++-----
1 file changed, 68 insertions(+), 22 deletions(-)
diff --git a/tools/testing/selftests/cgroup/test_hugetlb_memcg.c b/tools/testing/selftests/cgroup/test_hugetlb_memcg.c
index f451aa449be6..e6157a784138 100644
--- a/tools/testing/selftests/cgroup/test_hugetlb_memcg.c
+++ b/tools/testing/selftests/cgroup/test_hugetlb_memcg.c
@@ -7,15 +7,21 @@
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
+#include <stdint.h>
#include "kselftest.h"
#include "cgroup_util.h"
#define ADDR ((void *)(0x0UL))
#define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB)
-/* mapping 8 MBs == 4 hugepages */
-#define LENGTH (8UL*1024*1024)
#define PROTECTION (PROT_READ | PROT_WRITE)
+/*
+ * This value matches the kernel's MEMCG_CHARGE_BATCH definition:
+ * see include/linux/memcontrol.h. If the kernel value changes, this
+ * test constant must be updated accordingly to stay consistent.
+ */
+#define MEMCG_CHARGE_BATCH 64U
+
/* borrowed from mm/hmm-tests.c */
static long get_hugepage_size(void)
{
@@ -84,11 +90,11 @@ static unsigned int check_first(char *addr)
return *(unsigned int *)addr;
}
-static void write_data(char *addr)
+static void write_data(char *addr, size_t length)
{
unsigned long i;
- for (i = 0; i < LENGTH; i++)
+ for (i = 0; i < length; i++)
*(addr + i) = (char)i;
}
@@ -96,26 +102,33 @@ static int hugetlb_test_program(const char *cgroup, void *arg)
{
char *test_group = (char *)arg;
void *addr;
+ long hpage_size, batch_bytes;
long old_current, expected_current, current;
int ret = EXIT_FAILURE;
+ size_t length;
+ int pagesize, nr_pages;
+
+ pagesize = getpagesize();
+ hpage_size = get_hugepage_size() * 1024;
+ length = 4 * hpage_size;
+ batch_bytes = MEMCG_CHARGE_BATCH * pagesize;
old_current = cg_read_long(test_group, "memory.current");
set_nr_hugepages(20);
current = cg_read_long(test_group, "memory.current");
- if (current - old_current >= MB(2)) {
+ if (current - old_current >= hpage_size) {
ksft_print_msg(
"setting nr_hugepages should not increase hugepage usage.\n");
ksft_print_msg("before: %ld, after: %ld\n", old_current, current);
return EXIT_FAILURE;
}
- addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0);
- if (addr == MAP_FAILED) {
- ksft_print_msg("fail to mmap.\n");
- return EXIT_FAILURE;
- }
+ addr = mmap(ADDR, length, PROTECTION, FLAGS, 0, 0);
+ if (addr == MAP_FAILED)
+ ksft_exit_skip("mmap failed, not enough memory.\n");
+
current = cg_read_long(test_group, "memory.current");
- if (current - old_current >= MB(2)) {
+ if (current - old_current >= hpage_size) {
ksft_print_msg("mmap should not increase hugepage usage.\n");
ksft_print_msg("before: %ld, after: %ld\n", old_current, current);
goto out_failed_munmap;
@@ -124,10 +137,34 @@ static int hugetlb_test_program(const char *cgroup, void *arg)
/* read the first page */
check_first(addr);
- expected_current = old_current + MB(2);
+ nr_pages = hpage_size / pagesize;
+ expected_current = old_current + hpage_size;
current = cg_read_long(test_group, "memory.current");
- if (!values_close(expected_current, current, 5)) {
- ksft_print_msg("memory usage should increase by around 2MB.\n");
+ if (nr_pages < MEMCG_CHARGE_BATCH &&
+ (current == old_current ||
+ values_close(old_current + batch_bytes, current, 5))) {
+ /*
+ * Memory cgroup charging uses per-CPU stocks and batched updates to the
+ * memcg usage counters. For hugetlb allocations, the number of pages
+ * that memcg charges is expressed in base pages (nr_pages), not
+ * in hugepage units. When the charge for an allocation is smaller than
+ * the internal batching threshold (nr_pages < MEMCG_CHARGE_BATCH),
+ * it may be fully satisfied from the CPU’s local stock. In such
+ * cases memory.current does not necessarily increase.
+ *
+ * If the local stock is insufficient, it may be refilled in batches
+ * of MEMCG_CHARGE_BATCH base pages, causing memory.current to increase
+ * by more than the allocation size.
+ *
+ * Therefore, Treat both a zero delta and a batched increase as a
+ * valid behaviour here.
+ */
+ if (current == old_current)
+ ksft_print_msg("allocation consumed from local stock.\n");
+ else
+ ksft_print_msg("memcg charge batched via stock refill.\n");
+ } else if (!values_close(expected_current, current, 5)) {
+ ksft_print_msg("memory usage should increase by ~1 huge page.\n");
ksft_print_msg(
"expected memory: %ld, actual memory: %ld\n",
expected_current, current);
@@ -135,11 +172,11 @@ static int hugetlb_test_program(const char *cgroup, void *arg)
}
/* write to the whole range */
- write_data(addr);
+ write_data(addr, length);
current = cg_read_long(test_group, "memory.current");
- expected_current = old_current + MB(8);
+ expected_current = old_current + length;
if (!values_close(expected_current, current, 5)) {
- ksft_print_msg("memory usage should increase by around 8MB.\n");
+ ksft_print_msg("memory usage should increase by around 4 huge pages.\n");
ksft_print_msg(
"expected memory: %ld, actual memory: %ld\n",
expected_current, current);
@@ -147,7 +184,7 @@ static int hugetlb_test_program(const char *cgroup, void *arg)
}
/* unmap the whole range */
- munmap(addr, LENGTH);
+ munmap(addr, length);
current = cg_read_long(test_group, "memory.current");
expected_current = old_current;
if (!values_close(expected_current, current, 5)) {
@@ -162,14 +199,17 @@ static int hugetlb_test_program(const char *cgroup, void *arg)
return ret;
out_failed_munmap:
- munmap(addr, LENGTH);
+ munmap(addr, length);
return ret;
}
static int test_hugetlb_memcg(char *root)
{
int ret = KSFT_FAIL;
+ int num_pages = 20;
+ long hpage_size = get_hugepage_size();
char *test_group;
+ uint64_t limit;
test_group = cg_name(root, "hugetlb_memcg_test");
if (!test_group || cg_create(test_group)) {
@@ -177,7 +217,9 @@ static int test_hugetlb_memcg(char *root)
goto out;
}
- if (cg_write(test_group, "memory.max", "100M")) {
+ limit = (uint64_t)num_pages * hpage_size * 1024ULL;
+
+ if (cg_write_numeric(test_group, "memory.max", limit)) {
ksft_print_msg("fail to set cgroup memory limit.\n");
goto out;
}
@@ -200,6 +242,7 @@ int main(int argc, char **argv)
{
char root[PATH_MAX];
int ret = EXIT_SUCCESS, has_memory_hugetlb_acc;
+ long val;
has_memory_hugetlb_acc = proc_mount_contains("memory_hugetlb_accounting");
if (has_memory_hugetlb_acc < 0)
@@ -208,12 +251,15 @@ int main(int argc, char **argv)
ksft_exit_skip("memory hugetlb accounting is disabled\n");
/* Unit is kB! */
- if (get_hugepage_size() != 2048) {
- ksft_print_msg("test_hugetlb_memcg requires 2MB hugepages\n");
+ val = get_hugepage_size();
+ if (val < 0) {
+ ksft_print_msg("Failed to read hugepage size\n");
ksft_test_result_skip("test_hugetlb_memcg\n");
return ret;
}
+ ksft_print_msg("Hugepage size: %ld kB\n", val);
+
if (cg_find_unified_root(root, sizeof(root), NULL))
ksft_exit_skip("cgroup v2 isn't mounted\n");
--
2.52.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-04-06 9:25 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-06 9:19 [PATCH v4 00/15] selftests/mm: fix failures and robustness improvements Sayali Patil
2026-04-06 9:19 ` [PATCH v4 01/15] selftests/mm: restore default nr_hugepages value via EXIT trap in charge_reserved_hugetlb.sh Sayali Patil
2026-04-06 9:19 ` [PATCH v4 02/15] selftests/mm: fix hugetlb pathname construction " Sayali Patil
2026-04-06 9:19 ` [PATCH v4 03/15] selftests/mm: restore default nr_hugepages value via EXIT trap in hugetlb_reparenting_test.sh Sayali Patil
2026-04-06 9:19 ` [PATCH v4 04/15] selftests/mm: fix hugetlb pathname construction " Sayali Patil
2026-04-06 9:19 ` [PATCH v4 05/15] selftests/mm: fix cgroup task placement and drop memory.current checks " Sayali Patil
2026-04-06 9:19 ` [PATCH v4 06/15] selftests/mm: size tmpfs according to PMD page size in split_huge_page_test Sayali Patil
2026-04-06 9:19 ` [PATCH v4 07/15] selftests/mm: free dynamically allocated PMD-sized buffers " Sayali Patil
2026-04-06 9:19 ` [PATCH v4 08/15] selftest/mm: align memory size to huge page size in hugepage-mremap test Sayali Patil
2026-04-06 9:19 ` [PATCH v4 09/15] selftest/mm: register existing mapping with userfaultfd in hugepage-mremap Sayali Patil
2026-04-06 9:19 ` [PATCH v4 10/15] selftests/mm: ensure destination is hugetlb-backed " Sayali Patil
2026-04-06 9:19 ` [PATCH v4 11/15] selftests/mm: skip uffd-wp-mremap if UFFD write-protect is unsupported Sayali Patil
2026-04-06 9:19 ` [PATCH v4 12/15] selftests/mm: skip uffd-stress test when nr_pages_per_cpu is zero Sayali Patil
2026-04-06 9:19 ` [PATCH v4 13/15] selftests/mm: move hwpoison setup into run_test() and silence modprobe output for memory-failure category Sayali Patil
2026-04-06 9:19 ` [PATCH v4 14/15] selftests/mm: clarify alternate unmapping in compaction_test Sayali Patil
2026-04-06 9:19 ` [PATCH v4 15/15] selftests/cgroup: extend test_hugetlb_memcg.c to support all huge page sizes Sayali Patil
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox