Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/sh
0002 # SPDX-License-Identifier: GPL-2.0
0003 
0004 # Kselftest framework requirement - SKIP code is 4.
0005 ksft_skip=4
0006 
0007 set -e
0008 
0009 if [[ $(id -u) -ne 0 ]]; then
0010   echo "This test must be run as root. Skipping..."
0011   exit $ksft_skip
0012 fi
0013 
0014 fault_limit_file=limit_in_bytes
0015 reservation_limit_file=rsvd.limit_in_bytes
0016 fault_usage_file=usage_in_bytes
0017 reservation_usage_file=rsvd.usage_in_bytes
0018 
0019 if [[ "$1" == "-cgroup-v2" ]]; then
0020   cgroup2=1
0021   fault_limit_file=max
0022   reservation_limit_file=rsvd.max
0023   fault_usage_file=current
0024   reservation_usage_file=rsvd.current
0025 fi
0026 
0027 if [[ $cgroup2 ]]; then
0028   cgroup_path=$(mount -t cgroup2 | head -1 | awk -e '{print $3}')
0029   if [[ -z "$cgroup_path" ]]; then
0030     cgroup_path=/dev/cgroup/memory
0031     mount -t cgroup2 none $cgroup_path
0032     do_umount=1
0033   fi
0034   echo "+hugetlb" >$cgroup_path/cgroup.subtree_control
0035 else
0036   cgroup_path=$(mount -t cgroup | grep ",hugetlb" | awk -e '{print $3}')
0037   if [[ -z "$cgroup_path" ]]; then
0038     cgroup_path=/dev/cgroup/memory
0039     mount -t cgroup memory,hugetlb $cgroup_path
0040     do_umount=1
0041   fi
0042 fi
0043 export cgroup_path
0044 
0045 function cleanup() {
0046   if [[ $cgroup2 ]]; then
0047     echo $$ >$cgroup_path/cgroup.procs
0048   else
0049     echo $$ >$cgroup_path/tasks
0050   fi
0051 
0052   if [[ -e /mnt/huge ]]; then
0053     rm -rf /mnt/huge/*
0054     umount /mnt/huge || echo error
0055     rmdir /mnt/huge
0056   fi
0057   if [[ -e $cgroup_path/hugetlb_cgroup_test ]]; then
0058     rmdir $cgroup_path/hugetlb_cgroup_test
0059   fi
0060   if [[ -e $cgroup_path/hugetlb_cgroup_test1 ]]; then
0061     rmdir $cgroup_path/hugetlb_cgroup_test1
0062   fi
0063   if [[ -e $cgroup_path/hugetlb_cgroup_test2 ]]; then
0064     rmdir $cgroup_path/hugetlb_cgroup_test2
0065   fi
0066   echo 0 >/proc/sys/vm/nr_hugepages
0067   echo CLEANUP DONE
0068 }
0069 
0070 function expect_equal() {
0071   local expected="$1"
0072   local actual="$2"
0073   local error="$3"
0074 
0075   if [[ "$expected" != "$actual" ]]; then
0076     echo "expected ($expected) != actual ($actual): $3"
0077     cleanup
0078     exit 1
0079   fi
0080 }
0081 
0082 function get_machine_hugepage_size() {
0083   hpz=$(grep -i hugepagesize /proc/meminfo)
0084   kb=${hpz:14:-3}
0085   mb=$(($kb / 1024))
0086   echo $mb
0087 }
0088 
0089 MB=$(get_machine_hugepage_size)
0090 
0091 function setup_cgroup() {
0092   local name="$1"
0093   local cgroup_limit="$2"
0094   local reservation_limit="$3"
0095 
0096   mkdir $cgroup_path/$name
0097 
0098   echo writing cgroup limit: "$cgroup_limit"
0099   echo "$cgroup_limit" >$cgroup_path/$name/hugetlb.${MB}MB.$fault_limit_file
0100 
0101   echo writing reseravation limit: "$reservation_limit"
0102   echo "$reservation_limit" > \
0103     $cgroup_path/$name/hugetlb.${MB}MB.$reservation_limit_file
0104 
0105   if [ -e "$cgroup_path/$name/cpuset.cpus" ]; then
0106     echo 0 >$cgroup_path/$name/cpuset.cpus
0107   fi
0108   if [ -e "$cgroup_path/$name/cpuset.mems" ]; then
0109     echo 0 >$cgroup_path/$name/cpuset.mems
0110   fi
0111 }
0112 
0113 function wait_for_hugetlb_memory_to_get_depleted() {
0114   local cgroup="$1"
0115   local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
0116   # Wait for hugetlbfs memory to get depleted.
0117   while [ $(cat $path) != 0 ]; do
0118     echo Waiting for hugetlb memory to get depleted.
0119     cat $path
0120     sleep 0.5
0121   done
0122 }
0123 
0124 function wait_for_hugetlb_memory_to_get_reserved() {
0125   local cgroup="$1"
0126   local size="$2"
0127 
0128   local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file"
0129   # Wait for hugetlbfs memory to get written.
0130   while [ $(cat $path) != $size ]; do
0131     echo Waiting for hugetlb memory reservation to reach size $size.
0132     cat $path
0133     sleep 0.5
0134   done
0135 }
0136 
0137 function wait_for_hugetlb_memory_to_get_written() {
0138   local cgroup="$1"
0139   local size="$2"
0140 
0141   local path="$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file"
0142   # Wait for hugetlbfs memory to get written.
0143   while [ $(cat $path) != $size ]; do
0144     echo Waiting for hugetlb memory to reach size $size.
0145     cat $path
0146     sleep 0.5
0147   done
0148 }
0149 
0150 function write_hugetlbfs_and_get_usage() {
0151   local cgroup="$1"
0152   local size="$2"
0153   local populate="$3"
0154   local write="$4"
0155   local path="$5"
0156   local method="$6"
0157   local private="$7"
0158   local expect_failure="$8"
0159   local reserve="$9"
0160 
0161   # Function return values.
0162   reservation_failed=0
0163   oom_killed=0
0164   hugetlb_difference=0
0165   reserved_difference=0
0166 
0167   local hugetlb_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$fault_usage_file
0168   local reserved_usage=$cgroup_path/$cgroup/hugetlb.${MB}MB.$reservation_usage_file
0169 
0170   local hugetlb_before=$(cat $hugetlb_usage)
0171   local reserved_before=$(cat $reserved_usage)
0172 
0173   echo
0174   echo Starting:
0175   echo hugetlb_usage="$hugetlb_before"
0176   echo reserved_usage="$reserved_before"
0177   echo expect_failure is "$expect_failure"
0178 
0179   output=$(mktemp)
0180   set +e
0181   if [[ "$method" == "1" ]] || [[ "$method" == 2 ]] ||
0182     [[ "$private" == "-r" ]] && [[ "$expect_failure" != 1 ]]; then
0183 
0184     bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
0185       "$cgroup" "$path" "$method" "$private" "-l" "$reserve" 2>&1 | tee $output &
0186 
0187     local write_result=$?
0188     local write_pid=$!
0189 
0190     until grep -q -i "DONE" $output; do
0191       echo waiting for DONE signal.
0192       if ! ps $write_pid > /dev/null
0193       then
0194         echo "FAIL: The write died"
0195         cleanup
0196         exit 1
0197       fi
0198       sleep 0.5
0199     done
0200 
0201     echo ================= write_hugetlb_memory.sh output is:
0202     cat $output
0203     echo ================= end output.
0204 
0205     if [[ "$populate" == "-o" ]] || [[ "$write" == "-w" ]]; then
0206       wait_for_hugetlb_memory_to_get_written "$cgroup" "$size"
0207     elif [[ "$reserve" != "-n" ]]; then
0208       wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
0209     else
0210       # This case doesn't produce visible effects, but we still have
0211       # to wait for the async process to start and execute...
0212       sleep 0.5
0213     fi
0214 
0215     echo write_result is $write_result
0216   else
0217     bash write_hugetlb_memory.sh "$size" "$populate" "$write" \
0218       "$cgroup" "$path" "$method" "$private" "$reserve"
0219     local write_result=$?
0220 
0221     if [[ "$reserve" != "-n" ]]; then
0222       wait_for_hugetlb_memory_to_get_reserved "$cgroup" "$size"
0223     fi
0224   fi
0225   set -e
0226 
0227   if [[ "$write_result" == 1 ]]; then
0228     reservation_failed=1
0229   fi
0230 
0231   # On linus/master, the above process gets SIGBUS'd on oomkill, with
0232   # return code 135. On earlier kernels, it gets actual oomkill, with return
0233   # code 137, so just check for both conditions in case we're testing
0234   # against an earlier kernel.
0235   if [[ "$write_result" == 135 ]] || [[ "$write_result" == 137 ]]; then
0236     oom_killed=1
0237   fi
0238 
0239   local hugetlb_after=$(cat $hugetlb_usage)
0240   local reserved_after=$(cat $reserved_usage)
0241 
0242   echo After write:
0243   echo hugetlb_usage="$hugetlb_after"
0244   echo reserved_usage="$reserved_after"
0245 
0246   hugetlb_difference=$(($hugetlb_after - $hugetlb_before))
0247   reserved_difference=$(($reserved_after - $reserved_before))
0248 }
0249 
0250 function cleanup_hugetlb_memory() {
0251   set +e
0252   local cgroup="$1"
0253   if [[ "$(pgrep -f write_to_hugetlbfs)" != "" ]]; then
0254     echo killing write_to_hugetlbfs
0255     killall -2 write_to_hugetlbfs
0256     wait_for_hugetlb_memory_to_get_depleted $cgroup
0257   fi
0258   set -e
0259 
0260   if [[ -e /mnt/huge ]]; then
0261     rm -rf /mnt/huge/*
0262     umount /mnt/huge
0263     rmdir /mnt/huge
0264   fi
0265 }
0266 
0267 function run_test() {
0268   local size=$(($1 * ${MB} * 1024 * 1024))
0269   local populate="$2"
0270   local write="$3"
0271   local cgroup_limit=$(($4 * ${MB} * 1024 * 1024))
0272   local reservation_limit=$(($5 * ${MB} * 1024 * 1024))
0273   local nr_hugepages="$6"
0274   local method="$7"
0275   local private="$8"
0276   local expect_failure="$9"
0277   local reserve="${10}"
0278 
0279   # Function return values.
0280   hugetlb_difference=0
0281   reserved_difference=0
0282   reservation_failed=0
0283   oom_killed=0
0284 
0285   echo nr hugepages = "$nr_hugepages"
0286   echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
0287 
0288   setup_cgroup "hugetlb_cgroup_test" "$cgroup_limit" "$reservation_limit"
0289 
0290   mkdir -p /mnt/huge
0291   mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
0292 
0293   write_hugetlbfs_and_get_usage "hugetlb_cgroup_test" "$size" "$populate" \
0294     "$write" "/mnt/huge/test" "$method" "$private" "$expect_failure" \
0295     "$reserve"
0296 
0297   cleanup_hugetlb_memory "hugetlb_cgroup_test"
0298 
0299   local final_hugetlb=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$fault_usage_file)
0300   local final_reservation=$(cat $cgroup_path/hugetlb_cgroup_test/hugetlb.${MB}MB.$reservation_usage_file)
0301 
0302   echo $hugetlb_difference
0303   echo $reserved_difference
0304   expect_equal "0" "$final_hugetlb" "final hugetlb is not zero"
0305   expect_equal "0" "$final_reservation" "final reservation is not zero"
0306 }
0307 
0308 function run_multiple_cgroup_test() {
0309   local size1="$1"
0310   local populate1="$2"
0311   local write1="$3"
0312   local cgroup_limit1="$4"
0313   local reservation_limit1="$5"
0314 
0315   local size2="$6"
0316   local populate2="$7"
0317   local write2="$8"
0318   local cgroup_limit2="$9"
0319   local reservation_limit2="${10}"
0320 
0321   local nr_hugepages="${11}"
0322   local method="${12}"
0323   local private="${13}"
0324   local expect_failure="${14}"
0325   local reserve="${15}"
0326 
0327   # Function return values.
0328   hugetlb_difference1=0
0329   reserved_difference1=0
0330   reservation_failed1=0
0331   oom_killed1=0
0332 
0333   hugetlb_difference2=0
0334   reserved_difference2=0
0335   reservation_failed2=0
0336   oom_killed2=0
0337 
0338   echo nr hugepages = "$nr_hugepages"
0339   echo "$nr_hugepages" >/proc/sys/vm/nr_hugepages
0340 
0341   setup_cgroup "hugetlb_cgroup_test1" "$cgroup_limit1" "$reservation_limit1"
0342   setup_cgroup "hugetlb_cgroup_test2" "$cgroup_limit2" "$reservation_limit2"
0343 
0344   mkdir -p /mnt/huge
0345   mount -t hugetlbfs -o pagesize=${MB}M,size=256M none /mnt/huge
0346 
0347   write_hugetlbfs_and_get_usage "hugetlb_cgroup_test1" "$size1" \
0348     "$populate1" "$write1" "/mnt/huge/test1" "$method" "$private" \
0349     "$expect_failure" "$reserve"
0350 
0351   hugetlb_difference1=$hugetlb_difference
0352   reserved_difference1=$reserved_difference
0353   reservation_failed1=$reservation_failed
0354   oom_killed1=$oom_killed
0355 
0356   local cgroup1_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$fault_usage_file
0357   local cgroup1_reservation_usage=$cgroup_path/hugetlb_cgroup_test1/hugetlb.${MB}MB.$reservation_usage_file
0358   local cgroup2_hugetlb_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$fault_usage_file
0359   local cgroup2_reservation_usage=$cgroup_path/hugetlb_cgroup_test2/hugetlb.${MB}MB.$reservation_usage_file
0360 
0361   local usage_before_second_write=$(cat $cgroup1_hugetlb_usage)
0362   local reservation_usage_before_second_write=$(cat $cgroup1_reservation_usage)
0363 
0364   write_hugetlbfs_and_get_usage "hugetlb_cgroup_test2" "$size2" \
0365     "$populate2" "$write2" "/mnt/huge/test2" "$method" "$private" \
0366     "$expect_failure" "$reserve"
0367 
0368   hugetlb_difference2=$hugetlb_difference
0369   reserved_difference2=$reserved_difference
0370   reservation_failed2=$reservation_failed
0371   oom_killed2=$oom_killed
0372 
0373   expect_equal "$usage_before_second_write" \
0374     "$(cat $cgroup1_hugetlb_usage)" "Usage changed."
0375   expect_equal "$reservation_usage_before_second_write" \
0376     "$(cat $cgroup1_reservation_usage)" "Reservation usage changed."
0377 
0378   cleanup_hugetlb_memory
0379 
0380   local final_hugetlb=$(cat $cgroup1_hugetlb_usage)
0381   local final_reservation=$(cat $cgroup1_reservation_usage)
0382 
0383   expect_equal "0" "$final_hugetlb" \
0384     "hugetlbt_cgroup_test1 final hugetlb is not zero"
0385   expect_equal "0" "$final_reservation" \
0386     "hugetlbt_cgroup_test1 final reservation is not zero"
0387 
0388   local final_hugetlb=$(cat $cgroup2_hugetlb_usage)
0389   local final_reservation=$(cat $cgroup2_reservation_usage)
0390 
0391   expect_equal "0" "$final_hugetlb" \
0392     "hugetlb_cgroup_test2 final hugetlb is not zero"
0393   expect_equal "0" "$final_reservation" \
0394     "hugetlb_cgroup_test2 final reservation is not zero"
0395 }
0396 
0397 cleanup
0398 
0399 for populate in "" "-o"; do
0400   for method in 0 1 2; do
0401     for private in "" "-r"; do
0402       for reserve in "" "-n"; do
0403 
0404         # Skip mmap(MAP_HUGETLB | MAP_SHARED). Doesn't seem to be supported.
0405         if [[ "$method" == 1 ]] && [[ "$private" == "" ]]; then
0406           continue
0407         fi
0408 
0409         # Skip populated shmem tests. Doesn't seem to be supported.
0410         if [[ "$method" == 2"" ]] && [[ "$populate" == "-o" ]]; then
0411           continue
0412         fi
0413 
0414         if [[ "$method" == 2"" ]] && [[ "$reserve" == "-n" ]]; then
0415           continue
0416         fi
0417 
0418         cleanup
0419         echo
0420         echo
0421         echo
0422         echo Test normal case.
0423         echo private=$private, populate=$populate, method=$method, reserve=$reserve
0424         run_test 5 "$populate" "" 10 10 10 "$method" "$private" "0" "$reserve"
0425 
0426         echo Memory charged to hugtlb=$hugetlb_difference
0427         echo Memory charged to reservation=$reserved_difference
0428 
0429         if [[ "$populate" == "-o" ]]; then
0430           expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
0431             "Reserved memory charged to hugetlb cgroup."
0432         else
0433           expect_equal "0" "$hugetlb_difference" \
0434             "Reserved memory charged to hugetlb cgroup."
0435         fi
0436 
0437         if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
0438           expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
0439             "Reserved memory not charged to reservation usage."
0440         else
0441           expect_equal "0" "$reserved_difference" \
0442             "Reserved memory not charged to reservation usage."
0443         fi
0444 
0445         echo 'PASS'
0446 
0447         cleanup
0448         echo
0449         echo
0450         echo
0451         echo Test normal case with write.
0452         echo private=$private, populate=$populate, method=$method, reserve=$reserve
0453         run_test 5 "$populate" '-w' 5 5 10 "$method" "$private" "0" "$reserve"
0454 
0455         echo Memory charged to hugtlb=$hugetlb_difference
0456         echo Memory charged to reservation=$reserved_difference
0457 
0458         expect_equal "$((5 * $MB * 1024 * 1024))" "$hugetlb_difference" \
0459           "Reserved memory charged to hugetlb cgroup."
0460 
0461         expect_equal "$((5 * $MB * 1024 * 1024))" "$reserved_difference" \
0462           "Reserved memory not charged to reservation usage."
0463 
0464         echo 'PASS'
0465 
0466         cleanup
0467         continue
0468         echo
0469         echo
0470         echo
0471         echo Test more than reservation case.
0472         echo private=$private, populate=$populate, method=$method, reserve=$reserve
0473 
0474         if [ "$reserve" != "-n" ]; then
0475           run_test "5" "$populate" '' "10" "2" "10" "$method" "$private" "1" \
0476             "$reserve"
0477 
0478           expect_equal "1" "$reservation_failed" "Reservation succeeded."
0479         fi
0480 
0481         echo 'PASS'
0482 
0483         cleanup
0484 
0485         echo
0486         echo
0487         echo
0488         echo Test more than cgroup limit case.
0489         echo private=$private, populate=$populate, method=$method, reserve=$reserve
0490 
0491         # Not sure if shm memory can be cleaned up when the process gets sigbus'd.
0492         if [[ "$method" != 2 ]]; then
0493           run_test 5 "$populate" "-w" 2 10 10 "$method" "$private" "1" "$reserve"
0494 
0495           expect_equal "1" "$oom_killed" "Not oom killed."
0496         fi
0497         echo 'PASS'
0498 
0499         cleanup
0500 
0501         echo
0502         echo
0503         echo
0504         echo Test normal case, multiple cgroups.
0505         echo private=$private, populate=$populate, method=$method, reserve=$reserve
0506         run_multiple_cgroup_test "3" "$populate" "" "10" "10" "5" \
0507           "$populate" "" "10" "10" "10" \
0508           "$method" "$private" "0" "$reserve"
0509 
0510         echo Memory charged to hugtlb1=$hugetlb_difference1
0511         echo Memory charged to reservation1=$reserved_difference1
0512         echo Memory charged to hugtlb2=$hugetlb_difference2
0513         echo Memory charged to reservation2=$reserved_difference2
0514 
0515         if [[ "$reserve" != "-n" ]] || [[ "$populate" == "-o" ]]; then
0516           expect_equal "3" "$reserved_difference1" \
0517             "Incorrect reservations charged to cgroup 1."
0518 
0519           expect_equal "5" "$reserved_difference2" \
0520             "Incorrect reservation charged to cgroup 2."
0521 
0522         else
0523           expect_equal "0" "$reserved_difference1" \
0524             "Incorrect reservations charged to cgroup 1."
0525 
0526           expect_equal "0" "$reserved_difference2" \
0527             "Incorrect reservation charged to cgroup 2."
0528         fi
0529 
0530         if [[ "$populate" == "-o" ]]; then
0531           expect_equal "3" "$hugetlb_difference1" \
0532             "Incorrect hugetlb charged to cgroup 1."
0533 
0534           expect_equal "5" "$hugetlb_difference2" \
0535             "Incorrect hugetlb charged to cgroup 2."
0536 
0537         else
0538           expect_equal "0" "$hugetlb_difference1" \
0539             "Incorrect hugetlb charged to cgroup 1."
0540 
0541           expect_equal "0" "$hugetlb_difference2" \
0542             "Incorrect hugetlb charged to cgroup 2."
0543         fi
0544         echo 'PASS'
0545 
0546         cleanup
0547         echo
0548         echo
0549         echo
0550         echo Test normal case with write, multiple cgroups.
0551         echo private=$private, populate=$populate, method=$method, reserve=$reserve
0552         run_multiple_cgroup_test "3" "$populate" "-w" "10" "10" "5" \
0553           "$populate" "-w" "10" "10" "10" \
0554           "$method" "$private" "0" "$reserve"
0555 
0556         echo Memory charged to hugtlb1=$hugetlb_difference1
0557         echo Memory charged to reservation1=$reserved_difference1
0558         echo Memory charged to hugtlb2=$hugetlb_difference2
0559         echo Memory charged to reservation2=$reserved_difference2
0560 
0561         expect_equal "3" "$hugetlb_difference1" \
0562           "Incorrect hugetlb charged to cgroup 1."
0563 
0564         expect_equal "3" "$reserved_difference1" \
0565           "Incorrect reservation charged to cgroup 1."
0566 
0567         expect_equal "5" "$hugetlb_difference2" \
0568           "Incorrect hugetlb charged to cgroup 2."
0569 
0570         expect_equal "5" "$reserved_difference2" \
0571           "Incorrected reservation charged to cgroup 2."
0572         echo 'PASS'
0573 
0574         cleanup
0575 
0576       done # reserve
0577     done   # private
0578   done     # populate
0579 done       # method
0580 
0581 if [[ $do_umount ]]; then
0582   umount $cgroup_path
0583   rmdir $cgroup_path
0584 fi