589 lines · bash
1#!/bin/bash2# SPDX-License-Identifier: GPL-2.03 4# Kselftest framework requirement - SKIP code is 4.5ksft_skip=46 7set -e8 9if [[ $(id -u) -ne 0 ]]; then10 echo "This test must be run as root. Skipping..."11 exit $ksft_skip12fi13 14nr_hugepgs=$(cat /proc/sys/vm/nr_hugepages)15 16fault_limit_file=limit_in_bytes17reservation_limit_file=rsvd.limit_in_bytes18fault_usage_file=usage_in_bytes19reservation_usage_file=rsvd.usage_in_bytes20 21if [[ "$1" == "-cgroup-v2" ]]; then22 cgroup2=123 fault_limit_file=max24 reservation_limit_file=rsvd.max25 fault_usage_file=current26 reservation_usage_file=rsvd.current27fi28 29if [[ $cgroup2 ]]; then30 cgroup_path=$(mount -t cgroup2 | head -1 | awk '{print $3}')31 if [[ -z "$cgroup_path" ]]; then32 cgroup_path=/dev/cgroup/memory33 mount -t cgroup2 none $cgroup_path34 do_umount=135 fi36 echo "+hugetlb" >$cgroup_path/cgroup.subtree_control37else38 cgroup_path=$(mount -t cgroup | grep ",hugetlb" | awk '{print $3}')39 if [[ -z "$cgroup_path" ]]; then40 cgroup_path=/dev/cgroup/memory41 mount -t cgroup memory,hugetlb $cgroup_path42 do_umount=143 fi44fi45export cgroup_path46 47function cleanup() {48 if [[ $cgroup2 ]]; then49 echo $$ >$cgroup_path/cgroup.procs50 else51 echo $$ >$cgroup_path/tasks52 fi53 54 if [[ -e /mnt/huge ]]; then55 rm -rf /mnt/huge/*56 umount /mnt/huge || echo error57 rmdir /mnt/huge58 fi59 if [[ -e $cgroup_path/hugetlb_cgroup_test ]]; then60 rmdir $cgroup_path/hugetlb_cgroup_test61 fi62 if [[ -e $cgroup_path/hugetlb_cgroup_test1 ]]; then63 rmdir $cgroup_path/hugetlb_cgroup_test164 fi65 if [[ -e $cgroup_path/hugetlb_cgroup_test2 ]]; then66 rmdir $cgroup_path/hugetlb_cgroup_test267 fi68 echo 0 >/proc/sys/vm/nr_hugepages69 echo CLEANUP DONE70}71 72function expect_equal() {73 local expected="$1"74 local actual="$2"75 local error="$3"76 77 if [[ "$expected" != "$actual" ]]; then78 echo "expected ($expected) != actual ($actual): $3"79 cleanup80 exit 181 fi82}83 84function get_machine_hugepage_size() {85 hpz=$(grep -i hugepagesize /proc/meminfo)86 kb=${hpz:14:-3}87 mb=$(($kb / 1024))88 echo $mb89}90 91MB=$(get_machine_hugepage_size)92 93function setup_cgroup() {94 local name="$1"95 local cgroup_limit="$2"96 local reservation_limit="$3"97 98 mkdir $cgroup_path/$name99 100 echo writing cgroup limit: "$cgroup_limit"101 echo "$cgroup_limit" >$cgroup_path/$name/hugetlb.${MB}MB.$fault_limit_file102 103 echo writing reseravation limit: "$reservation_limit"104 echo "$reservation_limit" > \105 $cgroup_path/$name/hugetlb.${MB}MB.$reservation_limit_file106 107 if [ -e "$cgroup_path/$name/cpuset.cpus" ]; then108 echo 0 >$cgroup_path/$name/cpuset.cpus109 fi110 if [ -e "$cgroup_path/$name/cpuset.mems" ]; then111 echo 0 >$cgroup_path/$name/cpuset.mems112 fi113}114 115function wait_for_hugetlb_memory_to_get_depleted() {116 local cgroup="$1"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 ]; do120 echo Waiting for hugetlb memory to get depleted.121 cat $path122 sleep 0.5123 done124}125 126function wait_for_hugetlb_memory_to_get_reserved() {127 local cgroup="$1"128 local size="$2"129 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 ]; do133 echo Waiting for hugetlb memory reservation to reach size $size.134 cat $path135 sleep 0.5136 done137}138 139function wait_for_hugetlb_memory_to_get_written() {140 local cgroup="$1"141 local size="$2"142 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 ]; do146 echo Waiting for hugetlb memory to reach size $size.147 cat $path148 sleep 0.5149 done150}151 152function write_hugetlbfs_and_get_usage() {153 local cgroup="$1"154 local size="$2"155 local populate="$3"156 local write="$4"157 local path="$5"158 local method="$6"159 local private="$7"160 local expect_failure="$8"161 local reserve="$9"162 163 # Function return values.164 reservation_failed=0165 oom_killed=0166 hugetlb_difference=0167 reserved_difference=0168 169 local hugetlb_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file170 local reserved_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file171 172 local hugetlb_before=$(cat $hugetlb_usage)173 local reserved_before=$(cat $reserved_usage)174 175 echo176 echo Starting:177 echo hugetlb_usage="$hugetlb_before"178 echo reserved_usage="$reserved_before"179 echo expect_failure is "$expect_failure"180 181 output=$(mktemp)182 set +e183 if [[ "$method" == "1" ]] || [[ "$method" == 2 ]] ||184 [[ "$private" == "-r" ]] && [[ "$expect_failure" != 1 ]]; then185 186 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \187 "$cgroup" "$path" "$method" "$private" "-l" "$reserve" 2>&1 | tee $output &188 189 local write_result=$?190 local write_pid=$!191 192 until grep -q -i "DONE" $output; do193 echo waiting for DONE signal.194 if ! ps $write_pid > /dev/null195 then196 echo "FAIL: The write died"197 cleanup198 exit 1199 fi200 sleep 0.5201 done202 203 echo ================= write_hugetlb_memory.sh output is:204 cat $output205 echo ================= end output.206 207 if [[ "$populate" == "-o" ]] || [[ "$write" == "-w" ]]; then208 wait_for_hugetlb_memory_to_get_written "$cgroup" "$size"209 elif [[ "$reserve" != "-n" ]]; then210 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"211 else212 # This case doesn't produce visible effects, but we still have213 # to wait for the async process to start and execute...214 sleep 0.5215 fi216 217 echo write_result is $write_result218 else219 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \220 "$cgroup" "$path" "$method" "$private" "$reserve"221 local write_result=$?222 223 if [[ "$reserve" != "-n" ]]; then224 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"225 fi226 fi227 set -e228 229 if [[ "$write_result" == 1 ]]; then230 reservation_failed=1231 fi232 233 # On linus/master, the above process gets SIGBUS'd on oomkill, with234 # return code 135. On earlier kernels, it gets actual oomkill, with return235 # code 137, so just check for both conditions in case we're testing236 # against an earlier kernel.237 if [[ "$write_result" == 135 ]] || [[ "$write_result" == 137 ]]; then238 oom_killed=1239 fi240 241 local hugetlb_after=$(cat $hugetlb_usage)242 local reserved_after=$(cat $reserved_usage)243 244 echo After write:245 echo hugetlb_usage="$hugetlb_after"246 echo reserved_usage="$reserved_after"247 248 hugetlb_difference=$(($hugetlb_after - $hugetlb_before))249 reserved_difference=$(($reserved_after - $reserved_before))250}251 252function cleanup_hugetlb_memory() {253 set +e254 local cgroup="$1"255 if [[ "$(pgrep -f write_to_hugetlbfs)" != "" ]]; then256 echo killing write_to_hugetlbfs257 killall -2 --wait write_to_hugetlbfs258 wait_for_hugetlb_memory_to_get_depleted $cgroup259 fi260 set -e261 262 if [[ -e /mnt/huge ]]; then263 rm -rf /mnt/huge/*264 umount /mnt/huge265 rmdir /mnt/huge266 fi267}268 269function run_test() {270 local size=$(($1 * ${MB} * 1024 * 1024))271 local populate="$2"272 local write="$3"273 local cgroup_limit=$(($4 * ${MB} * 1024 * 1024))274 local reservation_limit=$(($5 * ${MB} * 1024 * 1024))275 local nr_hugepages="$6"276 local method="$7"277 local private="$8"278 local expect_failure="$9"279 local reserve="${10}"280 281 # Function return values.282 hugetlb_difference=0283 reserved_difference=0284 reservation_failed=0285 oom_killed=0286 287 echo nr hugepages = "$nr_hugepages"288 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages289 290 setup_cgroup "hugetlb_cgroup_test" "$cgroup_limit" "$reservation_limit"291 292 mkdir -p /mnt/huge293 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge294 295 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test" "$size" "$populate" \296 "$write" "/mnt/huge/test" "$method" "$private" "$expect_failure" \297 "$reserve"298 299 cleanup_hugetlb_memory "hugetlb_cgroup_test"300 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)303 304 echo $hugetlb_difference305 echo $reserved_difference306 expect_equal "0" "$final_hugetlb" "final hugetlb is not zero"307 expect_equal "0" "$final_reservation" "final reservation is not zero"308}309 310function run_multiple_cgroup_test() {311 local size1="$1"312 local populate1="$2"313 local write1="$3"314 local cgroup_limit1="$4"315 local reservation_limit1="$5"316 317 local size2="$6"318 local populate2="$7"319 local write2="$8"320 local cgroup_limit2="$9"321 local reservation_limit2="${10}"322 323 local nr_hugepages="${11}"324 local method="${12}"325 local private="${13}"326 local expect_failure="${14}"327 local reserve="${15}"328 329 # Function return values.330 hugetlb_difference1=0331 reserved_difference1=0332 reservation_failed1=0333 oom_killed1=0334 335 hugetlb_difference2=0336 reserved_difference2=0337 reservation_failed2=0338 oom_killed2=0339 340 echo nr hugepages = "$nr_hugepages"341 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages342 343 setup_cgroup "hugetlb_cgroup_test1" "$cgroup_limit1" "$reservation_limit1"344 setup_cgroup "hugetlb_cgroup_test2" "$cgroup_limit2" "$reservation_limit2"345 346 mkdir -p /mnt/huge347 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge348 349 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test1" "$size1" \350 "$populate1" "$write1" "/mnt/huge/test1" "$method" "$private" \351 "$expect_failure" "$reserve"352 353 hugetlb_difference1=$hugetlb_difference354 reserved_difference1=$reserved_difference355 reservation_failed1=$reservation_failed356 oom_killed1=$oom_killed357 358 local cgroup1_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$fault_usage_file359 local cgroup1_reservation_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$reservation_usage_file360 local cgroup2_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$fault_usage_file361 local cgroup2_reservation_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$reservation_usage_file362 363 local usage_before_second_write=$(cat $cgroup1_hugetlb_usage)364 local reservation_usage_before_second_write=$(cat $cgroup1_reservation_usage)365 366 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test2" "$size2" \367 "$populate2" "$write2" "/mnt/huge/test2" "$method" "$private" \368 "$expect_failure" "$reserve"369 370 hugetlb_difference2=$hugetlb_difference371 reserved_difference2=$reserved_difference372 reservation_failed2=$reservation_failed373 oom_killed2=$oom_killed374 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."379 380 cleanup_hugetlb_memory381 382 local final_hugetlb=$(cat $cgroup1_hugetlb_usage)383 local final_reservation=$(cat $cgroup1_reservation_usage)384 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"389 390 local final_hugetlb=$(cat $cgroup2_hugetlb_usage)391 local final_reservation=$(cat $cgroup2_reservation_usage)392 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"397}398 399cleanup400 401for populate in "" "-o"; do402 for method in 0 1 2; do403 for private in "" "-r"; do404 for reserve in "" "-n"; do405 406 # Skip mmap(MAP_HUGETLB | MAP_SHARED). Doesn't seem to be supported.407 if [[ "$method" == 1 ]] && [[ "$private" == "" ]]; then408 continue409 fi410 411 # Skip populated shmem tests. Doesn't seem to be supported.412 if [[ "$method" == 2"" ]] && [[ "$populate" == "-o" ]]; then413 continue414 fi415 416 if [[ "$method" == 2"" ]] && [[ "$reserve" == "-n" ]]; then417 continue418 fi419 420 cleanup421 echo422 echo423 echo424 echo Test normal case.425 echo private=$private, populate=$populate, method=$method, reserve=$reserve426 run_test 5 "$populate" "" 10 10 10 "$method" "$private" "0" "$reserve"427 428 echo Memory charged to hugtlb=$hugetlb_difference429 echo Memory charged to reservation=$reserved_difference430 431 if [[ "$populate" == "-o" ]]; then432 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \433 "Reserved memory charged to hugetlb cgroup."434 else435 expect_equal "0" "$hugetlb_difference" \436 "Reserved memory charged to hugetlb cgroup."437 fi438 439 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then440 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \441 "Reserved memory not charged to reservation usage."442 else443 expect_equal "0" "$reserved_difference" \444 "Reserved memory not charged to reservation usage."445 fi446 447 echo 'PASS'448 449 cleanup450 echo451 echo452 echo453 echo Test normal case with write.454 echo private=$private, populate=$populate, method=$method, reserve=$reserve455 run_test 5 "$populate" '-w' 5 5 10 "$method" "$private" "0" "$reserve"456 457 echo Memory charged to hugtlb=$hugetlb_difference458 echo Memory charged to reservation=$reserved_difference459 460 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \461 "Reserved memory charged to hugetlb cgroup."462 463 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \464 "Reserved memory not charged to reservation usage."465 466 echo 'PASS'467 468 cleanup469 continue470 echo471 echo472 echo473 echo Test more than reservation case.474 echo private=$private, populate=$populate, method=$method, reserve=$reserve475 476 if [ "$reserve" != "-n" ]; then477 run_test "5" "$populate" '' "10" "2" "10" "$method" "$private" "1" \478 "$reserve"479 480 expect_equal "1" "$reservation_failed" "Reservation succeeded."481 fi482 483 echo 'PASS'484 485 cleanup486 487 echo488 echo489 echo490 echo Test more than cgroup limit case.491 echo private=$private, populate=$populate, method=$method, reserve=$reserve492 493 # Not sure if shm memory can be cleaned up when the process gets sigbus'd.494 if [[ "$method" != 2 ]]; then495 run_test 5 "$populate" "-w" 2 10 10 "$method" "$private" "1" "$reserve"496 497 expect_equal "1" "$oom_killed" "Not oom killed."498 fi499 echo 'PASS'500 501 cleanup502 503 echo504 echo505 echo506 echo Test normal case, multiple cgroups.507 echo private=$private, populate=$populate, method=$method, reserve=$reserve508 run_multiple_cgroup_test "3" "$populate" "" "10" "10" "5" \509 "$populate" "" "10" "10" "10" \510 "$method" "$private" "0" "$reserve"511 512 echo Memory charged to hugtlb1=$hugetlb_difference1513 echo Memory charged to reservation1=$reserved_difference1514 echo Memory charged to hugtlb2=$hugetlb_difference2515 echo Memory charged to reservation2=$reserved_difference2516 517 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then518 expect_equal "3" "$reserved_difference1" \519 "Incorrect reservations charged to cgroup 1."520 521 expect_equal "5" "$reserved_difference2" \522 "Incorrect reservation charged to cgroup 2."523 524 else525 expect_equal "0" "$reserved_difference1" \526 "Incorrect reservations charged to cgroup 1."527 528 expect_equal "0" "$reserved_difference2" \529 "Incorrect reservation charged to cgroup 2."530 fi531 532 if [[ "$populate" == "-o" ]]; then533 expect_equal "3" "$hugetlb_difference1" \534 "Incorrect hugetlb charged to cgroup 1."535 536 expect_equal "5" "$hugetlb_difference2" \537 "Incorrect hugetlb charged to cgroup 2."538 539 else540 expect_equal "0" "$hugetlb_difference1" \541 "Incorrect hugetlb charged to cgroup 1."542 543 expect_equal "0" "$hugetlb_difference2" \544 "Incorrect hugetlb charged to cgroup 2."545 fi546 echo 'PASS'547 548 cleanup549 echo550 echo551 echo552 echo Test normal case with write, multiple cgroups.553 echo private=$private, populate=$populate, method=$method, reserve=$reserve554 run_multiple_cgroup_test "3" "$populate" "-w" "10" "10" "5" \555 "$populate" "-w" "10" "10" "10" \556 "$method" "$private" "0" "$reserve"557 558 echo Memory charged to hugtlb1=$hugetlb_difference1559 echo Memory charged to reservation1=$reserved_difference1560 echo Memory charged to hugtlb2=$hugetlb_difference2561 echo Memory charged to reservation2=$reserved_difference2562 563 expect_equal "3" "$hugetlb_difference1" \564 "Incorrect hugetlb charged to cgroup 1."565 566 expect_equal "3" "$reserved_difference1" \567 "Incorrect reservation charged to cgroup 1."568 569 expect_equal "5" "$hugetlb_difference2" \570 "Incorrect hugetlb charged to cgroup 2."571 572 expect_equal "5" "$reserved_difference2" \573 "Incorrected reservation charged to cgroup 2."574 echo 'PASS'575 576 cleanup577 578 done # reserve579 done # private580 done # populate581done # method582 583if [[ $do_umount ]]; then584 umount $cgroup_path585 rmdir $cgroup_path586fi587 588echo "$nr_hugepgs" > /proc/sys/vm/nr_hugepages589