1#!/bin/sh 2# SPDX-License-Identifier: GPL-2.0 3 4set -e 5 6if [[ $(id -u) -ne 0 ]]; then 7 echo "This test must be run as root. Skipping..." 8 exit 0 9fi 10 11fault_limit_file=limit_in_bytes 12reservation_limit_file=rsvd.limit_in_bytes 13fault_usage_file=usage_in_bytes 14reservation_usage_file=rsvd.usage_in_bytes 15 16if [[ "$1" == "-cgroup-v2" ]]; then 17 cgroup2=1 18 fault_limit_file=max 19 reservation_limit_file=rsvd.max 20 fault_usage_file=current 21 reservation_usage_file=rsvd.current 22fi 23 24cgroup_path=/dev/cgroup/memory 25if [[ ! -e $cgroup_path ]]; then 26 mkdir -p $cgroup_path 27 if [[ $cgroup2 ]]; then 28 mount -t cgroup2 none $cgroup_path 29 else 30 mount -t cgroup memory,hugetlb $cgroup_path 31 fi 32fi 33 34if [[ $cgroup2 ]]; then 35 echo "+hugetlb" >/dev/cgroup/memory/cgroup.subtree_control 36fi 37 38function cleanup() { 39 if [[ $cgroup2 ]]; then 40 echo $$ >$cgroup_path/cgroup.procs 41 else 42 echo $$ >$cgroup_path/tasks 43 fi 44 45 if [[ -e /mnt/huge ]]; then 46 rm -rf /mnt/huge/* 47 umount /mnt/huge || echo error 48 rmdir /mnt/huge 49 fi 50 if [[ -e $cgroup_path/hugetlb_cgroup_test ]]; then 51 rmdir $cgroup_path/hugetlb_cgroup_test 52 fi 53 if [[ -e $cgroup_path/hugetlb_cgroup_test1 ]]; then 54 rmdir $cgroup_path/hugetlb_cgroup_test1 55 fi 56 if [[ -e $cgroup_path/hugetlb_cgroup_test2 ]]; then 57 rmdir $cgroup_path/hugetlb_cgroup_test2 58 fi 59 echo 0 >/proc/sys/vm/nr_hugepages 60 echo CLEANUP DONE 61} 62 63function expect_equal() { 64 local expected="$1" 65 local actual="$2" 66 local error="$3" 67 68 if [[ "$expected" != "$actual" ]]; then 69 echo "expected ($expected) != actual ($actual): $3" 70 cleanup 71 exit 1 72 fi 73} 74 75function get_machine_hugepage_size() { 76 hpz=$(grep -i hugepagesize /proc/meminfo) 77 kb=${hpz:14:-3} 78 mb=$(($kb / 1024)) 79 echo $mb 80} 81 82MB=$(get_machine_hugepage_size) 83 84function setup_cgroup() { 85 local name="$1" 86 local cgroup_limit="$2" 87 local reservation_limit="$3" 88 89 mkdir $cgroup_path/$name 90 91 echo writing cgroup limit: "$cgroup_limit" 92 echo "$cgroup_limit" >$cgroup_path/$name/hugetlb.${MB}MB.$fault_limit_file 93 94 echo writing reseravation limit: "$reservation_limit" 95 echo "$reservation_limit" > \ 96 $cgroup_path/$name/hugetlb.${MB}MB.$reservation_limit_file 97 98 if [ -e "$cgroup_path/$name/cpuset.cpus" ]; then 99 echo 0 >$cgroup_path/$name/cpuset.cpus 100 fi 101 if [ -e "$cgroup_path/$name/cpuset.mems" ]; then 102 echo 0 >$cgroup_path/$name/cpuset.mems 103 fi 104} 105 106function wait_for_hugetlb_memory_to_get_depleted() { 107 local cgroup="$1" 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. 112 cat $path 113 sleep 0.5 114 done 115} 116 117function wait_for_hugetlb_memory_to_get_reserved() { 118 local cgroup="$1" 119 local size="$2" 120 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. 125 cat $path 126 sleep 0.5 127 done 128} 129 130function wait_for_hugetlb_memory_to_get_written() { 131 local cgroup="$1" 132 local size="$2" 133 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. 138 cat $path 139 sleep 0.5 140 done 141} 142 143function write_hugetlbfs_and_get_usage() { 144 local cgroup="$1" 145 local size="$2" 146 local populate="$3" 147 local write="$4" 148 local path="$5" 149 local method="$6" 150 local private="$7" 151 local expect_failure="$8" 152 local reserve="$9" 153 154 # Function return values. 155 reservation_failed=0 156 oom_killed=0 157 hugetlb_difference=0 158 reserved_difference=0 159 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 162 163 local hugetlb_before=$(cat $hugetlb_usage) 164 local reserved_before=$(cat $reserved_usage) 165 166 echo 167 echo Starting: 168 echo hugetlb_usage="$hugetlb_before" 169 echo reserved_usage="$reserved_before" 170 echo expect_failure is "$expect_failure" 171 172 output=$(mktemp) 173 set +e 174 if [[ "$method" == "1" ]] || [[ "$method" == 2 ]] || 175 [[ "$private" == "-r" ]] && [[ "$expect_failure" != 1 ]]; then 176 177 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \ 178 "$cgroup" "$path" "$method" "$private" "-l" "$reserve" 2>&1 | tee $output & 179 180 local write_result=$? 181 local write_pid=$! 182 183 until grep -q -i "DONE" $output; do 184 echo waiting for DONE signal. 185 if ! ps $write_pid > /dev/null 186 then 187 echo "FAIL: The write died" 188 cleanup 189 exit 1 190 fi 191 sleep 0.5 192 done 193 194 echo ================= write_hugetlb_memory.sh output is: 195 cat $output 196 echo ================= end output. 197 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" 202 else 203 # This case doesn't produce visible effects, but we still have 204 # to wait for the async process to start and execute... 205 sleep 0.5 206 fi 207 208 echo write_result is $write_result 209 else 210 bash write_hugetlb_memory.sh "$size" "$populate" "$write" \ 211 "$cgroup" "$path" "$method" "$private" "$reserve" 212 local write_result=$? 213 214 if [[ "$reserve" != "-n" ]]; then 215 wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size" 216 fi 217 fi 218 set -e 219 220 if [[ "$write_result" == 1 ]]; then 221 reservation_failed=1 222 fi 223 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 229 oom_killed=1 230 fi 231 232 local hugetlb_after=$(cat $hugetlb_usage) 233 local reserved_after=$(cat $reserved_usage) 234 235 echo After write: 236 echo hugetlb_usage="$hugetlb_after" 237 echo reserved_usage="$reserved_after" 238 239 hugetlb_difference=$(($hugetlb_after - $hugetlb_before)) 240 reserved_difference=$(($reserved_after - $reserved_before)) 241} 242 243function cleanup_hugetlb_memory() { 244 set +e 245 local cgroup="$1" 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 250 fi 251 set -e 252 253 if [[ -e /mnt/huge ]]; then 254 rm -rf /mnt/huge/* 255 umount /mnt/huge 256 rmdir /mnt/huge 257 fi 258} 259 260function run_test() { 261 local size=$(($1 * ${MB} * 1024 * 1024)) 262 local populate="$2" 263 local write="$3" 264 local cgroup_limit=$(($4 * ${MB} * 1024 * 1024)) 265 local reservation_limit=$(($5 * ${MB} * 1024 * 1024)) 266 local nr_hugepages="$6" 267 local method="$7" 268 local private="$8" 269 local expect_failure="$9" 270 local reserve="${10}" 271 272 # Function return values. 273 hugetlb_difference=0 274 reserved_difference=0 275 reservation_failed=0 276 oom_killed=0 277 278 echo nr hugepages = "$nr_hugepages" 279 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages 280 281 setup_cgroup "hugetlb_cgroup_test" "$cgroup_limit" "$reservation_limit" 282 283 mkdir -p /mnt/huge 284 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge 285 286 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test" "$size" "$populate" \ 287 "$write" "/mnt/huge/test" "$method" "$private" "$expect_failure" \ 288 "$reserve" 289 290 cleanup_hugetlb_memory "hugetlb_cgroup_test" 291 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) 294 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" 299} 300 301function run_multiple_cgroup_test() { 302 local size1="$1" 303 local populate1="$2" 304 local write1="$3" 305 local cgroup_limit1="$4" 306 local reservation_limit1="$5" 307 308 local size2="$6" 309 local populate2="$7" 310 local write2="$8" 311 local cgroup_limit2="$9" 312 local reservation_limit2="${10}" 313 314 local nr_hugepages="${11}" 315 local method="${12}" 316 local private="${13}" 317 local expect_failure="${14}" 318 local reserve="${15}" 319 320 # Function return values. 321 hugetlb_difference1=0 322 reserved_difference1=0 323 reservation_failed1=0 324 oom_killed1=0 325 326 hugetlb_difference2=0 327 reserved_difference2=0 328 reservation_failed2=0 329 oom_killed2=0 330 331 echo nr hugepages = "$nr_hugepages" 332 echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages 333 334 setup_cgroup "hugetlb_cgroup_test1" "$cgroup_limit1" "$reservation_limit1" 335 setup_cgroup "hugetlb_cgroup_test2" "$cgroup_limit2" "$reservation_limit2" 336 337 mkdir -p /mnt/huge 338 mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge 339 340 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test1" "$size1" \ 341 "$populate1" "$write1" "/mnt/huge/test1" "$method" "$private" \ 342 "$expect_failure" "$reserve" 343 344 hugetlb_difference1=$hugetlb_difference 345 reserved_difference1=$reserved_difference 346 reservation_failed1=$reservation_failed 347 oom_killed1=$oom_killed 348 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 353 354 local usage_before_second_write=$(cat $cgroup1_hugetlb_usage) 355 local reservation_usage_before_second_write=$(cat $cgroup1_reservation_usage) 356 357 write_hugetlbfs_and_get_usage "hugetlb_cgroup_test2" "$size2" \ 358 "$populate2" "$write2" "/mnt/huge/test2" "$method" "$private" \ 359 "$expect_failure" "$reserve" 360 361 hugetlb_difference2=$hugetlb_difference 362 reserved_difference2=$reserved_difference 363 reservation_failed2=$reservation_failed 364 oom_killed2=$oom_killed 365 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." 370 371 cleanup_hugetlb_memory 372 373 local final_hugetlb=$(cat $cgroup1_hugetlb_usage) 374 local final_reservation=$(cat $cgroup1_reservation_usage) 375 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" 380 381 local final_hugetlb=$(cat $cgroup2_hugetlb_usage) 382 local final_reservation=$(cat $cgroup2_reservation_usage) 383 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" 388} 389 390cleanup 391 392for populate in "" "-o"; do 393 for method in 0 1 2; do 394 for private in "" "-r"; do 395 for reserve in "" "-n"; do 396 397 # Skip mmap(MAP_HUGETLB | MAP_SHARED). Doesn't seem to be supported. 398 if [[ "$method" == 1 ]] && [[ "$private" == "" ]]; then 399 continue 400 fi 401 402 # Skip populated shmem tests. Doesn't seem to be supported. 403 if [[ "$method" == 2"" ]] && [[ "$populate" == "-o" ]]; then 404 continue 405 fi 406 407 if [[ "$method" == 2"" ]] && [[ "$reserve" == "-n" ]]; then 408 continue 409 fi 410 411 cleanup 412 echo 413 echo 414 echo 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" 418 419 echo Memory charged to hugtlb=$hugetlb_difference 420 echo Memory charged to reservation=$reserved_difference 421 422 if [[ "$populate" == "-o" ]]; then 423 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \ 424 "Reserved memory charged to hugetlb cgroup." 425 else 426 expect_equal "0" "$hugetlb_difference" \ 427 "Reserved memory charged to hugetlb cgroup." 428 fi 429 430 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then 431 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \ 432 "Reserved memory not charged to reservation usage." 433 else 434 expect_equal "0" "$reserved_difference" \ 435 "Reserved memory not charged to reservation usage." 436 fi 437 438 echo 'PASS' 439 440 cleanup 441 echo 442 echo 443 echo 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" 447 448 echo Memory charged to hugtlb=$hugetlb_difference 449 echo Memory charged to reservation=$reserved_difference 450 451 expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \ 452 "Reserved memory charged to hugetlb cgroup." 453 454 expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \ 455 "Reserved memory not charged to reservation usage." 456 457 echo 'PASS' 458 459 cleanup 460 continue 461 echo 462 echo 463 echo 464 echo Test more than reservation case. 465 echo private=$private, populate=$populate, method=$method, reserve=$reserve 466 467 if [ "$reserve" != "-n" ]; then 468 run_test "5" "$populate" '' "10" "2" "10" "$method" "$private" "1" \ 469 "$reserve" 470 471 expect_equal "1" "$reservation_failed" "Reservation succeeded." 472 fi 473 474 echo 'PASS' 475 476 cleanup 477 478 echo 479 echo 480 echo 481 echo Test more than cgroup limit case. 482 echo private=$private, populate=$populate, method=$method, reserve=$reserve 483 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" 487 488 expect_equal "1" "$oom_killed" "Not oom killed." 489 fi 490 echo 'PASS' 491 492 cleanup 493 494 echo 495 echo 496 echo 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" 502 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 507 508 if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then 509 expect_equal "3" "$reserved_difference1" \ 510 "Incorrect reservations charged to cgroup 1." 511 512 expect_equal "5" "$reserved_difference2" \ 513 "Incorrect reservation charged to cgroup 2." 514 515 else 516 expect_equal "0" "$reserved_difference1" \ 517 "Incorrect reservations charged to cgroup 1." 518 519 expect_equal "0" "$reserved_difference2" \ 520 "Incorrect reservation charged to cgroup 2." 521 fi 522 523 if [[ "$populate" == "-o" ]]; then 524 expect_equal "3" "$hugetlb_difference1" \ 525 "Incorrect hugetlb charged to cgroup 1." 526 527 expect_equal "5" "$hugetlb_difference2" \ 528 "Incorrect hugetlb charged to cgroup 2." 529 530 else 531 expect_equal "0" "$hugetlb_difference1" \ 532 "Incorrect hugetlb charged to cgroup 1." 533 534 expect_equal "0" "$hugetlb_difference2" \ 535 "Incorrect hugetlb charged to cgroup 2." 536 fi 537 echo 'PASS' 538 539 cleanup 540 echo 541 echo 542 echo 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" 548 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 553 554 expect_equal "3" "$hugetlb_difference1" \ 555 "Incorrect hugetlb charged to cgroup 1." 556 557 expect_equal "3" "$reserved_difference1" \ 558 "Incorrect reservation charged to cgroup 1." 559 560 expect_equal "5" "$hugetlb_difference2" \ 561 "Incorrect hugetlb charged to cgroup 2." 562 563 expect_equal "5" "$reserved_difference2" \ 564 "Incorrected reservation charged to cgroup 2." 565 echo 'PASS' 566 567 cleanup 568 569 done # reserve 570 done # private 571 done # populate 572done # method 573 574umount $cgroup_path 575rmdir $cgroup_path 576