2 # SPDX-License-Identifier: GPL-2.0
6 if [[ $(id -u) -ne 0 ]]; then
7 echo "This test must be run as root. Skipping..."
11 fault_limit_file=limit_in_bytes
12 reservation_limit_file=rsvd.limit_in_bytes
13 fault_usage_file=usage_in_bytes
14 reservation_usage_file=rsvd.usage_in_bytes
16 if [[ "$1" == "-cgroup-v2" ]]; then
19 reservation_limit_file=rsvd.max
20 fault_usage_file=current
21 reservation_usage_file=rsvd.current
24 cgroup_path=/dev/cgroup/memory
25 if [[ ! -e $cgroup_path ]]; then
27 if [[ $cgroup2 ]]; then
28 mount -t cgroup2 none $cgroup_path
30 mount -t cgroup memory,hugetlb $cgroup_path
34 if [[ $cgroup2 ]]; then
35 echo "+hugetlb" >/dev/cgroup/memory/cgroup.subtree_control
39 if [[ $cgroup2 ]]; then
40 echo $$ >$cgroup_path/cgroup.procs
42 echo $$ >$cgroup_path/tasks
45 if [[ -e /mnt/huge ]]; then
47 umount /mnt/huge || echo error
50 if [[ -e $cgroup_path/hugetlb_cgroup_test ]]; then
51 rmdir $cgroup_path/hugetlb_cgroup_test
53 if [[ -e $cgroup_path/hugetlb_cgroup_test1 ]]; then
54 rmdir $cgroup_path/hugetlb_cgroup_test1
56 if [[ -e $cgroup_path/hugetlb_cgroup_test2 ]]; then
57 rmdir $cgroup_path/hugetlb_cgroup_test2
59 echo 0 >/proc/sys/vm/nr_hugepages
63 function expect_equal() {
68 if [[ "$expected" != "$actual" ]]; then
69 echo "expected ($expected) != actual ($actual): $3"
75 function get_machine_hugepage_size() {
76 hpz=$(grep -i hugepagesize /proc/meminfo)
82 MB=$(get_machine_hugepage_size)
84 function setup_cgroup() {
86 local cgroup_limit="$2"
87 local reservation_limit="$3"
89 mkdir $cgroup_path/$name
91 echo writing cgroup limit: "$cgroup_limit"
92 echo "$cgroup_limit" >$cgroup_path/$name/hugetlb.${MB}MB.$fault_limit_file
94 echo writing reseravation limit: "$reservation_limit"
95 echo "$reservation_limit" > \
96 $cgroup_path/$name/hugetlb.${MB}MB.$reservation_limit_file
98 if [ -e "$cgroup_path/$name/cpuset.cpus" ]; then
99 echo 0 >$cgroup_path/$name/cpuset.cpus
101 if [ -e "$cgroup_path/$name/cpuset.mems" ]; then
102 echo 0 >$cgroup_path/$name/cpuset.mems
106 function wait_for_hugetlb_memory_to_get_depleted() {
108 local path="/dev/cgroup/memory/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
109 # Wait for hugetlbfs memory to get depleted.
110 while [ $(cat $path) != 0 ]; do
111 echo Waiting for hugetlb memory to get depleted.
117 function wait_for_hugetlb_memory_to_get_reserved() {
121 local path="/dev/cgroup/memory/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
122 # Wait for hugetlbfs memory to get written.
123 while [ $(cat $path) != $size ]; do
124 echo Waiting for hugetlb memory reservation to reach size $size.
130 function wait_for_hugetlb_memory_to_get_written() {
134 local path="/dev/cgroup/memory/$cgroup/hugetlb.${MB}MB.$fault_usage_file"
135 # Wait for hugetlbfs memory to get written.
136 while [ $(cat $path) != $size ]; do
137 echo Waiting for hugetlb memory to reach size $size.
143 function write_hugetlbfs_and_get_usage() {
151 local expect_failure="$8"
154 # Function return values.
158 reserved_difference=0
160 local hugetlb_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file
161 local reserved_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file
163 local hugetlb_before=$(cat $hugetlb_usage)
164 local reserved_before=$(cat $reserved_usage)
168 echo hugetlb_usage="$hugetlb_before"
169 echo reserved_usage="$reserved_before"
170 echo expect_failure is "$expect_failure"
174 if [[ "$method" == "1" ]] || [[ "$method" == 2 ]] ||
175 [[ "$private" == "-r" ]] && [[ "$expect_failure" != 1 ]]; then
177 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
178 "$cgroup" "$path" "$method" "$private" "-l" "$reserve" 2>&1 | tee $output &
180 local write_result=$?
183 until grep -q -i "DONE" $output; do
184 echo waiting for DONE signal.
185 if ! ps $write_pid > /dev/null
187 echo "FAIL: The write died"
194 echo ================= write_hugetlb_memory.sh output is:
196 echo ================= end output.
198 if [[ "$populate" == "-o" ]] || [[ "$write" == "-w" ]]; then
199 wait_for_hugetlb_memory_to_get_written "$cgroup" "$size"
200 elif [[ "$reserve" != "-n" ]]; then
201 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
203 # This case doesn't produce visible effects, but we still have
204 # to wait for the async process to start and execute...
208 echo write_result is $write_result
210 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
211 "$cgroup" "$path" "$method" "$private" "$reserve"
212 local write_result=$?
214 if [[ "$reserve" != "-n" ]]; then
215 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
220 if [[ "$write_result" == 1 ]]; then
224 # On linus/master, the above process gets SIGBUS'd on oomkill, with
225 # return code 135. On earlier kernels, it gets actual oomkill, with return
226 # code 137, so just check for both conditions in case we're testing
227 # against an earlier kernel.
228 if [[ "$write_result" == 135 ]] || [[ "$write_result" == 137 ]]; then
232 local hugetlb_after=$(cat $hugetlb_usage)
233 local reserved_after=$(cat $reserved_usage)
236 echo hugetlb_usage="$hugetlb_after"
237 echo reserved_usage="$reserved_after"
239 hugetlb_difference=$(($hugetlb_after - $hugetlb_before))
240 reserved_difference=$(($reserved_after - $reserved_before))
243 function cleanup_hugetlb_memory() {
246 if [[ "$(pgrep -f write_to_hugetlbfs)" != "" ]]; then
247 echo killing write_to_hugetlbfs
248 killall -2 write_to_hugetlbfs
249 wait_for_hugetlb_memory_to_get_depleted $cgroup
253 if [[ -e /mnt/huge ]]; then
260 function run_test() {
261 local size=$(($1 * ${MB} * 1024 * 1024))
264 local cgroup_limit=$(($4 * ${MB} * 1024 * 1024))
265 local reservation_limit=$(($5 * ${MB} * 1024 * 1024))
266 local nr_hugepages="$6"
269 local expect_failure="$9"
270 local reserve="${10}"
272 # Function return values.
274 reserved_difference=0
278 echo nr hugepages = "$nr_hugepages"
279 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
281 setup_cgroup "hugetlb_cgroup_test" "$cgroup_limit" "$reservation_limit"
284 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
286 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test" "$size" "$populate" \
287 "$write" "/mnt/huge/test" "$method" "$private" "$expect_failure" \
290 cleanup_hugetlb_memory "hugetlb_cgroup_test"
292 local final_hugetlb=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$fault_usage_file)
293 local final_reservation=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$reservation_usage_file)
295 echo $hugetlb_difference
296 echo $reserved_difference
297 expect_equal "0" "$final_hugetlb" "final hugetlb is not zero"
298 expect_equal "0" "$final_reservation" "final reservation is not zero"
301 function run_multiple_cgroup_test() {
305 local cgroup_limit1="$4"
306 local reservation_limit1="$5"
311 local cgroup_limit2="$9"
312 local reservation_limit2="${10}"
314 local nr_hugepages="${11}"
316 local private="${13}"
317 local expect_failure="${14}"
318 local reserve="${15}"
320 # Function return values.
321 hugetlb_difference1=0
322 reserved_difference1=0
323 reservation_failed1=0
326 hugetlb_difference2=0
327 reserved_difference2=0
328 reservation_failed2=0
331 echo nr hugepages = "$nr_hugepages"
332 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
334 setup_cgroup "hugetlb_cgroup_test1" "$cgroup_limit1" "$reservation_limit1"
335 setup_cgroup "hugetlb_cgroup_test2" "$cgroup_limit2" "$reservation_limit2"
338 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
340 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test1" "$size1" \
341 "$populate1" "$write1" "/mnt/huge/test1" "$method" "$private" \
342 "$expect_failure" "$reserve"
344 hugetlb_difference1=$hugetlb_difference
345 reserved_difference1=$reserved_difference
346 reservation_failed1=$reservation_failed
347 oom_killed1=$oom_killed
349 local cgroup1_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$fault_usage_file
350 local cgroup1_reservation_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$reservation_usage_file
351 local cgroup2_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$fault_usage_file
352 local cgroup2_reservation_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$reservation_usage_file
354 local usage_before_second_write=$(cat $cgroup1_hugetlb_usage)
355 local reservation_usage_before_second_write=$(cat $cgroup1_reservation_usage)
357 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test2" "$size2" \
358 "$populate2" "$write2" "/mnt/huge/test2" "$method" "$private" \
359 "$expect_failure" "$reserve"
361 hugetlb_difference2=$hugetlb_difference
362 reserved_difference2=$reserved_difference
363 reservation_failed2=$reservation_failed
364 oom_killed2=$oom_killed
366 expect_equal "$usage_before_second_write" \
367 "$(cat $cgroup1_hugetlb_usage)" "Usage changed."
368 expect_equal "$reservation_usage_before_second_write" \
369 "$(cat $cgroup1_reservation_usage)" "Reservation usage changed."
371 cleanup_hugetlb_memory
373 local final_hugetlb=$(cat $cgroup1_hugetlb_usage)
374 local final_reservation=$(cat $cgroup1_reservation_usage)
376 expect_equal "0" "$final_hugetlb" \
377 "hugetlbt_cgroup_test1 final hugetlb is not zero"
378 expect_equal "0" "$final_reservation" \
379 "hugetlbt_cgroup_test1 final reservation is not zero"
381 local final_hugetlb=$(cat $cgroup2_hugetlb_usage)
382 local final_reservation=$(cat $cgroup2_reservation_usage)
384 expect_equal "0" "$final_hugetlb" \
385 "hugetlb_cgroup_test2 final hugetlb is not zero"
386 expect_equal "0" "$final_reservation" \
387 "hugetlb_cgroup_test2 final reservation is not zero"
392 for populate in "" "-o"; do
393 for method in 0 1 2; do
394 for private in "" "-r"; do
395 for reserve in "" "-n"; do
397 # Skip mmap(MAP_HUGETLB | MAP_SHARED). Doesn't seem to be supported.
398 if [[ "$method" == 1 ]] && [[ "$private" == "" ]]; then
402 # Skip populated shmem tests. Doesn't seem to be supported.
403 if [[ "$method" == 2"" ]] && [[ "$populate" == "-o" ]]; then
407 if [[ "$method" == 2"" ]] && [[ "$reserve" == "-n" ]]; then
415 echo Test normal case.
416 echo private=$private, populate=$populate, method=$method, reserve=$reserve
417 run_test 5 "$populate" "" 10 10 10 "$method" "$private" "0" "$reserve"
419 echo Memory charged to hugtlb=$hugetlb_difference
420 echo Memory charged to reservation=$reserved_difference
422 if [[ "$populate" == "-o" ]]; then
423 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
424 "Reserved memory charged to hugetlb cgroup."
426 expect_equal "0" "$hugetlb_difference" \
427 "Reserved memory charged to hugetlb cgroup."
430 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
431 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
432 "Reserved memory not charged to reservation usage."
434 expect_equal "0" "$reserved_difference" \
435 "Reserved memory not charged to reservation usage."
444 echo Test normal case with write.
445 echo private=$private, populate=$populate, method=$method, reserve=$reserve
446 run_test 5 "$populate" '-w' 5 5 10 "$method" "$private" "0" "$reserve"
448 echo Memory charged to hugtlb=$hugetlb_difference
449 echo Memory charged to reservation=$reserved_difference
451 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
452 "Reserved memory charged to hugetlb cgroup."
454 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
455 "Reserved memory not charged to reservation usage."
464 echo Test more than reservation case.
465 echo private=$private, populate=$populate, method=$method, reserve=$reserve
467 if [ "$reserve" != "-n" ]; then
468 run_test "5" "$populate" '' "10" "2" "10" "$method" "$private" "1" \
471 expect_equal "1" "$reservation_failed" "Reservation succeeded."
481 echo Test more than cgroup limit case.
482 echo private=$private, populate=$populate, method=$method, reserve=$reserve
484 # Not sure if shm memory can be cleaned up when the process gets sigbus'd.
485 if [[ "$method" != 2 ]]; then
486 run_test 5 "$populate" "-w" 2 10 10 "$method" "$private" "1" "$reserve"
488 expect_equal "1" "$oom_killed" "Not oom killed."
497 echo Test normal case, multiple cgroups.
498 echo private=$private, populate=$populate, method=$method, reserve=$reserve
499 run_multiple_cgroup_test "3" "$populate" "" "10" "10" "5" \
500 "$populate" "" "10" "10" "10" \
501 "$method" "$private" "0" "$reserve"
503 echo Memory charged to hugtlb1=$hugetlb_difference1
504 echo Memory charged to reservation1=$reserved_difference1
505 echo Memory charged to hugtlb2=$hugetlb_difference2
506 echo Memory charged to reservation2=$reserved_difference2
508 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
509 expect_equal "3" "$reserved_difference1" \
510 "Incorrect reservations charged to cgroup 1."
512 expect_equal "5" "$reserved_difference2" \
513 "Incorrect reservation charged to cgroup 2."
516 expect_equal "0" "$reserved_difference1" \
517 "Incorrect reservations charged to cgroup 1."
519 expect_equal "0" "$reserved_difference2" \
520 "Incorrect reservation charged to cgroup 2."
523 if [[ "$populate" == "-o" ]]; then
524 expect_equal "3" "$hugetlb_difference1" \
525 "Incorrect hugetlb charged to cgroup 1."
527 expect_equal "5" "$hugetlb_difference2" \
528 "Incorrect hugetlb charged to cgroup 2."
531 expect_equal "0" "$hugetlb_difference1" \
532 "Incorrect hugetlb charged to cgroup 1."
534 expect_equal "0" "$hugetlb_difference2" \
535 "Incorrect hugetlb charged to cgroup 2."
543 echo Test normal case with write, multiple cgroups.
544 echo private=$private, populate=$populate, method=$method, reserve=$reserve
545 run_multiple_cgroup_test "3" "$populate" "-w" "10" "10" "5" \
546 "$populate" "-w" "10" "10" "10" \
547 "$method" "$private" "0" "$reserve"
549 echo Memory charged to hugtlb1=$hugetlb_difference1
550 echo Memory charged to reservation1=$reserved_difference1
551 echo Memory charged to hugtlb2=$hugetlb_difference2
552 echo Memory charged to reservation2=$reserved_difference2
554 expect_equal "3" "$hugetlb_difference1" \
555 "Incorrect hugetlb charged to cgroup 1."
557 expect_equal "3" "$reserved_difference1" \
558 "Incorrect reservation charged to cgroup 1."
560 expect_equal "5" "$hugetlb_difference2" \
561 "Incorrect hugetlb charged to cgroup 2."
563 expect_equal "5" "$reserved_difference2" \
564 "Incorrected reservation charged to cgroup 2."