2 # SPDX-License-Identifier: GPL-2.0
4 # Kselftest framework requirement - SKIP code is 4.
9 if [[ $(id -u) -ne 0 ]]; then
10 echo "This test must be run as root. Skipping..."
14 nr_hugepgs=$(cat /proc/sys/vm/nr_hugepages)
16 fault_limit_file=limit_in_bytes
17 reservation_limit_file=rsvd.limit_in_bytes
18 fault_usage_file=usage_in_bytes
19 reservation_usage_file=rsvd.usage_in_bytes
21 if [[ "$1" == "-cgroup-v2" ]]; then
24 reservation_limit_file=rsvd.max
25 fault_usage_file=current
26 reservation_usage_file=rsvd.current
29 if [[ $cgroup2 ]]; then
30 cgroup_path=$(mount -t cgroup2 | head -1 | awk '{print $3}')
31 if [[ -z "$cgroup_path" ]]; then
32 cgroup_path=/dev/cgroup/memory
33 mount -t cgroup2 none $cgroup_path
36 echo "+hugetlb" >$cgroup_path/cgroup.subtree_control
38 cgroup_path=$(mount -t cgroup | grep ",hugetlb" | awk '{print $3}')
39 if [[ -z "$cgroup_path" ]]; then
40 cgroup_path=/dev/cgroup/memory
41 mount -t cgroup memory,hugetlb $cgroup_path
48 if [[ $cgroup2 ]]; then
49 echo $$ >$cgroup_path/cgroup.procs
51 echo $$ >$cgroup_path/tasks
54 if [[ -e /mnt/huge ]]; then
56 umount /mnt/huge || echo error
59 if [[ -e $cgroup_path/hugetlb_cgroup_test ]]; then
60 rmdir $cgroup_path/hugetlb_cgroup_test
62 if [[ -e $cgroup_path/hugetlb_cgroup_test1 ]]; then
63 rmdir $cgroup_path/hugetlb_cgroup_test1
65 if [[ -e $cgroup_path/hugetlb_cgroup_test2 ]]; then
66 rmdir $cgroup_path/hugetlb_cgroup_test2
68 echo 0 >/proc/sys/vm/nr_hugepages
72 function expect_equal() {
77 if [[ "$expected" != "$actual" ]]; then
78 echo "expected ($expected) != actual ($actual): $3"
84 function get_machine_hugepage_size() {
85 hpz=$(grep -i hugepagesize /proc/meminfo)
91 MB=$(get_machine_hugepage_size)
93 function setup_cgroup() {
95 local cgroup_limit="$2"
96 local reservation_limit="$3"
98 mkdir $cgroup_path/$name
100 echo writing cgroup limit: "$cgroup_limit"
101 echo "$cgroup_limit" >$cgroup_path/$name/hugetlb.${MB}MB.$fault_limit_file
103 echo writing reseravation limit: "$reservation_limit"
104 echo "$reservation_limit" > \
105 $cgroup_path/$name/hugetlb.${MB}MB.$reservation_limit_file
107 if [ -e "$cgroup_path/$name/cpuset.cpus" ]; then
108 echo 0 >$cgroup_path/$name/cpuset.cpus
110 if [ -e "$cgroup_path/$name/cpuset.mems" ]; then
111 echo 0 >$cgroup_path/$name/cpuset.mems
115 function wait_for_hugetlb_memory_to_get_depleted() {
117 local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
118 # Wait for hugetlbfs memory to get depleted.
119 while [ $(cat $path) != 0 ]; do
120 echo Waiting for hugetlb memory to get depleted.
126 function wait_for_hugetlb_memory_to_get_reserved() {
130 local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
131 # Wait for hugetlbfs memory to get written.
132 while [ $(cat $path) != $size ]; do
133 echo Waiting for hugetlb memory reservation to reach size $size.
139 function wait_for_hugetlb_memory_to_get_written() {
143 local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file"
144 # Wait for hugetlbfs memory to get written.
145 while [ $(cat $path) != $size ]; do
146 echo Waiting for hugetlb memory to reach size $size.
152 function write_hugetlbfs_and_get_usage() {
160 local expect_failure="$8"
163 # Function return values.
167 reserved_difference=0
169 local hugetlb_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file
170 local reserved_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file
172 local hugetlb_before=$(cat $hugetlb_usage)
173 local reserved_before=$(cat $reserved_usage)
177 echo hugetlb_usage="$hugetlb_before"
178 echo reserved_usage="$reserved_before"
179 echo expect_failure is "$expect_failure"
183 if [[ "$method" == "1" ]] || [[ "$method" == 2 ]] ||
184 [[ "$private" == "-r" ]] && [[ "$expect_failure" != 1 ]]; then
186 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
187 "$cgroup" "$path" "$method" "$private" "-l" "$reserve" 2>&1 | tee $output &
189 local write_result=$?
192 until grep -q -i "DONE" $output; do
193 echo waiting for DONE signal.
194 if ! ps $write_pid > /dev/null
196 echo "FAIL: The write died"
203 echo ================= write_hugetlb_memory.sh output is:
205 echo ================= end output.
207 if [[ "$populate" == "-o" ]] || [[ "$write" == "-w" ]]; then
208 wait_for_hugetlb_memory_to_get_written "$cgroup" "$size"
209 elif [[ "$reserve" != "-n" ]]; then
210 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
212 # This case doesn't produce visible effects, but we still have
213 # to wait for the async process to start and execute...
217 echo write_result is $write_result
219 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
220 "$cgroup" "$path" "$method" "$private" "$reserve"
221 local write_result=$?
223 if [[ "$reserve" != "-n" ]]; then
224 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
229 if [[ "$write_result" == 1 ]]; then
233 # On linus/master, the above process gets SIGBUS'd on oomkill, with
234 # return code 135. On earlier kernels, it gets actual oomkill, with return
235 # code 137, so just check for both conditions in case we're testing
236 # against an earlier kernel.
237 if [[ "$write_result" == 135 ]] || [[ "$write_result" == 137 ]]; then
241 local hugetlb_after=$(cat $hugetlb_usage)
242 local reserved_after=$(cat $reserved_usage)
245 echo hugetlb_usage="$hugetlb_after"
246 echo reserved_usage="$reserved_after"
248 hugetlb_difference=$(($hugetlb_after - $hugetlb_before))
249 reserved_difference=$(($reserved_after - $reserved_before))
252 function cleanup_hugetlb_memory() {
255 if [[ "$(pgrep -f write_to_hugetlbfs)" != "" ]]; then
256 echo killing write_to_hugetlbfs
257 killall -2 write_to_hugetlbfs
258 wait_for_hugetlb_memory_to_get_depleted $cgroup
262 if [[ -e /mnt/huge ]]; then
269 function run_test() {
270 local size=$(($1 * ${MB} * 1024 * 1024))
273 local cgroup_limit=$(($4 * ${MB} * 1024 * 1024))
274 local reservation_limit=$(($5 * ${MB} * 1024 * 1024))
275 local nr_hugepages="$6"
278 local expect_failure="$9"
279 local reserve="${10}"
281 # Function return values.
283 reserved_difference=0
287 echo nr hugepages = "$nr_hugepages"
288 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
290 setup_cgroup "hugetlb_cgroup_test" "$cgroup_limit" "$reservation_limit"
293 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
295 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test" "$size" "$populate" \
296 "$write" "/mnt/huge/test" "$method" "$private" "$expect_failure" \
299 cleanup_hugetlb_memory "hugetlb_cgroup_test"
301 local final_hugetlb=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$fault_usage_file)
302 local final_reservation=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$reservation_usage_file)
304 echo $hugetlb_difference
305 echo $reserved_difference
306 expect_equal "0" "$final_hugetlb" "final hugetlb is not zero"
307 expect_equal "0" "$final_reservation" "final reservation is not zero"
310 function run_multiple_cgroup_test() {
314 local cgroup_limit1="$4"
315 local reservation_limit1="$5"
320 local cgroup_limit2="$9"
321 local reservation_limit2="${10}"
323 local nr_hugepages="${11}"
325 local private="${13}"
326 local expect_failure="${14}"
327 local reserve="${15}"
329 # Function return values.
330 hugetlb_difference1=0
331 reserved_difference1=0
332 reservation_failed1=0
335 hugetlb_difference2=0
336 reserved_difference2=0
337 reservation_failed2=0
340 echo nr hugepages = "$nr_hugepages"
341 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
343 setup_cgroup "hugetlb_cgroup_test1" "$cgroup_limit1" "$reservation_limit1"
344 setup_cgroup "hugetlb_cgroup_test2" "$cgroup_limit2" "$reservation_limit2"
347 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
349 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test1" "$size1" \
350 "$populate1" "$write1" "/mnt/huge/test1" "$method" "$private" \
351 "$expect_failure" "$reserve"
353 hugetlb_difference1=$hugetlb_difference
354 reserved_difference1=$reserved_difference
355 reservation_failed1=$reservation_failed
356 oom_killed1=$oom_killed
358 local cgroup1_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$fault_usage_file
359 local cgroup1_reservation_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$reservation_usage_file
360 local cgroup2_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$fault_usage_file
361 local cgroup2_reservation_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$reservation_usage_file
363 local usage_before_second_write=$(cat $cgroup1_hugetlb_usage)
364 local reservation_usage_before_second_write=$(cat $cgroup1_reservation_usage)
366 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test2" "$size2" \
367 "$populate2" "$write2" "/mnt/huge/test2" "$method" "$private" \
368 "$expect_failure" "$reserve"
370 hugetlb_difference2=$hugetlb_difference
371 reserved_difference2=$reserved_difference
372 reservation_failed2=$reservation_failed
373 oom_killed2=$oom_killed
375 expect_equal "$usage_before_second_write" \
376 "$(cat $cgroup1_hugetlb_usage)" "Usage changed."
377 expect_equal "$reservation_usage_before_second_write" \
378 "$(cat $cgroup1_reservation_usage)" "Reservation usage changed."
380 cleanup_hugetlb_memory
382 local final_hugetlb=$(cat $cgroup1_hugetlb_usage)
383 local final_reservation=$(cat $cgroup1_reservation_usage)
385 expect_equal "0" "$final_hugetlb" \
386 "hugetlbt_cgroup_test1 final hugetlb is not zero"
387 expect_equal "0" "$final_reservation" \
388 "hugetlbt_cgroup_test1 final reservation is not zero"
390 local final_hugetlb=$(cat $cgroup2_hugetlb_usage)
391 local final_reservation=$(cat $cgroup2_reservation_usage)
393 expect_equal "0" "$final_hugetlb" \
394 "hugetlb_cgroup_test2 final hugetlb is not zero"
395 expect_equal "0" "$final_reservation" \
396 "hugetlb_cgroup_test2 final reservation is not zero"
401 for populate in "" "-o"; do
402 for method in 0 1 2; do
403 for private in "" "-r"; do
404 for reserve in "" "-n"; do
406 # Skip mmap(MAP_HUGETLB | MAP_SHARED). Doesn't seem to be supported.
407 if [[ "$method" == 1 ]] && [[ "$private" == "" ]]; then
411 # Skip populated shmem tests. Doesn't seem to be supported.
412 if [[ "$method" == 2"" ]] && [[ "$populate" == "-o" ]]; then
416 if [[ "$method" == 2"" ]] && [[ "$reserve" == "-n" ]]; then
424 echo Test normal case.
425 echo private=$private, populate=$populate, method=$method, reserve=$reserve
426 run_test 5 "$populate" "" 10 10 10 "$method" "$private" "0" "$reserve"
428 echo Memory charged to hugtlb=$hugetlb_difference
429 echo Memory charged to reservation=$reserved_difference
431 if [[ "$populate" == "-o" ]]; then
432 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
433 "Reserved memory charged to hugetlb cgroup."
435 expect_equal "0" "$hugetlb_difference" \
436 "Reserved memory charged to hugetlb cgroup."
439 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
440 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
441 "Reserved memory not charged to reservation usage."
443 expect_equal "0" "$reserved_difference" \
444 "Reserved memory not charged to reservation usage."
453 echo Test normal case with write.
454 echo private=$private, populate=$populate, method=$method, reserve=$reserve
455 run_test 5 "$populate" '-w' 5 5 10 "$method" "$private" "0" "$reserve"
457 echo Memory charged to hugtlb=$hugetlb_difference
458 echo Memory charged to reservation=$reserved_difference
460 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
461 "Reserved memory charged to hugetlb cgroup."
463 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
464 "Reserved memory not charged to reservation usage."
473 echo Test more than reservation case.
474 echo private=$private, populate=$populate, method=$method, reserve=$reserve
476 if [ "$reserve" != "-n" ]; then
477 run_test "5" "$populate" '' "10" "2" "10" "$method" "$private" "1" \
480 expect_equal "1" "$reservation_failed" "Reservation succeeded."
490 echo Test more than cgroup limit case.
491 echo private=$private, populate=$populate, method=$method, reserve=$reserve
493 # Not sure if shm memory can be cleaned up when the process gets sigbus'd.
494 if [[ "$method" != 2 ]]; then
495 run_test 5 "$populate" "-w" 2 10 10 "$method" "$private" "1" "$reserve"
497 expect_equal "1" "$oom_killed" "Not oom killed."
506 echo Test normal case, multiple cgroups.
507 echo private=$private, populate=$populate, method=$method, reserve=$reserve
508 run_multiple_cgroup_test "3" "$populate" "" "10" "10" "5" \
509 "$populate" "" "10" "10" "10" \
510 "$method" "$private" "0" "$reserve"
512 echo Memory charged to hugtlb1=$hugetlb_difference1
513 echo Memory charged to reservation1=$reserved_difference1
514 echo Memory charged to hugtlb2=$hugetlb_difference2
515 echo Memory charged to reservation2=$reserved_difference2
517 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
518 expect_equal "3" "$reserved_difference1" \
519 "Incorrect reservations charged to cgroup 1."
521 expect_equal "5" "$reserved_difference2" \
522 "Incorrect reservation charged to cgroup 2."
525 expect_equal "0" "$reserved_difference1" \
526 "Incorrect reservations charged to cgroup 1."
528 expect_equal "0" "$reserved_difference2" \
529 "Incorrect reservation charged to cgroup 2."
532 if [[ "$populate" == "-o" ]]; then
533 expect_equal "3" "$hugetlb_difference1" \
534 "Incorrect hugetlb charged to cgroup 1."
536 expect_equal "5" "$hugetlb_difference2" \
537 "Incorrect hugetlb charged to cgroup 2."
540 expect_equal "0" "$hugetlb_difference1" \
541 "Incorrect hugetlb charged to cgroup 1."
543 expect_equal "0" "$hugetlb_difference2" \
544 "Incorrect hugetlb charged to cgroup 2."
552 echo Test normal case with write, multiple cgroups.
553 echo private=$private, populate=$populate, method=$method, reserve=$reserve
554 run_multiple_cgroup_test "3" "$populate" "-w" "10" "10" "5" \
555 "$populate" "-w" "10" "10" "10" \
556 "$method" "$private" "0" "$reserve"
558 echo Memory charged to hugtlb1=$hugetlb_difference1
559 echo Memory charged to reservation1=$reserved_difference1
560 echo Memory charged to hugtlb2=$hugetlb_difference2
561 echo Memory charged to reservation2=$reserved_difference2
563 expect_equal "3" "$hugetlb_difference1" \
564 "Incorrect hugetlb charged to cgroup 1."
566 expect_equal "3" "$reserved_difference1" \
567 "Incorrect reservation charged to cgroup 1."
569 expect_equal "5" "$hugetlb_difference2" \
570 "Incorrect hugetlb charged to cgroup 2."
572 expect_equal "5" "$reserved_difference2" \
573 "Incorrected reservation charged to cgroup 2."
583 if [[ $do_umount ]]; then
588 echo "$nr_hugepgs" > /proc/sys/vm/nr_hugepages