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 fault_limit_file=limit_in_bytes
15 reservation_limit_file=rsvd.limit_in_bytes
16 fault_usage_file=usage_in_bytes
17 reservation_usage_file=rsvd.usage_in_bytes
19 if [[ "$1" == "-cgroup-v2" ]]; then
22 reservation_limit_file=rsvd.max
23 fault_usage_file=current
24 reservation_usage_file=rsvd.current
27 if [[ $cgroup2 ]]; then
28 cgroup_path=$(mount -t cgroup2 | head -1 | awk -e '{print $3}')
29 if [[ -z "$cgroup_path" ]]; then
30 cgroup_path=/dev/cgroup/memory
31 mount -t cgroup2 none $cgroup_path
34 echo "+hugetlb" >$cgroup_path/cgroup.subtree_control
36 cgroup_path=$(mount -t cgroup | grep ",hugetlb" | awk -e '{print $3}')
37 if [[ -z "$cgroup_path" ]]; then
38 cgroup_path=/dev/cgroup/memory
39 mount -t cgroup memory,hugetlb $cgroup_path
46 if [[ $cgroup2 ]]; then
47 echo $$ >$cgroup_path/cgroup.procs
49 echo $$ >$cgroup_path/tasks
52 if [[ -e /mnt/huge ]]; then
54 umount /mnt/huge || echo error
57 if [[ -e $cgroup_path/hugetlb_cgroup_test ]]; then
58 rmdir $cgroup_path/hugetlb_cgroup_test
60 if [[ -e $cgroup_path/hugetlb_cgroup_test1 ]]; then
61 rmdir $cgroup_path/hugetlb_cgroup_test1
63 if [[ -e $cgroup_path/hugetlb_cgroup_test2 ]]; then
64 rmdir $cgroup_path/hugetlb_cgroup_test2
66 echo 0 >/proc/sys/vm/nr_hugepages
70 function expect_equal() {
75 if [[ "$expected" != "$actual" ]]; then
76 echo "expected ($expected) != actual ($actual): $3"
82 function get_machine_hugepage_size() {
83 hpz=$(grep -i hugepagesize /proc/meminfo)
89 MB=$(get_machine_hugepage_size)
91 function setup_cgroup() {
93 local cgroup_limit="$2"
94 local reservation_limit="$3"
96 mkdir $cgroup_path/$name
98 echo writing cgroup limit: "$cgroup_limit"
99 echo "$cgroup_limit" >$cgroup_path/$name/hugetlb.${MB}MB.$fault_limit_file
101 echo writing reseravation limit: "$reservation_limit"
102 echo "$reservation_limit" > \
103 $cgroup_path/$name/hugetlb.${MB}MB.$reservation_limit_file
105 if [ -e "$cgroup_path/$name/cpuset.cpus" ]; then
106 echo 0 >$cgroup_path/$name/cpuset.cpus
108 if [ -e "$cgroup_path/$name/cpuset.mems" ]; then
109 echo 0 >$cgroup_path/$name/cpuset.mems
113 function wait_for_hugetlb_memory_to_get_depleted() {
115 local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
116 # Wait for hugetlbfs memory to get depleted.
117 while [ $(cat $path) != 0 ]; do
118 echo Waiting for hugetlb memory to get depleted.
124 function wait_for_hugetlb_memory_to_get_reserved() {
128 local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
129 # Wait for hugetlbfs memory to get written.
130 while [ $(cat $path) != $size ]; do
131 echo Waiting for hugetlb memory reservation to reach size $size.
137 function wait_for_hugetlb_memory_to_get_written() {
141 local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file"
142 # Wait for hugetlbfs memory to get written.
143 while [ $(cat $path) != $size ]; do
144 echo Waiting for hugetlb memory to reach size $size.
150 function write_hugetlbfs_and_get_usage() {
158 local expect_failure="$8"
161 # Function return values.
165 reserved_difference=0
167 local hugetlb_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file
168 local reserved_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file
170 local hugetlb_before=$(cat $hugetlb_usage)
171 local reserved_before=$(cat $reserved_usage)
175 echo hugetlb_usage="$hugetlb_before"
176 echo reserved_usage="$reserved_before"
177 echo expect_failure is "$expect_failure"
181 if [[ "$method" == "1" ]] || [[ "$method" == 2 ]] ||
182 [[ "$private" == "-r" ]] && [[ "$expect_failure" != 1 ]]; then
184 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
185 "$cgroup" "$path" "$method" "$private" "-l" "$reserve" 2>&1 | tee $output &
187 local write_result=$?
190 until grep -q -i "DONE" $output; do
191 echo waiting for DONE signal.
192 if ! ps $write_pid > /dev/null
194 echo "FAIL: The write died"
201 echo ================= write_hugetlb_memory.sh output is:
203 echo ================= end output.
205 if [[ "$populate" == "-o" ]] || [[ "$write" == "-w" ]]; then
206 wait_for_hugetlb_memory_to_get_written "$cgroup" "$size"
207 elif [[ "$reserve" != "-n" ]]; then
208 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
210 # This case doesn't produce visible effects, but we still have
211 # to wait for the async process to start and execute...
215 echo write_result is $write_result
217 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
218 "$cgroup" "$path" "$method" "$private" "$reserve"
219 local write_result=$?
221 if [[ "$reserve" != "-n" ]]; then
222 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
227 if [[ "$write_result" == 1 ]]; then
231 # On linus/master, the above process gets SIGBUS'd on oomkill, with
232 # return code 135. On earlier kernels, it gets actual oomkill, with return
233 # code 137, so just check for both conditions in case we're testing
234 # against an earlier kernel.
235 if [[ "$write_result" == 135 ]] || [[ "$write_result" == 137 ]]; then
239 local hugetlb_after=$(cat $hugetlb_usage)
240 local reserved_after=$(cat $reserved_usage)
243 echo hugetlb_usage="$hugetlb_after"
244 echo reserved_usage="$reserved_after"
246 hugetlb_difference=$(($hugetlb_after - $hugetlb_before))
247 reserved_difference=$(($reserved_after - $reserved_before))
250 function cleanup_hugetlb_memory() {
253 if [[ "$(pgrep -f write_to_hugetlbfs)" != "" ]]; then
254 echo killing write_to_hugetlbfs
255 killall -2 write_to_hugetlbfs
256 wait_for_hugetlb_memory_to_get_depleted $cgroup
260 if [[ -e /mnt/huge ]]; then
267 function run_test() {
268 local size=$(($1 * ${MB} * 1024 * 1024))
271 local cgroup_limit=$(($4 * ${MB} * 1024 * 1024))
272 local reservation_limit=$(($5 * ${MB} * 1024 * 1024))
273 local nr_hugepages="$6"
276 local expect_failure="$9"
277 local reserve="${10}"
279 # Function return values.
281 reserved_difference=0
285 echo nr hugepages = "$nr_hugepages"
286 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
288 setup_cgroup "hugetlb_cgroup_test" "$cgroup_limit" "$reservation_limit"
291 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
293 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test" "$size" "$populate" \
294 "$write" "/mnt/huge/test" "$method" "$private" "$expect_failure" \
297 cleanup_hugetlb_memory "hugetlb_cgroup_test"
299 local final_hugetlb=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$fault_usage_file)
300 local final_reservation=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$reservation_usage_file)
302 echo $hugetlb_difference
303 echo $reserved_difference
304 expect_equal "0" "$final_hugetlb" "final hugetlb is not zero"
305 expect_equal "0" "$final_reservation" "final reservation is not zero"
308 function run_multiple_cgroup_test() {
312 local cgroup_limit1="$4"
313 local reservation_limit1="$5"
318 local cgroup_limit2="$9"
319 local reservation_limit2="${10}"
321 local nr_hugepages="${11}"
323 local private="${13}"
324 local expect_failure="${14}"
325 local reserve="${15}"
327 # Function return values.
328 hugetlb_difference1=0
329 reserved_difference1=0
330 reservation_failed1=0
333 hugetlb_difference2=0
334 reserved_difference2=0
335 reservation_failed2=0
338 echo nr hugepages = "$nr_hugepages"
339 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
341 setup_cgroup "hugetlb_cgroup_test1" "$cgroup_limit1" "$reservation_limit1"
342 setup_cgroup "hugetlb_cgroup_test2" "$cgroup_limit2" "$reservation_limit2"
345 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
347 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test1" "$size1" \
348 "$populate1" "$write1" "/mnt/huge/test1" "$method" "$private" \
349 "$expect_failure" "$reserve"
351 hugetlb_difference1=$hugetlb_difference
352 reserved_difference1=$reserved_difference
353 reservation_failed1=$reservation_failed
354 oom_killed1=$oom_killed
356 local cgroup1_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$fault_usage_file
357 local cgroup1_reservation_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$reservation_usage_file
358 local cgroup2_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$fault_usage_file
359 local cgroup2_reservation_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$reservation_usage_file
361 local usage_before_second_write=$(cat $cgroup1_hugetlb_usage)
362 local reservation_usage_before_second_write=$(cat $cgroup1_reservation_usage)
364 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test2" "$size2" \
365 "$populate2" "$write2" "/mnt/huge/test2" "$method" "$private" \
366 "$expect_failure" "$reserve"
368 hugetlb_difference2=$hugetlb_difference
369 reserved_difference2=$reserved_difference
370 reservation_failed2=$reservation_failed
371 oom_killed2=$oom_killed
373 expect_equal "$usage_before_second_write" \
374 "$(cat $cgroup1_hugetlb_usage)" "Usage changed."
375 expect_equal "$reservation_usage_before_second_write" \
376 "$(cat $cgroup1_reservation_usage)" "Reservation usage changed."
378 cleanup_hugetlb_memory
380 local final_hugetlb=$(cat $cgroup1_hugetlb_usage)
381 local final_reservation=$(cat $cgroup1_reservation_usage)
383 expect_equal "0" "$final_hugetlb" \
384 "hugetlbt_cgroup_test1 final hugetlb is not zero"
385 expect_equal "0" "$final_reservation" \
386 "hugetlbt_cgroup_test1 final reservation is not zero"
388 local final_hugetlb=$(cat $cgroup2_hugetlb_usage)
389 local final_reservation=$(cat $cgroup2_reservation_usage)
391 expect_equal "0" "$final_hugetlb" \
392 "hugetlb_cgroup_test2 final hugetlb is not zero"
393 expect_equal "0" "$final_reservation" \
394 "hugetlb_cgroup_test2 final reservation is not zero"
399 for populate in "" "-o"; do
400 for method in 0 1 2; do
401 for private in "" "-r"; do
402 for reserve in "" "-n"; do
404 # Skip mmap(MAP_HUGETLB | MAP_SHARED). Doesn't seem to be supported.
405 if [[ "$method" == 1 ]] && [[ "$private" == "" ]]; then
409 # Skip populated shmem tests. Doesn't seem to be supported.
410 if [[ "$method" == 2"" ]] && [[ "$populate" == "-o" ]]; then
414 if [[ "$method" == 2"" ]] && [[ "$reserve" == "-n" ]]; then
422 echo Test normal case.
423 echo private=$private, populate=$populate, method=$method, reserve=$reserve
424 run_test 5 "$populate" "" 10 10 10 "$method" "$private" "0" "$reserve"
426 echo Memory charged to hugtlb=$hugetlb_difference
427 echo Memory charged to reservation=$reserved_difference
429 if [[ "$populate" == "-o" ]]; then
430 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
431 "Reserved memory charged to hugetlb cgroup."
433 expect_equal "0" "$hugetlb_difference" \
434 "Reserved memory charged to hugetlb cgroup."
437 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
438 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
439 "Reserved memory not charged to reservation usage."
441 expect_equal "0" "$reserved_difference" \
442 "Reserved memory not charged to reservation usage."
451 echo Test normal case with write.
452 echo private=$private, populate=$populate, method=$method, reserve=$reserve
453 run_test 5 "$populate" '-w' 5 5 10 "$method" "$private" "0" "$reserve"
455 echo Memory charged to hugtlb=$hugetlb_difference
456 echo Memory charged to reservation=$reserved_difference
458 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
459 "Reserved memory charged to hugetlb cgroup."
461 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
462 "Reserved memory not charged to reservation usage."
471 echo Test more than reservation case.
472 echo private=$private, populate=$populate, method=$method, reserve=$reserve
474 if [ "$reserve" != "-n" ]; then
475 run_test "5" "$populate" '' "10" "2" "10" "$method" "$private" "1" \
478 expect_equal "1" "$reservation_failed" "Reservation succeeded."
488 echo Test more than cgroup limit case.
489 echo private=$private, populate=$populate, method=$method, reserve=$reserve
491 # Not sure if shm memory can be cleaned up when the process gets sigbus'd.
492 if [[ "$method" != 2 ]]; then
493 run_test 5 "$populate" "-w" 2 10 10 "$method" "$private" "1" "$reserve"
495 expect_equal "1" "$oom_killed" "Not oom killed."
504 echo Test normal case, multiple cgroups.
505 echo private=$private, populate=$populate, method=$method, reserve=$reserve
506 run_multiple_cgroup_test "3" "$populate" "" "10" "10" "5" \
507 "$populate" "" "10" "10" "10" \
508 "$method" "$private" "0" "$reserve"
510 echo Memory charged to hugtlb1=$hugetlb_difference1
511 echo Memory charged to reservation1=$reserved_difference1
512 echo Memory charged to hugtlb2=$hugetlb_difference2
513 echo Memory charged to reservation2=$reserved_difference2
515 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
516 expect_equal "3" "$reserved_difference1" \
517 "Incorrect reservations charged to cgroup 1."
519 expect_equal "5" "$reserved_difference2" \
520 "Incorrect reservation charged to cgroup 2."
523 expect_equal "0" "$reserved_difference1" \
524 "Incorrect reservations charged to cgroup 1."
526 expect_equal "0" "$reserved_difference2" \
527 "Incorrect reservation charged to cgroup 2."
530 if [[ "$populate" == "-o" ]]; then
531 expect_equal "3" "$hugetlb_difference1" \
532 "Incorrect hugetlb charged to cgroup 1."
534 expect_equal "5" "$hugetlb_difference2" \
535 "Incorrect hugetlb charged to cgroup 2."
538 expect_equal "0" "$hugetlb_difference1" \
539 "Incorrect hugetlb charged to cgroup 1."
541 expect_equal "0" "$hugetlb_difference2" \
542 "Incorrect hugetlb charged to cgroup 2."
550 echo Test normal case with write, multiple cgroups.
551 echo private=$private, populate=$populate, method=$method, reserve=$reserve
552 run_multiple_cgroup_test "3" "$populate" "-w" "10" "10" "5" \
553 "$populate" "-w" "10" "10" "10" \
554 "$method" "$private" "0" "$reserve"
556 echo Memory charged to hugtlb1=$hugetlb_difference1
557 echo Memory charged to reservation1=$reserved_difference1
558 echo Memory charged to hugtlb2=$hugetlb_difference2
559 echo Memory charged to reservation2=$reserved_difference2
561 expect_equal "3" "$hugetlb_difference1" \
562 "Incorrect hugetlb charged to cgroup 1."
564 expect_equal "3" "$reserved_difference1" \
565 "Incorrect reservation charged to cgroup 1."
567 expect_equal "5" "$hugetlb_difference2" \
568 "Incorrect hugetlb charged to cgroup 2."
570 expect_equal "5" "$reserved_difference2" \
571 "Incorrected reservation charged to cgroup 2."
581 if [[ $do_umount ]]; then