1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3 4# Kselftest framework requirement - SKIP code is 4. 5ksft_skip=4 6 7set -e 8 9if [[ $(id -u) -ne 0 ]]; then 10 echo "This test must be run as root. Skipping..." 11 exit $ksft_skip 12fi 13 14nr_hugepgs=$(cat /proc/sys/vm/nr_hugepages) 15trap 'echo "$nr_hugepgs" > /proc/sys/vm/nr_hugepages' EXIT INT TERM 16 17usage_file=usage_in_bytes 18 19if [[ "$1" == "-cgroup-v2" ]]; then 20 cgroup2=1 21 usage_file=current 22fi 23 24 25if [[ $cgroup2 ]]; then 26 CGROUP_ROOT=$(mount -t cgroup2 | head -1 | awk '{print $3}') 27 if [[ -z "$CGROUP_ROOT" ]]; then 28 CGROUP_ROOT=$(mktemp -d) 29 mount -t cgroup2 none $CGROUP_ROOT 30 do_umount=1 31 fi 32 echo "+hugetlb +memory" >$CGROUP_ROOT/cgroup.subtree_control 33else 34 CGROUP_ROOT=$(mount -t cgroup | grep ",hugetlb" | awk '{print $3}') 35 if [[ -z "$CGROUP_ROOT" ]]; then 36 CGROUP_ROOT=/dev/cgroup/memory 37 mount -t cgroup memory,hugetlb $CGROUP_ROOT 38 do_umount=1 39 fi 40fi 41MNT='/mnt/huge' 42 43function get_machine_hugepage_size() { 44 hpz=$(grep -i hugepagesize /proc/meminfo) 45 kb=${hpz:14:-3} 46 mb=$(($kb / 1024)) 47 echo $mb 48} 49 50MB=$(get_machine_hugepage_size) 51if (( MB >= 1024 )); then 52 UNIT="GB" 53 MB_DISPLAY=$((MB / 1024)) 54else 55 UNIT="MB" 56 MB_DISPLAY=$MB 57fi 58 59function cleanup() { 60 echo cleanup 61 set +e 62 rm -rf "$MNT"/* 2>/dev/null 63 umount "$MNT" 2>/dev/null 64 rmdir "$MNT" 2>/dev/null 65 rmdir "$CGROUP_ROOT"/a/b 2>/dev/null 66 rmdir "$CGROUP_ROOT"/a 2>/dev/null 67 rmdir "$CGROUP_ROOT"/test1 2>/dev/null 68 set -e 69} 70 71function assert_with_retry() { 72 local actual_path="$1" 73 local expected="$2" 74 local tolerance=$((7 * 1024 * 1024)) 75 local timeout=20 76 local interval=1 77 local start_time 78 local now 79 local elapsed 80 local actual 81 82 start_time=$(date +%s) 83 84 while true; do 85 actual="$(cat "$actual_path")" 86 87 if [[ $actual -ge $(($expected - $tolerance)) ]] && 88 [[ $actual -le $(($expected + $tolerance)) ]]; then 89 return 0 90 fi 91 92 now=$(date +%s) 93 elapsed=$((now - start_time)) 94 95 if [[ $elapsed -ge $timeout ]]; then 96 echo "actual = $((${actual%% *} / 1024 / 1024)) MB" 97 echo "expected = $((${expected%% *} / 1024 / 1024)) MB" 98 echo FAIL 99 cleanup 100 exit 1 101 fi 102 103 sleep $interval 104 done 105} 106 107function assert_state() { 108 local expected_a_hugetlb="$1" 109 local expected_b_hugetlb="" 110 111 if [ ! -z ${2:-} ]; then 112 expected_b_hugetlb="$2" 113 fi 114 115 assert_with_retry \ 116 "$CGROUP_ROOT/a/hugetlb.${MB_DISPLAY}${UNIT}.$usage_file" "$expected_a_hugetlb" 117 118 if [[ -n "$expected_b_hugetlb" ]]; then 119 assert_with_retry \ 120 "$CGROUP_ROOT/a/b/hugetlb.${MB_DISPLAY}${UNIT}.$usage_file" "$expected_b_hugetlb" 121 fi 122} 123 124function setup() { 125 echo 100 >/proc/sys/vm/nr_hugepages 126 mkdir "$CGROUP_ROOT"/a 127 sleep 1 128 if [[ $cgroup2 ]]; then 129 echo "+hugetlb +memory" >$CGROUP_ROOT/a/cgroup.subtree_control 130 else 131 echo 0 >$CGROUP_ROOT/a/cpuset.mems 132 echo 0 >$CGROUP_ROOT/a/cpuset.cpus 133 fi 134 135 mkdir "$CGROUP_ROOT"/a/b 136 137 if [[ ! $cgroup2 ]]; then 138 echo 0 >$CGROUP_ROOT/a/b/cpuset.mems 139 echo 0 >$CGROUP_ROOT/a/b/cpuset.cpus 140 fi 141 142 mkdir -p "$MNT" 143 mount -t hugetlbfs none "$MNT" 144} 145 146write_hugetlbfs() { 147 local cgroup="$1" 148 local path="$2" 149 local size="$3" 150 151 if [[ $cgroup2 ]]; then 152 cg_file="$CGROUP_ROOT/$cgroup/cgroup.procs" 153 else 154 echo 0 >$CGROUP_ROOT/$cgroup/cpuset.mems 155 echo 0 >$CGROUP_ROOT/$cgroup/cpuset.cpus 156 cg_file="$CGROUP_ROOT/$cgroup/tasks" 157 fi 158 159 # Spawn helper to join cgroup before exec to ensure correct cgroup accounting 160 bash -c 'echo $$ > "$1"; exec ./write_to_hugetlbfs -p "$2" -s "$3" -m 0 -o' _ \ 161 "$cg_file" "$path" "$size" & pid=$! 162 wait "$pid" 163 echo 164} 165 166set -e 167 168size=$((${MB} * 1024 * 1024 * 25)) # 50MB = 25 * 2MB hugepages. 169 170cleanup 171 172echo 173echo Test charge, rmdir, uncharge 174setup 175echo mkdir 176mkdir $CGROUP_ROOT/test1 177 178echo write 179write_hugetlbfs test1 "$MNT"/test $size 180 181echo rmdir 182rmdir $CGROUP_ROOT/test1 183mkdir $CGROUP_ROOT/test1 184 185echo uncharge 186rm -rf /mnt/huge/* 187 188cleanup 189 190echo done 191echo 192if [[ ! $cgroup2 ]]; then 193 echo "Test parent and child hugetlb usage" 194 setup 195 196 echo write 197 write_hugetlbfs a "$MNT"/test $size 198 199 echo Assert memory charged correctly for parent use. 200 assert_state $size 0 201 202 write_hugetlbfs a/b "$MNT"/test2 $size 203 204 echo Assert memory charged correctly for child use. 205 assert_state $(($size * 2)) $size 206 207 rmdir "$CGROUP_ROOT"/a/b 208 echo Assert memory reparent correctly. 209 assert_state $(($size * 2)) 210 211 rm -rf "$MNT"/* 212 umount "$MNT" 213 echo Assert memory uncharged correctly. 214 assert_state 0 215 216 cleanup 217fi 218 219echo 220echo "Test child only hugetlb usage" 221echo setup 222setup 223 224echo write 225write_hugetlbfs a/b "$MNT"/test2 $size 226 227echo Assert memory charged correctly for child only use. 228assert_state $(($size)) $size 229 230rmdir "$CGROUP_ROOT"/a/b 231echo Assert memory reparent correctly. 232assert_state $size 233 234rm -rf "$MNT"/* 235umount "$MNT" 236echo Assert memory uncharged correctly. 237assert_state 0 238 239cleanup 240 241echo ALL PASS 242 243if [[ $do_umount ]]; then 244 umount $CGROUP_ROOT 245 rm -rf $CGROUP_ROOT 246fi 247 248