1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# 4# Test for cpuset v2 partition root state (PRS) 5# 6# The sched verbose flag can be optionally set so that the console log 7# can be examined for the correct setting of scheduling domain. 8# 9 10skip_test() { 11 echo "$1" 12 echo "Test SKIPPED" 13 exit 4 # ksft_skip 14} 15 16[[ $(id -u) -eq 0 ]] || skip_test "Test must be run as root!" 17 18 19# Get wait_inotify location 20WAIT_INOTIFY=$(cd $(dirname $0); pwd)/wait_inotify 21 22# Find cgroup v2 mount point 23CGROUP2=$(mount -t cgroup2 | head -1 | awk '{print $3}') 24[[ -n "$CGROUP2" ]] || skip_test "Cgroup v2 mount point not found!" 25SUBPARTS_CPUS=$CGROUP2/.__DEBUG__.cpuset.cpus.subpartitions 26CPULIST=$(cat $CGROUP2/cpuset.cpus.effective) 27 28NR_CPUS=$(lscpu | grep "^CPU(s):" | sed -e "s/.*:[[:space:]]*//") 29[[ $NR_CPUS -lt 8 ]] && skip_test "Test needs at least 8 cpus available!" 30 31# Check to see if /dev/console exists and is writable 32if [[ -c /dev/console && -w /dev/console ]] 33then 34 CONSOLE=/dev/console 35else 36 CONSOLE=/dev/null 37fi 38 39# Set verbose flag and delay factor 40PROG=$1 41VERBOSE=0 42DELAY_FACTOR=1 43SCHED_DEBUG= 44while [[ "$1" = -* ]] 45do 46 case "$1" in 47 -v) ((VERBOSE++)) 48 # Enable sched/verbose can slow thing down 49 [[ $DELAY_FACTOR -eq 1 ]] && 50 DELAY_FACTOR=2 51 ;; 52 -d) DELAY_FACTOR=$2 53 shift 54 ;; 55 *) echo "Usage: $PROG [-v] [-d <delay-factor>" 56 exit 57 ;; 58 esac 59 shift 60done 61 62# Set sched verbose flag if available when "-v" option is specified 63if [[ $VERBOSE -gt 0 && -d /sys/kernel/debug/sched ]] 64then 65 # Used to restore the original setting during cleanup 66 SCHED_DEBUG=$(cat /sys/kernel/debug/sched/verbose) 67 echo Y > /sys/kernel/debug/sched/verbose 68fi 69 70cd $CGROUP2 71echo +cpuset > cgroup.subtree_control 72 73# 74# If cpuset has been set up and used in child cgroups, we may not be able to 75# create partition under root cgroup because of the CPU exclusivity rule. 76# So we are going to skip the test if this is the case. 77# 78[[ -d test ]] || mkdir test 79echo 0-6 > test/cpuset.cpus 80echo root > test/cpuset.cpus.partition 81cat test/cpuset.cpus.partition | grep -q invalid 82RESULT=$? 83echo member > test/cpuset.cpus.partition 84echo "" > test/cpuset.cpus 85[[ $RESULT -eq 0 ]] && skip_test "Child cgroups are using cpuset!" 86 87# 88# If isolated CPUs have been reserved at boot time (as shown in 89# cpuset.cpus.isolated), these isolated CPUs should be outside of CPUs 0-8 90# that will be used by this script for testing purpose. If not, some of 91# the tests may fail incorrectly. Wait a bit and retry again just in case 92# these isolated CPUs are leftover from previous run and have just been 93# cleaned up earlier in this script. 94# 95# These pre-isolated CPUs should stay in an isolated state throughout the 96# testing process for now. 97# 98BOOT_ISOLCPUS=$(cat $CGROUP2/cpuset.cpus.isolated) 99[[ -n "$BOOT_ISOLCPUS" ]] && { 100 sleep 0.5 101 BOOT_ISOLCPUS=$(cat $CGROUP2/cpuset.cpus.isolated) 102} 103if [[ -n "$BOOT_ISOLCPUS" ]] 104then 105 [[ $(echo $BOOT_ISOLCPUS | sed -e "s/[,-].*//") -le 8 ]] && 106 skip_test "Pre-isolated CPUs ($BOOT_ISOLCPUS) overlap CPUs to be tested" 107 echo "Pre-isolated CPUs: $BOOT_ISOLCPUS" 108fi 109 110cleanup() 111{ 112 online_cpus 113 cd $CGROUP2 114 rmdir A1/A2/A3 A1/A2 A1 B1 test/A1 test/B1 test > /dev/null 2>&1 115 rmdir rtest/p1/c11 rtest/p1/c12 rtest/p2/c21 \ 116 rtest/p2/c22 rtest/p1 rtest/p2 rtest > /dev/null 2>&1 117 [[ -n "$SCHED_DEBUG" ]] && 118 echo "$SCHED_DEBUG" > /sys/kernel/debug/sched/verbose 119} 120 121# Pause in ms 122pause() 123{ 124 DELAY=$1 125 LOOP=0 126 while [[ $LOOP -lt $DELAY_FACTOR ]] 127 do 128 sleep $DELAY 129 ((LOOP++)) 130 done 131 return 0 132} 133 134console_msg() 135{ 136 MSG=$1 137 echo "$MSG" 138 echo "" > $CONSOLE 139 echo "$MSG" > $CONSOLE 140 pause 0.01 141} 142 143test_partition() 144{ 145 EXPECTED_VAL=$1 146 echo $EXPECTED_VAL > cpuset.cpus.partition 147 [[ $? -eq 0 ]] || exit 1 148 ACTUAL_VAL=$(cat cpuset.cpus.partition) 149 [[ $ACTUAL_VAL != $EXPECTED_VAL ]] && { 150 echo "cpuset.cpus.partition: expect $EXPECTED_VAL, found $ACTUAL_VAL" 151 echo "Test FAILED" 152 exit 1 153 } 154} 155 156test_effective_cpus() 157{ 158 EXPECTED_VAL=$1 159 ACTUAL_VAL=$(cat cpuset.cpus.effective) 160 [[ "$ACTUAL_VAL" != "$EXPECTED_VAL" ]] && { 161 echo "cpuset.cpus.effective: expect '$EXPECTED_VAL', found '$ACTUAL_VAL'" 162 echo "Test FAILED" 163 exit 1 164 } 165} 166 167# Adding current process to cgroup.procs as a test 168test_add_proc() 169{ 170 OUTSTR="$1" 171 ERRMSG=$((echo $$ > cgroup.procs) |& cat) 172 echo $ERRMSG | grep -q "$OUTSTR" 173 [[ $? -ne 0 ]] && { 174 echo "cgroup.procs: expect '$OUTSTR', got '$ERRMSG'" 175 echo "Test FAILED" 176 exit 1 177 } 178 echo $$ > $CGROUP2/cgroup.procs # Move out the task 179} 180 181# 182# Cpuset controller state transition test matrix. 183# 184# Cgroup test hierarchy 185# 186# root 187# | 188# +------+------+ 189# | | 190# A1 B1 191# | 192# A2 193# | 194# A3 195# 196# P<v> = set cpus.partition (0:member, 1:root, 2:isolated) 197# C<l> = add cpu-list to cpuset.cpus 198# X<l> = add cpu-list to cpuset.cpus.exclusive 199# T = put a task into cgroup 200# CX<l> = add cpu-list to both cpuset.cpus and cpuset.cpus.exclusive 201# O<c>=<v> = Write <v> to CPU online file of <c> 202# 203# ECPUs - effective CPUs of cpusets 204# Pstate - partition root state 205# ISOLCPUS - isolated CPUs (<icpus>[,<icpus2>]) 206# 207# Note that if there are 2 fields in ISOLCPUS, the first one is for 208# sched-debug matching which includes offline CPUs and single-CPU partitions 209# while the second one is for matching cpuset.cpus.isolated. 210# 211SETUP_A123_PARTITIONS="C1-3:P1 C2-3:P1 C3:P1" 212TEST_MATRIX=( 213 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS 214 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- 215 " C0-1 . . C2-3 . C4-5 . . 0 A2:0-1" 216 " C0-1 . . C2-3 P1 . . . 0 " 217 " C0-1 . . C2-3 P1 C0-1:P1 . . 0 " 218 " C0-1 . . C2-3 P1 C1:P1 . . 0 " 219 " C0-1 . . C2-3 . . . P1 0 " 220 " C0-1:P1 . . C2-3 . C1 . . 0 " 221 " C0-1:P1 . . C2-3 . C1:P1 . . 0 " 222 " C0-1:P1 . . C2-3 . C1:P1 . P1 0 " 223 " C0-1:P1 . . C2-3 C4-5 . . . 0 A1:4-5" 224 " C0-1 . . C2-3:P1 . . . C2 0 " 225 " C0-1 . . C2-3:P1 . . . C4-5 0 B1:4-5" 226 " C0-3:P1 C2-3:P1 . . . . . . 0 A1:0-1|A2:2-3|XA2:2-3" 227 " C0-3:P1 C2-3:P1 . . C1-3 . . . 0 A1:1|A2:2-3|XA2:2-3" 228 " C2-3:P1 C3:P1 . . C3 . . . 0 A1:|A2:3|XA2:3 A1:P1|A2:P1" 229 " C2-3:P1 C3:P1 . . C3 P0 . . 0 A1:3|A2:3 A1:P1|A2:P0" 230 " C2-3:P1 C2:P1 . . C2-4 . . . 0 A1:3-4|A2:2" 231 " C2-3:P1 C3:P1 . . C3 . . C0-2 0 A1:|B1:0-2 A1:P1|A2:P1" 232 "$SETUP_A123_PARTITIONS . C2-3 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 233 234 # CPU offlining cases: 235 " C0-1 . . C2-3 . C4-5 . O2=0 0 A1:0-1|B1:3" 236 " C0-3:P1 C2-3:P1 . . O2=0 . . . 0 A1:0-1|A2:3" 237 " C0-3:P1 C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1|A2:2-3" 238 " C0-3:P1 C2-3:P1 . . O1=0 . . . 0 A1:0|A2:2-3" 239 " C0-3:P1 C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1|A2:2-3" 240 " C2-3:P1 C3:P1 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P1" 241 " C2-3:P1 C3:P2 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P2" 242 " C2-3:P1 C3:P1 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P1" 243 " C2-3:P1 C3:P2 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P2" 244 " C2-3:P1 C3:P1 . . O2=0 . . . 0 A1:|A2:3 A1:P1|A2:P1" 245 " C2-3:P1 C3:P1 . . O3=0 . . . 0 A1:2|A2: A1:P1|A2:P1" 246 " C2-3:P1 C3:P1 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-1" 247 " C2-3:P1 C3:P1 . . . T:O3=0 . . 0 A1:2|A2:2 A1:P1|A2:P-1" 248 " C2-3:P1 C3:P2 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-2" 249 " C1-3:P1 C3:P2 . . . T:O3=0 . . 0 A1:1-2|A2:1-2 A1:P1|A2:P-2 3|" 250 " C1-3:P1 C3:P2 . . . T:O3=0 O3=1 . 0 A1:1-2|A2:3 A1:P1|A2:P2 3" 251 "$SETUP_A123_PARTITIONS . O1=0 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 252 "$SETUP_A123_PARTITIONS . O2=0 . . . 0 A1:1|A2:|A3:3 A1:P1|A2:P1|A3:P1" 253 "$SETUP_A123_PARTITIONS . O3=0 . . . 0 A1:1|A2:2|A3: A1:P1|A2:P1|A3:P1" 254 "$SETUP_A123_PARTITIONS . T:O1=0 . . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1" 255 "$SETUP_A123_PARTITIONS . . T:O2=0 . . 0 A1:1|A2:3|A3:3 A1:P1|A2:P1|A3:P-1" 256 "$SETUP_A123_PARTITIONS . . . T:O3=0 . 0 A1:1|A2:2|A3:2 A1:P1|A2:P1|A3:P-1" 257 "$SETUP_A123_PARTITIONS . T:O1=0 O1=1 . . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 258 "$SETUP_A123_PARTITIONS . . T:O2=0 O2=1 . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 259 "$SETUP_A123_PARTITIONS . . . T:O3=0 O3=1 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 260 "$SETUP_A123_PARTITIONS . T:O1=0 O2=0 O1=1 . 0 A1:1|A2:|A3:3 A1:P1|A2:P1|A3:P1" 261 "$SETUP_A123_PARTITIONS . T:O1=0 O2=0 O2=1 . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1" 262 263 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS 264 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- 265 # 266 # Remote partition and cpuset.cpus.exclusive tests 267 # 268 " C0-3 C1-3 C2-3 . X2-3 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:2-3" 269 " C0-3 C1-3 C2-3 . X2-3 X2-3:P2 . . 0 A1:0-1|A2:2-3|A3:2-3 A1:P0|A2:P2 2-3" 270 " C0-3 C1-3 C2-3 . X2-3 X3:P2 . . 0 A1:0-2|A2:3|A3:3 A1:P0|A2:P2 3" 271 " C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3" 272 " C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:C3 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3" 273 " C0-3 C1-3 C2-3 C2-3 . . . P2 0 A1:0-1|A2:1|A3:1|B1:2-3 A1:P0|A3:P0|B1:P2" 274 " C0-3 C1-3 C2-3 C4-5 . . . P2 0 B1:4-5 B1:P2 4-5" 275 " C0-3 C1-3 C2-3 C4 X2-3 X2-3 X2-3:P2 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4" 276 " C0-3 C1-3 C2-3 C4 X2-3 X2-3 X2-3:P2:C1-3 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4" 277 " C0-3 C1-3 C2-3 C4 X1-3 X1-3:P2 P2 . 0 A2:1|A3:2-3 A2:P2|A3:P2 1-3" 278 " C0-3 C1-3 C2-3 C4 X2-3 X2-3 X2-3:P2 P2:C4-5 0 A3:2-3|B1:4-5 A3:P2|B1:P2 2-5" 279 " C4:X0-3 X1-3 X2-3 . . P2 . . 0 A1:4|A2:1-3|A3:1-3 A2:P2 1-3" 280 " C4:X0-3 X1-3 X2-3 . . . P2 . 0 A1:4|A2:4|A3:2-3 A3:P2 2-3" 281 282 # Nested remote/local partition tests 283 " C0-3 C1-3 C2-3 C4-5 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4-5 \ 284 A1:P0|A2:P1|A3:P2|B1:P1 2-3" 285 " C0-3 C1-3 C2-3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4 \ 286 A1:P0|A2:P1|A3:P2|B1:P1 2-4|2-3" 287 " C0-3 C1-3 C2-3 C4 X2-3 X2-3:P1 . P1 0 A1:0-1|A2:2-3|A3:2-3|B1:4 \ 288 A1:P0|A2:P1|A3:P0|B1:P1" 289 " C0-3 C1-3 C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:2|A3:3|B1:4 \ 290 A1:P0|A2:P1|A3:P2|B1:P1 2-4|3" 291 " C0-4 C1-4 C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1|A2:2-3|A3:4 \ 292 A1:P0|A2:P2|A3:P1 2-4|2-3" 293 " C0-4 C1-4 C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1|A2:2|A3:3-4 \ 294 A1:P0|A2:P2|A3:P1 2" 295 " C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \ 296 . . X5 . . 0 A1:0-4|A2:1-4|A3:2-4 \ 297 A1:P0|A2:P-2|A3:P-1 ." 298 " C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \ 299 . . . X1 . 0 A1:0-1|A2:2-4|A3:2-4 \ 300 A1:P0|A2:P2|A3:P-1 2-4" 301 302 # Remote partition offline tests 303 " C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:O2=0 . 0 A1:0-1|A2:1|A3:3 A1:P0|A3:P2 2-3" 304 " C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:O2=0 O2=1 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3" 305 " C0-3 C1-3 C3 . X2-3 X2-3 P2:O3=0 . 0 A1:0-2|A2:1-2|A3: A1:P0|A3:P2 3" 306 " C0-3 C1-3 C3 . X2-3 X2-3 T:P2:O3=0 . 0 A1:0-2|A2:1-2|A3:1-2 A1:P0|A3:P-2 3|" 307 308 # An invalidated remote partition cannot self-recover from hotplug 309 " C0-3 C1-3 C2 . X2-3 X2-3 T:P2:O2=0 O2=1 0 A1:0-3|A2:1-3|A3:2 A1:P0|A3:P-2 ." 310 311 # cpus.exclusive.effective clearing test 312 " C0-3 C1-3 C2 . X2-3:X . . . 0 A1:0-3|A2:1-3|A3:2|XA1:" 313 314 # Invalid to valid remote partition transition test 315 " C0-3 C1-3 . . . X3:P2 . . 0 A1:0-3|A2:1-3|XA2: A2:P-2 ." 316 " C0-3 C1-3:X3:P2 . . X2-3 P2 . . 0 A1:0-2|A2:3|XA2:3 A2:P2 3" 317 318 # Invalid to valid local partition direct transition tests 319 " C1-3:P2 X4:P2 . . . . . . 0 A1:1-3|XA1:1-3|A2:1-3:XA2: A1:P2|A2:P-2 1-3" 320 " C1-3:P2 X4:P2 . . . X3:P2 . . 0 A1:1-2|XA1:1-3|A2:3:XA2:3 A1:P2|A2:P2 1-3" 321 " C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4|B1:5-6 A1:P2|B1:P0" 322 " C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3|B1:4-6 A1:P2|B1:P0 0-3" 323 324 # Local partition invalidation tests 325 " C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \ 326 . . . . . 0 A1:1|A2:2|A3:3 A1:P2|A2:P2|A3:P2 1-3" 327 " C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \ 328 . . X4 . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3" 329 " C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \ 330 . . C4:X . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3" 331 # Local partition CPU change tests 332 " C0-5:P2 C4-5:P1 . . . C3-5 . . 0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2" 333 " C0-5:P2 C4-5:P1 . . C1-5 . . . 0 A1:1-3|A2:4-5 A1:P2|A2:P1 1-3" 334 335 # cpus_allowed/exclusive_cpus update tests 336 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \ 337 . X:C4 . P2 . 0 A1:4|A2:4|XA2:|XA3:|A3:4 \ 338 A1:P0|A3:P-2 ." 339 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \ 340 . X1 . P2 . 0 A1:0-3|A2:1-3|XA1:1|XA2:|XA3:|A3:2-3 \ 341 A1:P0|A3:P-2 ." 342 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \ 343 . . X3 P2 . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3 \ 344 A1:P0|A3:P2 3" 345 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3:P2 \ 346 . . X3 . . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3|XA3:3 \ 347 A1:P0|A3:P2 3" 348 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3:P2 \ 349 . X4 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:4|XA2:|XA3 \ 350 A1:P0|A3:P-2" 351 352 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS 353 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- 354 # 355 # Incorrect change to cpuset.cpus[.exclusive] invalidates partition root 356 # 357 # Adding CPUs to partition root that are not in parent's 358 # cpuset.cpus is allowed, but those extra CPUs are ignored. 359 " C2-3:P1 C3:P1 . . . C2-4 . . 0 A1:|A2:2-3 A1:P1|A2:P1" 360 361 # Taking away all CPUs from parent or itself if there are tasks 362 # will make the partition invalid. 363 " C2-3:P1 C3:P1 . . T C2-3 . . 0 A1:2-3|A2:2-3 A1:P1|A2:P-1" 364 " C3:P1 C3 . . T P1 . . 0 A1:3|A2:3 A1:P1|A2:P-1" 365 "$SETUP_A123_PARTITIONS . T:C2-3 . . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1" 366 "$SETUP_A123_PARTITIONS . T:C2-3:C1-3 . . . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 367 368 # Changing a partition root to member makes child partitions invalid 369 " C2-3:P1 C3:P1 . . P0 . . . 0 A1:2-3|A2:3 A1:P0|A2:P-1" 370 "$SETUP_A123_PARTITIONS . C2-3 P0 . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P0|A3:P-1" 371 372 # cpuset.cpus can contains cpus not in parent's cpuset.cpus as long 373 # as they overlap. 374 " C2-3:P1 . . . . C3-4:P1 . . 0 A1:2|A2:3 A1:P1|A2:P1" 375 376 # Deletion of CPUs distributed to child cgroup is allowed. 377 " C0-1:P1 C1 . C2-3 C4-5 . . . 0 A1:4-5|A2:4-5" 378 379 # To become a valid partition root, cpuset.cpus must overlap parent's 380 # cpuset.cpus. 381 " C0-1:P1 . . C2-3 . C4-5:P1 . . 0 A1:0-1|A2:0-1 A1:P1|A2:P-1" 382 383 # Enabling partition with child cpusets is allowed 384 " C0-1 C1 . C2-3 P1 . . . 0 A1:0-1|A2:1 A1:P1" 385 386 # A partition root with non-partition root parent is invalid| but it 387 # can be made valid if its parent becomes a partition root too. 388 " C0-1 C1 . C2-3 . P2 . . 0 A1:0-1|A2:1 A1:P0|A2:P-2" 389 " C0-1 C1:P2 . C2-3 P1 . . . 0 A1:0|A2:1 A1:P1|A2:P2 0-1|1" 390 391 # A non-exclusive cpuset.cpus change will not invalidate its siblings partition. 392 " C0-1:P1 . . C2-3 C0-2 . . . 0 A1:0-2|B1:3 A1:P1|B1:P0" 393 " C0-1:P1 . . P1:C2-3 C0-2 . . . 0 A1:0-1|XA1:0-1|B1:2-3 A1:P1|B1:P1" 394 " C0-1 . . P1:C2-3 C0-2 . . . 0 A1:0-1|B1:2-3 A1:P0|B1:P1" 395 396 # cpuset.cpus can overlap with sibling cpuset.cpus.exclusive but not subsumed by it 397 " C0-3 . . C4-5 X5 . . . 0 A1:0-3|B1:4-5" 398 399 # Child partition root that try to take all CPUs from parent partition 400 # with tasks will remain invalid. 401 " C1-4:P1 P1 . . . . . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1" 402 " C1-4:P1 P1 . . . C1-4 . . 0 A1|A2:1-4 A1:P1|A2:P1" 403 " C1-4:P1 P1 . . T C1-4 . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1" 404 405 # Clearing of cpuset.cpus with a preset cpuset.cpus.exclusive shouldn't 406 # affect cpuset.cpus.exclusive.effective. 407 " C1-4:X3 C1:X3 . . . C . . 0 A2:1-4|XA2:3" 408 409 # cpuset.cpus can contain CPUs that overlap a sibling cpuset with cpus.exclusive 410 # but creating a local partition out of it is not allowed. Similarly and change 411 # in cpuset.cpus of a local partition that overlaps sibling exclusive CPUs will 412 # invalidate it. 413 " CX1-4 CX2-4:P2 . C5-6 . . . P1 0 A1:1|A2:2-4|B1:5-6|XB1:5-6 \ 414 A1:P0|A2:P2:B1:P1 2-4" 415 " CX1-4 CX2-4:P2 . C3-6 . . . P1 0 A1:1|A2:2-4|B1:5-6 \ 416 A1:P0|A2:P2:B1:P-1 2-4" 417 " CX1-4 CX2-4:P2 . C5-6 . . . P1:C3-6 0 A1:1|A2:2-4|B1:5-6 \ 418 A1:P0|A2:P2:B1:P-1 2-4" 419 420 # When multiple partitions with conflicting cpuset.cpus are created, the 421 # latter created ones will only get what are left of the available exclusive 422 # CPUs. 423 " C1-3:P1 . . . . . . C3-5:P1 0 A1:1-3|B1:4-5:XB1:4-5 A1:P1|B1:P1" 424 425 # cpuset.cpus can be set to a subset of sibling's cpuset.cpus.exclusive 426 " C1-3:X1-3 . . C4-5 . . . C1-2 0 A1:1-3|B1:1-2" 427 428 # cpuset.cpus can become empty with task in it as it inherits parent's effective CPUs 429 " C1-3 C2 . . . T:C . . 0 A1:1-3|A2:1-3" 430 431 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS 432 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- 433 # Failure cases: 434 435 # A task cannot be added to a partition with no cpu 436 " C2-3:P1 C3:P1 . . O2=0:T . . . 1 A1:|A2:3 A1:P1|A2:P1" 437 438 # Changes to cpuset.cpus.exclusive that violate exclusivity rule is rejected 439 " C0-3 . . C4-5 X0-3 . . X3-5 1 A1:0-3|B1:4-5" 440 441 # cpuset.cpus.exclusive cannot be set to a superset of sibling's cpuset.cpus 442 " C0-3 . . C4-5 X3-5 . . . 1 A1:0-3|B1:4-5" 443) 444 445# 446# Cpuset controller remote partition test matrix. 447# 448# Cgroup test hierarchy 449# 450# root 451# | 452# rtest (cpuset.cpus.exclusive=1-7) 453# | 454# +------+------+ 455# | | 456# p1 p2 457# +--+--+ +--+--+ 458# | | | | 459# c11 c12 c21 c22 460# 461# REMOTE_TEST_MATRIX uses the same notational convention as TEST_MATRIX. 462# Only CPUs 1-7 should be used. 463# 464REMOTE_TEST_MATRIX=( 465 # old-p1 old-p2 old-c11 old-c12 old-c21 old-c22 466 # new-p1 new-p2 new-c11 new-c12 new-c21 new-c22 ECPUs Pstate ISOLCPUS 467 # ------ ------ ------- ------- ------- ------- ----- ------ -------- 468 " X1-3 X4-6 X1-2 X3 X4-5 X6 \ 469 . . P2 P2 P2 P2 c11:1-2|c12:3|c21:4-5|c22:6 \ 470 c11:P2|c12:P2|c21:P2|c22:P2 1-6" 471 " CX1-4 . X1-2:P2 C3 . . \ 472 . . . C3-4 . . p1:3-4|c11:1-2|c12:3-4 \ 473 p1:P0|c11:P2|c12:P0 1-2" 474 " CX1-4 . X1-2:P2 . . . \ 475 X2-4 . . . . . p1:1,3-4|c11:2 \ 476 p1:P0|c11:P2 2" 477 " CX1-5 . X1-2:P2 X3-5:P1 . . \ 478 X2-4 . . . . . p1:1,5|c11:2|c12:3-4 \ 479 p1:P0|c11:P2|c12:P1 2" 480 " CX1-4 . X1-2:P2 X3-4:P1 . . \ 481 . . X2 . . . p1:1|c11:2|c12:3-4 \ 482 p1:P0|c11:P2|c12:P1 2" 483 # p1 as member, will get its effective CPUs from its parent rtest 484 " CX1-4 . X1-2:P2 X3-4:P1 . . \ 485 . . X1 CX2-4 . . p1:5-7|c11:1|c12:2-4 \ 486 p1:P0|c11:P2|c12:P1 1" 487 " CX1-4 X5-6:P1 . . . . \ 488 . . X1-2:P2 X4-5:P1 . X1-7:P2 p1:3|c11:1-2|c12:4:c22:5-6 \ 489 p1:P0|p2:P1|c11:P2|c12:P1|c22:P2 \ 490 1-2,4-6|1-2,5-6" 491 # c12 whose cpuset.cpus CPUs are all granted to c11 will become invalid partition 492 " C1-5:P1 . C1-4:P1 C2-3 . . \ 493 . . . P1 . . p1:5|c11:1-4|c12:5 \ 494 p1:P1|c11:P1|c12:P-1" 495 # Narrowing cpuset.cpus to previously sibling-excluded CPUs should 496 # not return CPUs that were never actually owned. 497 " C1-4:P1 . C1-2:P1 C1-3:P2 . . \ 498 . . . C3 . . p1:4|c11:1-2|c12:3 \ 499 p1:P1|c11:P1|c12:P2 3" 500 # Expanding cpuset.cpus to include a previously sibling-excluded CPU 501 # after the sibling has become a member should correctly request it. 502 " C1-4:P1 . C1-2:P1 C1-3:P2 . . \ 503 . . P0 C2-3 . . p1:1,4|c11:1|c12:2-3 \ 504 p1:P1|c11:P0|c12:P2 2-3" 505 # Changing a sibling partition's cpuset.cpus to overlap with another 506 # sibling partition should invalidate itself and return only actually 507 # allocated CPUs (effective_xcpus) to the parent. 508 " C1-4:P1 . C1-2:P1 C2-4:P2 . . \ 509 . . . C1-2 . . p1:3-4|c11:1-2|c12:3-4 \ 510 p1:P1|c11:P1|c12:P-2" 511 # Cpusets with empty cpuset.cpus should inherit parent's effective_cpus 512 " C1-4:P1 C5-6 C1-2 . C5 . \ 513 . P1 P1 . . . p1:3-4|p2:5-6|c11:1-2|c12:3-4|c21:5|c22:5-6 \ 514 p1:P1|p2:P1|c11:P1" 515 " C1-4:P1 C5-6 C1-2 . C5 . \ 516 . P1 P1 . O5=0 . p1:3-4|p2:6|c11:1-2|c12:3-4|c21:6|c22:6 \ 517 p1:P1|p2:P1|c11:P1" 518) 519 520# 521# Write to the cpu online file 522# $1 - <c>=<v> where <c> = cpu number, <v> value to be written 523# 524write_cpu_online() 525{ 526 CPU=${1%=*} 527 VAL=${1#*=} 528 CPUFILE=//sys/devices/system/cpu/cpu${CPU}/online 529 echo $VAL > $CPUFILE || return 1 530 if [[ $VAL -eq 0 ]] 531 then 532 OFFLINE_CPUS="$OFFLINE_CPUS $CPU" 533 else 534 [[ -n "$OFFLINE_CPUS" ]] && { 535 OFFLINE_CPUS=$(echo $CPU $CPU $OFFLINE_CPUS | fmt -1 |\ 536 sort | uniq -u) 537 } 538 fi 539 pause 0.05 540} 541 542# 543# Set controller state 544# $1 - cgroup directory 545# $2 - state 546# $3 - showerr 547# 548# The presence of ":" in state means transition from one to the next. 549# 550set_ctrl_state() 551{ 552 TMPMSG=/tmp/.msg_$$ 553 CGRP=$1 554 STATE=$2 555 SHOWERR=${3} 556 HASERR=0 557 REDIRECT="2> $TMPMSG" 558 [[ -z "$STATE" || "$STATE" = '.' ]] && return 0 559 [[ $VERBOSE -gt 0 ]] && SHOWERR=1 560 561 rm -f $TMPMSG 562 for CMD in $(echo $STATE | sed -e "s/:/ /g") 563 do 564 TFILE=$CGRP/cgroup.procs 565 PFILE=$CGRP/cpuset.cpus.partition 566 CFILE=$CGRP/cpuset.cpus 567 XFILE=$CGRP/cpuset.cpus.exclusive 568 569 # Enable cpuset controller if not enabled yet 570 [[ -f $CFILE ]] || { 571 COMM="echo +cpuset > $CGRP/../cgroup.subtree_control" 572 eval $COMM $REDIRECT 573 } 574 case $CMD in 575 X*) 576 CPUS=${CMD#?} 577 COMM="echo $CPUS > $XFILE" 578 eval $COMM $REDIRECT 579 ;; 580 CX*) 581 CPUS=${CMD#??} 582 COMM="echo $CPUS > $CFILE; echo $CPUS > $XFILE" 583 eval $COMM $REDIRECT 584 ;; 585 C*) CPUS=${CMD#?} 586 COMM="echo $CPUS > $CFILE" 587 eval $COMM $REDIRECT 588 ;; 589 P*) VAL=${CMD#?} 590 case $VAL in 591 0) VAL=member 592 ;; 593 1) VAL=root 594 ;; 595 2) VAL=isolated 596 ;; 597 *) 598 echo "Invalid partition state - $VAL" 599 exit 1 600 ;; 601 esac 602 COMM="echo $VAL > $PFILE" 603 eval $COMM $REDIRECT 604 ;; 605 O*) VAL=${CMD#?} 606 COMM="write_cpu_online $VAL" 607 eval $COMM $REDIRECT 608 ;; 609 T*) COMM="echo 0 > $TFILE" 610 eval $COMM $REDIRECT 611 ;; 612 *) echo "Unknown command: $CMD" 613 exit 1 614 ;; 615 esac 616 RET=$? 617 [[ $RET -ne 0 ]] && { 618 [[ -n "$SHOWERR" ]] && { 619 echo "$COMM" 620 cat $TMPMSG 621 } 622 HASERR=1 623 } 624 pause 0.01 625 rm -f $TMPMSG 626 done 627 return $HASERR 628} 629 630set_ctrl_state_noerr() 631{ 632 CGRP=$1 633 STATE=$2 634 [[ -d $CGRP ]] || mkdir $CGRP 635 set_ctrl_state $CGRP $STATE 1 636 [[ $? -ne 0 ]] && { 637 echo "ERROR: Failed to set $2 to cgroup $1!" 638 exit 1 639 } 640} 641 642online_cpus() 643{ 644 [[ -n "$OFFLINE_CPUS" ]] && { 645 for C in $OFFLINE_CPUS 646 do 647 write_cpu_online ${C}=1 648 done 649 } 650} 651 652# 653# Remove all the test cgroup directories 654# 655reset_cgroup_states() 656{ 657 echo 0 > $CGROUP2/cgroup.procs 658 online_cpus 659 rmdir $RESET_LIST > /dev/null 2>&1 660} 661 662dump_states() 663{ 664 for DIR in $CGROUP_LIST 665 do 666 CPUS=$DIR/cpuset.cpus 667 ECPUS=$DIR/cpuset.cpus.effective 668 XCPUS=$DIR/cpuset.cpus.exclusive 669 XECPUS=$DIR/cpuset.cpus.exclusive.effective 670 PRS=$DIR/cpuset.cpus.partition 671 PCPUS=$DIR/.__DEBUG__.cpuset.cpus.subpartitions 672 ISCPUS=$DIR/cpuset.cpus.isolated 673 [[ -e $CPUS ]] && echo "$CPUS: $(cat $CPUS)" 674 [[ -e $XCPUS ]] && echo "$XCPUS: $(cat $XCPUS)" 675 [[ -e $ECPUS ]] && echo "$ECPUS: $(cat $ECPUS)" 676 [[ -e $XECPUS ]] && echo "$XECPUS: $(cat $XECPUS)" 677 [[ -e $PRS ]] && echo "$PRS: $(cat $PRS)" 678 [[ -e $PCPUS ]] && echo "$PCPUS: $(cat $PCPUS)" 679 [[ -e $ISCPUS ]] && echo "$ISCPUS: $(cat $ISCPUS)" 680 done 681} 682 683# 684# Set the actual cgroup directory into $CGRP_DIR 685# $1 - cgroup name 686# 687set_cgroup_dir() 688{ 689 CGRP_DIR=$1 690 [[ $CGRP_DIR = A2 ]] && CGRP_DIR=A1/A2 691 [[ $CGRP_DIR = A3 ]] && CGRP_DIR=A1/A2/A3 692 [[ $CGRP_DIR = c11 ]] && CGRP_DIR=p1/c11 693 [[ $CGRP_DIR = c12 ]] && CGRP_DIR=p1/c12 694 [[ $CGRP_DIR = c21 ]] && CGRP_DIR=p2/c21 695 [[ $CGRP_DIR = c22 ]] && CGRP_DIR=p2/c22 696} 697 698# 699# Check effective cpus 700# $1 - check string, format: <cgroup>:<cpu-list>[|<cgroup>:<cpu-list>]* 701# 702check_effective_cpus() 703{ 704 CHK_STR=$1 705 for CHK in $(echo $CHK_STR | sed -e "s/|/ /g") 706 do 707 set -- $(echo $CHK | sed -e "s/:/ /g") 708 CGRP=$1 709 EXPECTED_CPUS=$2 710 ACTUAL_CPUS= 711 if [[ $CGRP = X* ]] 712 then 713 CGRP=${CGRP#X} 714 FILE=cpuset.cpus.exclusive.effective 715 else 716 FILE=cpuset.cpus.effective 717 fi 718 set_cgroup_dir $CGRP 719 [[ -e $CGRP_DIR/$FILE ]] || return 1 720 ACTUAL_CPUS=$(cat $CGRP_DIR/$FILE) 721 [[ $EXPECTED_CPUS = $ACTUAL_CPUS ]] || return 1 722 done 723} 724 725# 726# Check cgroup states 727# $1 - check string, format: <cgroup>:<state>[|<cgroup>:<state>]* 728# 729check_cgroup_states() 730{ 731 CHK_STR=$1 732 for CHK in $(echo $CHK_STR | sed -e "s/|/ /g") 733 do 734 set -- $(echo $CHK | sed -e "s/:/ /g") 735 CGRP=$1 736 EXPECTED_STATE=$2 737 FILE= 738 EVAL=$(expr substr $EXPECTED_STATE 2 2) 739 740 set_cgroup_dir $CGRP 741 case $EXPECTED_STATE in 742 P*) FILE=$CGRP_DIR/cpuset.cpus.partition 743 ;; 744 *) echo "Unknown state: $EXPECTED_STATE!" 745 exit 1 746 ;; 747 esac 748 ACTUAL_STATE=$(cat $FILE) 749 750 case "$ACTUAL_STATE" in 751 member) VAL=0 752 ;; 753 root) VAL=1 754 ;; 755 isolated) 756 VAL=2 757 ;; 758 "root invalid"*) 759 VAL=-1 760 ;; 761 "isolated invalid"*) 762 VAL=-2 763 ;; 764 esac 765 [[ $EVAL != $VAL ]] && return 1 766 767 # 768 # For root partition, dump sched-domains info to console if 769 # verbose mode set for manual comparison with sched debug info. 770 # 771 [[ $VAL -eq 1 && $VERBOSE -gt 0 ]] && { 772 DOMS=$(cat $CGRP_DIR/cpuset.cpus.effective) 773 [[ -n "$DOMS" ]] && 774 echo " [$CGRP_DIR] sched-domain: $DOMS" > $CONSOLE 775 } 776 done 777 return 0 778} 779 780# 781# Get isolated (including offline) CPUs by looking at 782# /sys/kernel/debug/sched/domains and cpuset.cpus.isolated control file, 783# if available, and compare that with the expected value. 784# 785# Note that isolated CPUs from the sched/domains context include offline 786# CPUs as well as CPUs in non-isolated 1-CPU partition. Those CPUs may 787# not be included in the cpuset.cpus.isolated control file which contains 788# only CPUs in isolated partitions as well as those that are isolated at 789# boot time. 790# 791# $1 - expected isolated cpu list(s) <isolcpus1>{|<isolcpus2>} 792# <isolcpus1> - expected sched/domains value 793# <isolcpus2> - cpuset.cpus.isolated value = <isolcpus1> if not defined 794# 795check_isolcpus() 796{ 797 EXPECTED_ISOLCPUS=$1 798 ISCPUS=${CGROUP2}/cpuset.cpus.isolated 799 ISOLCPUS=$(cat $ISCPUS) 800 HKICPUS=$(cat /sys/devices/system/cpu/isolated) 801 LASTISOLCPU= 802 SCHED_DOMAINS=/sys/kernel/debug/sched/domains 803 if [[ $EXPECTED_ISOLCPUS = . ]] 804 then 805 EXPECTED_ISOLCPUS= 806 EXPECTED_SDOMAIN= 807 elif [[ $(expr $EXPECTED_ISOLCPUS : ".*|.*") > 0 ]] 808 then 809 set -- $(echo $EXPECTED_ISOLCPUS | sed -e "s/|/ /g") 810 EXPECTED_ISOLCPUS=$2 811 EXPECTED_SDOMAIN=$1 812 else 813 EXPECTED_SDOMAIN=$EXPECTED_ISOLCPUS 814 fi 815 816 # 817 # Appending pre-isolated CPUs 818 # Even though CPU #8 isn't used for testing, it can't be pre-isolated 819 # to make appending those CPUs easier. 820 # 821 [[ -n "$BOOT_ISOLCPUS" ]] && { 822 EXPECTED_ISOLCPUS=${EXPECTED_ISOLCPUS:+${EXPECTED_ISOLCPUS},}${BOOT_ISOLCPUS} 823 EXPECTED_SDOMAIN=${EXPECTED_SDOMAIN:+${EXPECTED_SDOMAIN},}${BOOT_ISOLCPUS} 824 } 825 826 # 827 # Check cpuset.cpus.isolated cpumask 828 # 829 [[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && { 830 # Take a 50ms pause and try again 831 pause 0.05 832 ISOLCPUS=$(cat $ISCPUS) 833 } 834 [[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && return 1 835 ISOLCPUS= 836 EXPECTED_ISOLCPUS=$EXPECTED_SDOMAIN 837 838 # 839 # The inverse of HK_TYPE_DOMAIN cpumask in $HKICPUS should match $ISOLCPUS 840 # 841 [[ "$ISOLCPUS" != "$HKICPUS" ]] && return 1 842 843 # 844 # Use the sched domain in debugfs to check isolated CPUs, if available 845 # 846 [[ -d $SCHED_DOMAINS ]] || return 0 847 848 for ((CPU=0; CPU < $NR_CPUS; CPU++)) 849 do 850 [[ -n "$(ls ${SCHED_DOMAINS}/cpu$CPU)" ]] && continue 851 852 if [[ -z "$LASTISOLCPU" ]] 853 then 854 ISOLCPUS=$CPU 855 LASTISOLCPU=$CPU 856 elif [[ "$LASTISOLCPU" -eq $((CPU - 1)) ]] 857 then 858 echo $ISOLCPUS | grep -q "\<$LASTISOLCPU\$" 859 if [[ $? -eq 0 ]] 860 then 861 ISOLCPUS=${ISOLCPUS}- 862 fi 863 LASTISOLCPU=$CPU 864 else 865 if [[ $ISOLCPUS = *- ]] 866 then 867 ISOLCPUS=${ISOLCPUS}$LASTISOLCPU 868 fi 869 ISOLCPUS=${ISOLCPUS},$CPU 870 LASTISOLCPU=$CPU 871 fi 872 done 873 [[ "$ISOLCPUS" = *- ]] && ISOLCPUS=${ISOLCPUS}$LASTISOLCPU 874 875 [[ "$EXPECTED_SDOMAIN" = "$ISOLCPUS" ]] 876} 877 878test_fail() 879{ 880 TESTNUM=$1 881 TESTTYPE=$2 882 ADDINFO=$3 883 echo "Test $TEST[$TESTNUM] failed $TESTTYPE check!" 884 [[ -n "$ADDINFO" ]] && echo "*** $ADDINFO ***" 885 eval echo \${$TEST[$I]} 886 echo 887 dump_states 888 exit 1 889} 890 891# 892# Check to see if there are unexpected isolated CPUs left beyond the boot 893# time isolated ones. 894# 895null_isolcpus_check() 896{ 897 [[ $VERBOSE -gt 0 ]] || return 0 898 # Retry a few times before printing error 899 RETRY=0 900 while [[ $RETRY -lt 8 ]] 901 do 902 pause 0.02 903 check_isolcpus "." 904 [[ $? -eq 0 ]] && return 0 905 ((RETRY++)) 906 done 907 echo "Unexpected isolated CPUs: $ISOLCPUS" 908 dump_states 909 exit 1 910} 911 912# 913# Check state transition test result 914# $1 - Test number 915# $2 - Expected effective CPU values 916# $3 - Expected partition states 917# $4 - Expected isolated CPUs 918# 919check_test_results() 920{ 921 _NR=$1 922 _ECPUS="$2" 923 _PSTATES="$3" 924 _ISOLCPUS="$4" 925 926 [[ -n "$_ECPUS" && "$_ECPUS" != . ]] && { 927 check_effective_cpus $_ECPUS 928 [[ $? -ne 0 ]] && test_fail $_NR "effective CPU" \ 929 "Cgroup $CGRP: expected $EXPECTED_CPUS, got $ACTUAL_CPUS" 930 } 931 932 [[ -n "$_PSTATES" && "$_PSTATES" != . ]] && { 933 check_cgroup_states $_PSTATES 934 [[ $? -ne 0 ]] && test_fail $_NR states \ 935 "Cgroup $CGRP: expected $EXPECTED_STATE, got $ACTUAL_STATE" 936 } 937 938 # Compare the expected isolated CPUs with the actual ones, 939 # if available 940 [[ -n "$_ISOLCPUS" ]] && { 941 check_isolcpus $_ISOLCPUS 942 [[ $? -ne 0 ]] && { 943 [[ -n "$BOOT_ISOLCPUS" ]] && _ISOLCPUS=${_ISOLCPUS},${BOOT_ISOLCPUS} 944 test_fail $_NR "isolated CPU" \ 945 "Expect $_ISOLCPUS, get $ISOLCPUS instead" 946 } 947 } 948 reset_cgroup_states 949 # 950 # Check to see if effective cpu list changes 951 # 952 _NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective) 953 RETRY=0 954 while [[ $_NEWLIST != $CPULIST && $RETRY -lt 8 ]] 955 do 956 # Wait a bit longer & recheck a few times 957 pause 0.02 958 ((RETRY++)) 959 _NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective) 960 done 961 [[ $_NEWLIST != $CPULIST ]] && { 962 echo "Effective cpus changed to $_NEWLIST after test $_NR!" 963 exit 1 964 } 965 null_isolcpus_check 966 [[ $VERBOSE -gt 0 ]] && echo "Test $I done." 967} 968 969# 970# Run cpuset state transition test 971# $1 - test matrix name 972# 973# This test is somewhat fragile as delays (sleep x) are added in various 974# places to make sure state changes are fully propagated before the next 975# action. These delays may need to be adjusted if running in a slower machine. 976# 977run_state_test() 978{ 979 TEST=$1 980 CGROUP_LIST=". A1 A1/A2 A1/A2/A3 B1" 981 RESET_LIST="A1/A2/A3 A1/A2 A1 B1" 982 I=0 983 eval CNT="\${#$TEST[@]}" 984 985 reset_cgroup_states 986 console_msg "Running state transition test ..." 987 988 while [[ $I -lt $CNT ]] 989 do 990 echo "Running test $I ..." > $CONSOLE 991 [[ $VERBOSE -gt 1 ]] && { 992 echo "" 993 eval echo \${$TEST[$I]} 994 } 995 eval set -- "\${$TEST[$I]}" 996 OLD_A1=$1 997 OLD_A2=$2 998 OLD_A3=$3 999 OLD_B1=$4 1000 NEW_A1=$5 1001 NEW_A2=$6 1002 NEW_A3=$7 1003 NEW_B1=$8 1004 RESULT=$9 1005 ECPUS=${10} 1006 STATES=${11} 1007 ICPUS=${12} 1008 1009 set_ctrl_state_noerr A1 $OLD_A1 1010 set_ctrl_state_noerr A1/A2 $OLD_A2 1011 set_ctrl_state_noerr A1/A2/A3 $OLD_A3 1012 set_ctrl_state_noerr B1 $OLD_B1 1013 1014 RETVAL=0 1015 set_ctrl_state A1 $NEW_A1; ((RETVAL += $?)) 1016 set_ctrl_state A1/A2 $NEW_A2; ((RETVAL += $?)) 1017 set_ctrl_state A1/A2/A3 $NEW_A3; ((RETVAL += $?)) 1018 set_ctrl_state B1 $NEW_B1; ((RETVAL += $?)) 1019 1020 [[ $RETVAL -ne $RESULT ]] && test_fail $I result 1021 1022 check_test_results $I "$ECPUS" "$STATES" "$ICPUS" 1023 ((I++)) 1024 done 1025 echo "All $I tests of $TEST PASSED." 1026} 1027 1028# 1029# Run cpuset remote partition state transition test 1030# $1 - test matrix name 1031# 1032run_remote_state_test() 1033{ 1034 TEST=$1 1035 [[ -d rtest ]] || mkdir rtest 1036 cd rtest 1037 echo +cpuset > cgroup.subtree_control 1038 echo "1-7" > cpuset.cpus 1039 echo "1-7" > cpuset.cpus.exclusive 1040 CGROUP_LIST=".. . p1 p2 p1/c11 p1/c12 p2/c21 p2/c22" 1041 RESET_LIST="p1/c11 p1/c12 p2/c21 p2/c22 p1 p2" 1042 I=0 1043 eval CNT="\${#$TEST[@]}" 1044 1045 reset_cgroup_states 1046 console_msg "Running remote partition state transition test ..." 1047 1048 while [[ $I -lt $CNT ]] 1049 do 1050 echo "Running test $I ..." > $CONSOLE 1051 [[ $VERBOSE -gt 1 ]] && { 1052 echo "" 1053 eval echo \${$TEST[$I]} 1054 } 1055 eval set -- "\${$TEST[$I]}" 1056 OLD_p1=$1 1057 OLD_p2=$2 1058 OLD_c11=$3 1059 OLD_c12=$4 1060 OLD_c21=$5 1061 OLD_c22=$6 1062 NEW_p1=$7 1063 NEW_p2=$8 1064 NEW_c11=$9 1065 NEW_c12=${10} 1066 NEW_c21=${11} 1067 NEW_c22=${12} 1068 ECPUS=${13} 1069 STATES=${14} 1070 ICPUS=${15} 1071 1072 set_ctrl_state_noerr p1 $OLD_p1 1073 set_ctrl_state_noerr p2 $OLD_p2 1074 set_ctrl_state_noerr p1/c11 $OLD_c11 1075 set_ctrl_state_noerr p1/c12 $OLD_c12 1076 set_ctrl_state_noerr p2/c21 $OLD_c21 1077 set_ctrl_state_noerr p2/c22 $OLD_c22 1078 1079 RETVAL=0 1080 set_ctrl_state p1 $NEW_p1 ; ((RETVAL += $?)) 1081 set_ctrl_state p2 $NEW_p2 ; ((RETVAL += $?)) 1082 set_ctrl_state p1/c11 $NEW_c11; ((RETVAL += $?)) 1083 set_ctrl_state p1/c12 $NEW_c12; ((RETVAL += $?)) 1084 set_ctrl_state p2/c21 $NEW_c21; ((RETVAL += $?)) 1085 set_ctrl_state p2/c22 $NEW_c22; ((RETVAL += $?)) 1086 1087 [[ $RETVAL -ne 0 ]] && test_fail $I result 1088 1089 check_test_results $I "$ECPUS" "$STATES" "$ICPUS" 1090 ((I++)) 1091 done 1092 cd .. 1093 rmdir rtest 1094 echo "All $I tests of $TEST PASSED." 1095} 1096 1097# 1098# Testing the new "isolated" partition root type 1099# 1100test_isolated() 1101{ 1102 cd $CGROUP2/test 1103 echo 2-3 > cpuset.cpus 1104 TYPE=$(cat cpuset.cpus.partition) 1105 [[ $TYPE = member ]] || echo member > cpuset.cpus.partition 1106 1107 console_msg "Change from member to root" 1108 test_partition root 1109 1110 console_msg "Change from root to isolated" 1111 test_partition isolated 1112 1113 console_msg "Change from isolated to member" 1114 test_partition member 1115 1116 console_msg "Change from member to isolated" 1117 test_partition isolated 1118 1119 console_msg "Change from isolated to root" 1120 test_partition root 1121 1122 console_msg "Change from root to member" 1123 test_partition member 1124 1125 # 1126 # Testing partition root with no cpu 1127 # 1128 console_msg "Distribute all cpus to child partition" 1129 echo +cpuset > cgroup.subtree_control 1130 test_partition root 1131 1132 mkdir A1 1133 cd A1 1134 echo 2-3 > cpuset.cpus 1135 test_partition root 1136 test_effective_cpus 2-3 1137 cd .. 1138 test_effective_cpus "" 1139 1140 console_msg "Moving task to partition test" 1141 test_add_proc "No space left" 1142 cd A1 1143 test_add_proc "" 1144 cd .. 1145 1146 console_msg "Shrink and expand child partition" 1147 cd A1 1148 echo 2 > cpuset.cpus 1149 cd .. 1150 test_effective_cpus 3 1151 cd A1 1152 echo 2-3 > cpuset.cpus 1153 cd .. 1154 test_effective_cpus "" 1155 1156 # Cleaning up 1157 console_msg "Cleaning up" 1158 echo $$ > $CGROUP2/cgroup.procs 1159 [[ -d A1 ]] && rmdir A1 1160 null_isolcpus_check 1161 pause 0.05 1162} 1163 1164# 1165# Wait for inotify event for the given file and read it 1166# $1: cgroup file to wait for 1167# $2: file to store the read result 1168# 1169wait_inotify() 1170{ 1171 CGROUP_FILE=$1 1172 OUTPUT_FILE=$2 1173 1174 $WAIT_INOTIFY $CGROUP_FILE 1175 cat $CGROUP_FILE > $OUTPUT_FILE 1176} 1177 1178# 1179# Test if inotify events are properly generated when going into and out of 1180# invalid partition state. 1181# 1182test_inotify() 1183{ 1184 ERR=0 1185 PRS=/tmp/.prs_$$ 1186 cd $CGROUP2/test 1187 [[ -f $WAIT_INOTIFY ]] || { 1188 echo "wait_inotify not found, inotify test SKIPPED." 1189 return 1190 } 1191 1192 pause 0.01 1193 echo 1 > cpuset.cpus 1194 echo 0 > cgroup.procs 1195 echo root > cpuset.cpus.partition 1196 pause 0.01 1197 rm -f $PRS 1198 wait_inotify $PWD/cpuset.cpus.partition $PRS & 1199 pause 0.01 1200 set_ctrl_state . "O1=0" 1201 pause 0.01 1202 check_cgroup_states ".:P-1" 1203 if [[ $? -ne 0 ]] 1204 then 1205 echo "FAILED: Inotify test - partition not invalid" 1206 ERR=1 1207 elif [[ ! -f $PRS ]] 1208 then 1209 echo "FAILED: Inotify test - event not generated" 1210 ERR=1 1211 kill %1 1212 elif [[ $(cat $PRS) != "root invalid"* ]] 1213 then 1214 echo "FAILED: Inotify test - incorrect state" 1215 cat $PRS 1216 ERR=1 1217 fi 1218 online_cpus 1219 echo member > cpuset.cpus.partition 1220 echo 0 > ../cgroup.procs 1221 if [[ $ERR -ne 0 ]] 1222 then 1223 exit 1 1224 else 1225 echo "Inotify test PASSED" 1226 fi 1227 echo member > cpuset.cpus.partition 1228 echo "" > cpuset.cpus 1229} 1230 1231trap cleanup 0 2 3 6 1232run_state_test TEST_MATRIX 1233run_remote_state_test REMOTE_TEST_MATRIX 1234test_isolated 1235test_inotify 1236echo "All tests PASSED." 1237