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 LASTISOLCPU= 801 SCHED_DOMAINS=/sys/kernel/debug/sched/domains 802 if [[ $EXPECTED_ISOLCPUS = . ]] 803 then 804 EXPECTED_ISOLCPUS= 805 EXPECTED_SDOMAIN= 806 elif [[ $(expr $EXPECTED_ISOLCPUS : ".*|.*") > 0 ]] 807 then 808 set -- $(echo $EXPECTED_ISOLCPUS | sed -e "s/|/ /g") 809 EXPECTED_ISOLCPUS=$2 810 EXPECTED_SDOMAIN=$1 811 else 812 EXPECTED_SDOMAIN=$EXPECTED_ISOLCPUS 813 fi 814 815 # 816 # Appending pre-isolated CPUs 817 # Even though CPU #8 isn't used for testing, it can't be pre-isolated 818 # to make appending those CPUs easier. 819 # 820 [[ -n "$BOOT_ISOLCPUS" ]] && { 821 EXPECTED_ISOLCPUS=${EXPECTED_ISOLCPUS:+${EXPECTED_ISOLCPUS},}${BOOT_ISOLCPUS} 822 EXPECTED_SDOMAIN=${EXPECTED_SDOMAIN:+${EXPECTED_SDOMAIN},}${BOOT_ISOLCPUS} 823 } 824 825 # 826 # Check cpuset.cpus.isolated cpumask 827 # 828 [[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && { 829 # Take a 50ms pause and try again 830 pause 0.05 831 ISOLCPUS=$(cat $ISCPUS) 832 } 833 [[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && return 1 834 ISOLCPUS= 835 EXPECTED_ISOLCPUS=$EXPECTED_SDOMAIN 836 837 # 838 # Use the sched domain in debugfs to check isolated CPUs, if available 839 # 840 [[ -d $SCHED_DOMAINS ]] || return 0 841 842 for ((CPU=0; CPU < $NR_CPUS; CPU++)) 843 do 844 [[ -n "$(ls ${SCHED_DOMAINS}/cpu$CPU)" ]] && continue 845 846 if [[ -z "$LASTISOLCPU" ]] 847 then 848 ISOLCPUS=$CPU 849 LASTISOLCPU=$CPU 850 elif [[ "$LASTISOLCPU" -eq $((CPU - 1)) ]] 851 then 852 echo $ISOLCPUS | grep -q "\<$LASTISOLCPU\$" 853 if [[ $? -eq 0 ]] 854 then 855 ISOLCPUS=${ISOLCPUS}- 856 fi 857 LASTISOLCPU=$CPU 858 else 859 if [[ $ISOLCPUS = *- ]] 860 then 861 ISOLCPUS=${ISOLCPUS}$LASTISOLCPU 862 fi 863 ISOLCPUS=${ISOLCPUS},$CPU 864 LASTISOLCPU=$CPU 865 fi 866 done 867 [[ "$ISOLCPUS" = *- ]] && ISOLCPUS=${ISOLCPUS}$LASTISOLCPU 868 869 [[ "$EXPECTED_SDOMAIN" = "$ISOLCPUS" ]] 870} 871 872test_fail() 873{ 874 TESTNUM=$1 875 TESTTYPE=$2 876 ADDINFO=$3 877 echo "Test $TEST[$TESTNUM] failed $TESTTYPE check!" 878 [[ -n "$ADDINFO" ]] && echo "*** $ADDINFO ***" 879 eval echo \${$TEST[$I]} 880 echo 881 dump_states 882 exit 1 883} 884 885# 886# Check to see if there are unexpected isolated CPUs left beyond the boot 887# time isolated ones. 888# 889null_isolcpus_check() 890{ 891 [[ $VERBOSE -gt 0 ]] || return 0 892 # Retry a few times before printing error 893 RETRY=0 894 while [[ $RETRY -lt 8 ]] 895 do 896 pause 0.02 897 check_isolcpus "." 898 [[ $? -eq 0 ]] && return 0 899 ((RETRY++)) 900 done 901 echo "Unexpected isolated CPUs: $ISOLCPUS" 902 dump_states 903 exit 1 904} 905 906# 907# Check state transition test result 908# $1 - Test number 909# $2 - Expected effective CPU values 910# $3 - Expected partition states 911# $4 - Expected isolated CPUs 912# 913check_test_results() 914{ 915 _NR=$1 916 _ECPUS="$2" 917 _PSTATES="$3" 918 _ISOLCPUS="$4" 919 920 [[ -n "$_ECPUS" && "$_ECPUS" != . ]] && { 921 check_effective_cpus $_ECPUS 922 [[ $? -ne 0 ]] && test_fail $_NR "effective CPU" \ 923 "Cgroup $CGRP: expected $EXPECTED_CPUS, got $ACTUAL_CPUS" 924 } 925 926 [[ -n "$_PSTATES" && "$_PSTATES" != . ]] && { 927 check_cgroup_states $_PSTATES 928 [[ $? -ne 0 ]] && test_fail $_NR states \ 929 "Cgroup $CGRP: expected $EXPECTED_STATE, got $ACTUAL_STATE" 930 } 931 932 # Compare the expected isolated CPUs with the actual ones, 933 # if available 934 [[ -n "$_ISOLCPUS" ]] && { 935 check_isolcpus $_ISOLCPUS 936 [[ $? -ne 0 ]] && { 937 [[ -n "$BOOT_ISOLCPUS" ]] && _ISOLCPUS=${_ISOLCPUS},${BOOT_ISOLCPUS} 938 test_fail $_NR "isolated CPU" \ 939 "Expect $_ISOLCPUS, get $ISOLCPUS instead" 940 } 941 } 942 reset_cgroup_states 943 # 944 # Check to see if effective cpu list changes 945 # 946 _NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective) 947 RETRY=0 948 while [[ $_NEWLIST != $CPULIST && $RETRY -lt 8 ]] 949 do 950 # Wait a bit longer & recheck a few times 951 pause 0.02 952 ((RETRY++)) 953 _NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective) 954 done 955 [[ $_NEWLIST != $CPULIST ]] && { 956 echo "Effective cpus changed to $_NEWLIST after test $_NR!" 957 exit 1 958 } 959 null_isolcpus_check 960 [[ $VERBOSE -gt 0 ]] && echo "Test $I done." 961} 962 963# 964# Run cpuset state transition test 965# $1 - test matrix name 966# 967# This test is somewhat fragile as delays (sleep x) are added in various 968# places to make sure state changes are fully propagated before the next 969# action. These delays may need to be adjusted if running in a slower machine. 970# 971run_state_test() 972{ 973 TEST=$1 974 CGROUP_LIST=". A1 A1/A2 A1/A2/A3 B1" 975 RESET_LIST="A1/A2/A3 A1/A2 A1 B1" 976 I=0 977 eval CNT="\${#$TEST[@]}" 978 979 reset_cgroup_states 980 console_msg "Running state transition test ..." 981 982 while [[ $I -lt $CNT ]] 983 do 984 echo "Running test $I ..." > $CONSOLE 985 [[ $VERBOSE -gt 1 ]] && { 986 echo "" 987 eval echo \${$TEST[$I]} 988 } 989 eval set -- "\${$TEST[$I]}" 990 OLD_A1=$1 991 OLD_A2=$2 992 OLD_A3=$3 993 OLD_B1=$4 994 NEW_A1=$5 995 NEW_A2=$6 996 NEW_A3=$7 997 NEW_B1=$8 998 RESULT=$9 999 ECPUS=${10} 1000 STATES=${11} 1001 ICPUS=${12} 1002 1003 set_ctrl_state_noerr A1 $OLD_A1 1004 set_ctrl_state_noerr A1/A2 $OLD_A2 1005 set_ctrl_state_noerr A1/A2/A3 $OLD_A3 1006 set_ctrl_state_noerr B1 $OLD_B1 1007 1008 RETVAL=0 1009 set_ctrl_state A1 $NEW_A1; ((RETVAL += $?)) 1010 set_ctrl_state A1/A2 $NEW_A2; ((RETVAL += $?)) 1011 set_ctrl_state A1/A2/A3 $NEW_A3; ((RETVAL += $?)) 1012 set_ctrl_state B1 $NEW_B1; ((RETVAL += $?)) 1013 1014 [[ $RETVAL -ne $RESULT ]] && test_fail $I result 1015 1016 check_test_results $I "$ECPUS" "$STATES" "$ICPUS" 1017 ((I++)) 1018 done 1019 echo "All $I tests of $TEST PASSED." 1020} 1021 1022# 1023# Run cpuset remote partition state transition test 1024# $1 - test matrix name 1025# 1026run_remote_state_test() 1027{ 1028 TEST=$1 1029 [[ -d rtest ]] || mkdir rtest 1030 cd rtest 1031 echo +cpuset > cgroup.subtree_control 1032 echo "1-7" > cpuset.cpus 1033 echo "1-7" > cpuset.cpus.exclusive 1034 CGROUP_LIST=".. . p1 p2 p1/c11 p1/c12 p2/c21 p2/c22" 1035 RESET_LIST="p1/c11 p1/c12 p2/c21 p2/c22 p1 p2" 1036 I=0 1037 eval CNT="\${#$TEST[@]}" 1038 1039 reset_cgroup_states 1040 console_msg "Running remote partition state transition test ..." 1041 1042 while [[ $I -lt $CNT ]] 1043 do 1044 echo "Running test $I ..." > $CONSOLE 1045 [[ $VERBOSE -gt 1 ]] && { 1046 echo "" 1047 eval echo \${$TEST[$I]} 1048 } 1049 eval set -- "\${$TEST[$I]}" 1050 OLD_p1=$1 1051 OLD_p2=$2 1052 OLD_c11=$3 1053 OLD_c12=$4 1054 OLD_c21=$5 1055 OLD_c22=$6 1056 NEW_p1=$7 1057 NEW_p2=$8 1058 NEW_c11=$9 1059 NEW_c12=${10} 1060 NEW_c21=${11} 1061 NEW_c22=${12} 1062 ECPUS=${13} 1063 STATES=${14} 1064 ICPUS=${15} 1065 1066 set_ctrl_state_noerr p1 $OLD_p1 1067 set_ctrl_state_noerr p2 $OLD_p2 1068 set_ctrl_state_noerr p1/c11 $OLD_c11 1069 set_ctrl_state_noerr p1/c12 $OLD_c12 1070 set_ctrl_state_noerr p2/c21 $OLD_c21 1071 set_ctrl_state_noerr p2/c22 $OLD_c22 1072 1073 RETVAL=0 1074 set_ctrl_state p1 $NEW_p1 ; ((RETVAL += $?)) 1075 set_ctrl_state p2 $NEW_p2 ; ((RETVAL += $?)) 1076 set_ctrl_state p1/c11 $NEW_c11; ((RETVAL += $?)) 1077 set_ctrl_state p1/c12 $NEW_c12; ((RETVAL += $?)) 1078 set_ctrl_state p2/c21 $NEW_c21; ((RETVAL += $?)) 1079 set_ctrl_state p2/c22 $NEW_c22; ((RETVAL += $?)) 1080 1081 [[ $RETVAL -ne 0 ]] && test_fail $I result 1082 1083 check_test_results $I "$ECPUS" "$STATES" "$ICPUS" 1084 ((I++)) 1085 done 1086 cd .. 1087 rmdir rtest 1088 echo "All $I tests of $TEST PASSED." 1089} 1090 1091# 1092# Testing the new "isolated" partition root type 1093# 1094test_isolated() 1095{ 1096 cd $CGROUP2/test 1097 echo 2-3 > cpuset.cpus 1098 TYPE=$(cat cpuset.cpus.partition) 1099 [[ $TYPE = member ]] || echo member > cpuset.cpus.partition 1100 1101 console_msg "Change from member to root" 1102 test_partition root 1103 1104 console_msg "Change from root to isolated" 1105 test_partition isolated 1106 1107 console_msg "Change from isolated to member" 1108 test_partition member 1109 1110 console_msg "Change from member to isolated" 1111 test_partition isolated 1112 1113 console_msg "Change from isolated to root" 1114 test_partition root 1115 1116 console_msg "Change from root to member" 1117 test_partition member 1118 1119 # 1120 # Testing partition root with no cpu 1121 # 1122 console_msg "Distribute all cpus to child partition" 1123 echo +cpuset > cgroup.subtree_control 1124 test_partition root 1125 1126 mkdir A1 1127 cd A1 1128 echo 2-3 > cpuset.cpus 1129 test_partition root 1130 test_effective_cpus 2-3 1131 cd .. 1132 test_effective_cpus "" 1133 1134 console_msg "Moving task to partition test" 1135 test_add_proc "No space left" 1136 cd A1 1137 test_add_proc "" 1138 cd .. 1139 1140 console_msg "Shrink and expand child partition" 1141 cd A1 1142 echo 2 > cpuset.cpus 1143 cd .. 1144 test_effective_cpus 3 1145 cd A1 1146 echo 2-3 > cpuset.cpus 1147 cd .. 1148 test_effective_cpus "" 1149 1150 # Cleaning up 1151 console_msg "Cleaning up" 1152 echo $$ > $CGROUP2/cgroup.procs 1153 [[ -d A1 ]] && rmdir A1 1154 null_isolcpus_check 1155 pause 0.05 1156} 1157 1158# 1159# Select an online CPU isolated from scheduler domains at boot. 1160# $1: test name used in the skip message 1161# 1162get_boot_isolated_cpu() 1163{ 1164 TEST_NAME=$1 1165 BOOT_ISOLATED_FILE=/sys/devices/system/cpu/isolated 1166 1167 [[ -r $BOOT_ISOLATED_FILE ]] || { 1168 echo "$TEST_NAME test SKIPPED: boot isolation state unavailable" 1169 return 1 1170 } 1171 BOOT_CPUS=$(cat $BOOT_ISOLATED_FILE) 1172 [[ -n "$BOOT_CPUS" ]] || { 1173 echo "$TEST_NAME test SKIPPED: no boot-isolated CPU" 1174 return 1 1175 } 1176 1177 BOOT_CPU=$(echo "$BOOT_CPUS" | sed -e 's/[,-].*//') 1178 CPU_ONLINE=/sys/devices/system/cpu/cpu${BOOT_CPU}/online 1179 [[ ! -e $CPU_ONLINE || $(cat $CPU_ONLINE) -eq 1 ]] || { 1180 echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is offline" 1181 return 1 1182 } 1183} 1184 1185# 1186# A CPU isolated at boot must stay isolated after it is released by a dynamic 1187# isolated partition. 1188# 1189test_boot_isolated() 1190{ 1191 TEST_NAME="Boot-isolated CPU partition release" 1192 get_boot_isolated_cpu "$TEST_NAME" || return 0 1193 echo "Running $TEST_NAME test ..." 1194 1195 cd $CGROUP2/test 1196 echo member > cpuset.cpus.partition 1197 echo $BOOT_CPU > cpuset.cpus 1198 [[ $(cat cpuset.cpus.effective) = "$BOOT_CPU" ]] || { 1199 echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is unavailable" 1200 echo "" > cpuset.cpus 1201 cd $CGROUP2 1202 return 0 1203 } 1204 test_partition isolated 1205 test_partition member 1206 check_isolcpus "." || { 1207 echo "Boot-isolated CPU $BOOT_CPU was lost after partition release" 1208 exit 1 1209 } 1210 echo "" > cpuset.cpus 1211 cd $CGROUP2 1212 echo "$TEST_NAME test PASSED." 1213} 1214 1215# 1216# Wait for inotify event for the given file and read it 1217# $1: cgroup file to wait for 1218# $2: file to store the read result 1219# 1220wait_inotify() 1221{ 1222 CGROUP_FILE=$1 1223 OUTPUT_FILE=$2 1224 1225 $WAIT_INOTIFY $CGROUP_FILE 1226 cat $CGROUP_FILE > $OUTPUT_FILE 1227} 1228 1229# 1230# Test if inotify events are properly generated when going into and out of 1231# invalid partition state. 1232# 1233test_inotify() 1234{ 1235 ERR=0 1236 PRS=/tmp/.prs_$$ 1237 cd $CGROUP2/test 1238 [[ -f $WAIT_INOTIFY ]] || { 1239 echo "wait_inotify not found, inotify test SKIPPED." 1240 return 1241 } 1242 1243 pause 0.01 1244 echo 1 > cpuset.cpus 1245 echo 0 > cgroup.procs 1246 echo root > cpuset.cpus.partition 1247 pause 0.01 1248 rm -f $PRS 1249 wait_inotify $PWD/cpuset.cpus.partition $PRS & 1250 pause 0.01 1251 set_ctrl_state . "O1=0" 1252 pause 0.01 1253 check_cgroup_states ".:P-1" 1254 if [[ $? -ne 0 ]] 1255 then 1256 echo "FAILED: Inotify test - partition not invalid" 1257 ERR=1 1258 elif [[ ! -f $PRS ]] 1259 then 1260 echo "FAILED: Inotify test - event not generated" 1261 ERR=1 1262 kill %1 1263 elif [[ $(cat $PRS) != "root invalid"* ]] 1264 then 1265 echo "FAILED: Inotify test - incorrect state" 1266 cat $PRS 1267 ERR=1 1268 fi 1269 online_cpus 1270 echo member > cpuset.cpus.partition 1271 echo 0 > ../cgroup.procs 1272 if [[ $ERR -ne 0 ]] 1273 then 1274 exit 1 1275 else 1276 echo "Inotify test PASSED" 1277 fi 1278 echo member > cpuset.cpus.partition 1279 echo "" > cpuset.cpus 1280} 1281 1282trap cleanup 0 2 3 6 1283run_state_test TEST_MATRIX 1284run_remote_state_test REMOTE_TEST_MATRIX 1285test_isolated 1286test_boot_isolated 1287test_inotify 1288echo "All tests PASSED." 1289