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 " CX1-3:P1 CX1-3 CX1-3 . . . P1 . 0 A1:1-3|A2:1-3|A3:1-3 \ 302 A1:P1|A2:P0|A3:P-1" 303 304 # Remote partition offline tests 305 " 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" 306 " 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" 307 " 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" 308 " 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|" 309 310 # An invalidated remote partition cannot self-recover from hotplug 311 " 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 ." 312 313 # cpus.exclusive.effective clearing test 314 " C0-3 C1-3 C2 . X2-3:X . . . 0 A1:0-3|A2:1-3|A3:2|XA1:" 315 316 # Invalid to valid remote partition transition test 317 " C0-3 C1-3 . . . X3:P2 . . 0 A1:0-3|A2:1-3|XA2: A2:P-2 ." 318 " C0-3 C1-3:X3:P2 . . X2-3 P2 . . 0 A1:0-2|A2:3|XA2:3 A2:P2 3" 319 320 # Invalid to valid local partition direct transition tests 321 " C1-3:P2 X4:P2 . . . . . . 0 A1:1-3|XA1:1-3|A2:1-3:XA2: A1:P2|A2:P-2 1-3" 322 " C1-3:P2 X4:P2 . . . X3:P2 . . 0 A1:1-2|XA1:1-3|A2:3:XA2:3 A1:P2|A2:P2 1-3" 323 " C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4|B1:5-6 A1:P2|B1:P0" 324 " C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3|B1:4-6 A1:P2|B1:P0 0-3" 325 326 # Local partition invalidation tests 327 " C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \ 328 . . . . . 0 A1:1|A2:2|A3:3 A1:P2|A2:P2|A3:P2 1-3" 329 " C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \ 330 . . X4 . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3" 331 " C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \ 332 . . C4:X . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3" 333 # Local partition CPU change tests 334 " C0-5:P2 C4-5:P1 . . . C3-5 . . 0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2" 335 " C0-5:P2 C4-5:P1 . . C1-5 . . . 0 A1:1-3|A2:4-5 A1:P2|A2:P1 1-3" 336 337 # cpus_allowed/exclusive_cpus update tests 338 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \ 339 . X:C4 . P2 . 0 A1:4|A2:4|XA2:|XA3:|A3:4 \ 340 A1:P0|A3:P-2 ." 341 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \ 342 . X1 . P2 . 0 A1:0-3|A2:1-3|XA1:1|XA2:|XA3:|A3:2-3 \ 343 A1:P0|A3:P-2 ." 344 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \ 345 . . X3 P2 . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3 \ 346 A1:P0|A3:P2 3" 347 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3:P2 \ 348 . . X3 . . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3|XA3:3 \ 349 A1:P0|A3:P2 3" 350 " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3:P2 \ 351 . X4 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:4|XA2:|XA3 \ 352 A1:P0|A3:P-2" 353 354 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS 355 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- 356 # 357 # Incorrect change to cpuset.cpus[.exclusive] invalidates partition root 358 # 359 # Adding CPUs to partition root that are not in parent's 360 # cpuset.cpus is allowed, but those extra CPUs are ignored. 361 " C2-3:P1 C3:P1 . . . C2-4 . . 0 A1:|A2:2-3 A1:P1|A2:P1" 362 363 # Taking away all CPUs from parent or itself if there are tasks 364 # will make the partition invalid. 365 " C2-3:P1 C3:P1 . . T C2-3 . . 0 A1:2-3|A2:2-3 A1:P1|A2:P-1" 366 " C3:P1 C3 . . T P1 . . 0 A1:3|A2:3 A1:P1|A2:P-1" 367 "$SETUP_A123_PARTITIONS . T:C2-3 . . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1" 368 "$SETUP_A123_PARTITIONS . T:C2-3:C1-3 . . . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 369 370 # Changing a partition root to member makes child partitions invalid 371 " C2-3:P1 C3:P1 . . P0 . . . 0 A1:2-3|A2:3 A1:P0|A2:P-1" 372 "$SETUP_A123_PARTITIONS . C2-3 P0 . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P0|A3:P-1" 373 374 # cpuset.cpus can contains cpus not in parent's cpuset.cpus as long 375 # as they overlap. 376 " C2-3:P1 . . . . C3-4:P1 . . 0 A1:2|A2:3 A1:P1|A2:P1" 377 378 # Deletion of CPUs distributed to child cgroup is allowed. 379 " C0-1:P1 C1 . C2-3 C4-5 . . . 0 A1:4-5|A2:4-5" 380 381 # To become a valid partition root, cpuset.cpus must overlap parent's 382 # cpuset.cpus. 383 " C0-1:P1 . . C2-3 . C4-5:P1 . . 0 A1:0-1|A2:0-1 A1:P1|A2:P-1" 384 385 # Enabling partition with child cpusets is allowed 386 " C0-1 C1 . C2-3 P1 . . . 0 A1:0-1|A2:1 A1:P1" 387 388 # A partition root with non-partition root parent is invalid| but it 389 # can be made valid if its parent becomes a partition root too. 390 " C0-1 C1 . C2-3 . P2 . . 0 A1:0-1|A2:1 A1:P0|A2:P-2" 391 " C0-1 C1:P2 . C2-3 P1 . . . 0 A1:0|A2:1 A1:P1|A2:P2 0-1|1" 392 393 # A non-exclusive cpuset.cpus change will not invalidate its siblings partition. 394 " C0-1:P1 . . C2-3 C0-2 . . . 0 A1:0-2|B1:3 A1:P1|B1:P0" 395 " C0-1:P1 . . P1:C2-3 C0-2 . . . 0 A1:0-1|XA1:0-1|B1:2-3 A1:P1|B1:P1" 396 " C0-1 . . P1:C2-3 C0-2 . . . 0 A1:0-1|B1:2-3 A1:P0|B1:P1" 397 398 # cpuset.cpus can overlap with sibling cpuset.cpus.exclusive but not subsumed by it 399 " C0-3 . . C4-5 X5 . . . 0 A1:0-3|B1:4-5" 400 401 # Child partition root that try to take all CPUs from parent partition 402 # with tasks will remain invalid. 403 " C1-4:P1 P1 . . . . . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1" 404 " C1-4:P1 P1 . . . C1-4 . . 0 A1|A2:1-4 A1:P1|A2:P1" 405 " C1-4:P1 P1 . . T C1-4 . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1" 406 407 # Clearing of cpuset.cpus with a preset cpuset.cpus.exclusive shouldn't 408 # affect cpuset.cpus.exclusive.effective. 409 " C1-4:X3 C1:X3 . . . C . . 0 A2:1-4|XA2:3" 410 411 # cpuset.cpus can contain CPUs that overlap a sibling cpuset with cpus.exclusive 412 # but creating a local partition out of it is not allowed. Similarly and change 413 # in cpuset.cpus of a local partition that overlaps sibling exclusive CPUs will 414 # invalidate it. 415 " CX1-4 CX2-4:P2 . C5-6 . . . P1 0 A1:1|A2:2-4|B1:5-6|XB1:5-6 \ 416 A1:P0|A2:P2:B1:P1 2-4" 417 " CX1-4 CX2-4:P2 . C3-6 . . . P1 0 A1:1|A2:2-4|B1:5-6 \ 418 A1:P0|A2:P2:B1:P-1 2-4" 419 " CX1-4 CX2-4:P2 . C5-6 . . . P1:C3-6 0 A1:1|A2:2-4|B1:5-6 \ 420 A1:P0|A2:P2:B1:P-1 2-4" 421 422 # When multiple partitions with conflicting cpuset.cpus are created, the 423 # latter created ones will only get what are left of the available exclusive 424 # CPUs. 425 " C1-3:P1 . . . . . . C3-5:P1 0 A1:1-3|B1:4-5:XB1:4-5 A1:P1|B1:P1" 426 427 # cpuset.cpus can be set to a subset of sibling's cpuset.cpus.exclusive 428 " C1-3:X1-3 . . C4-5 . . . C1-2 0 A1:1-3|B1:1-2" 429 430 # cpuset.cpus can become empty with task in it as it inherits parent's effective CPUs 431 " C1-3 C2 . . . T:C . . 0 A1:1-3|A2:1-3" 432 433 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS 434 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- 435 # Failure cases: 436 437 # A task cannot be added to a partition with no cpu 438 " C2-3:P1 C3:P1 . . O2=0:T . . . 1 A1:|A2:3 A1:P1|A2:P1" 439 440 # Changes to cpuset.cpus.exclusive that violate exclusivity rule is rejected 441 " C0-3 . . C4-5 X0-3 . . X3-5 1 A1:0-3|B1:4-5" 442 443 # cpuset.cpus.exclusive cannot be set to a superset of sibling's cpuset.cpus 444 " C0-3 . . C4-5 X3-5 . . . 1 A1:0-3|B1:4-5" 445) 446 447# 448# Cpuset controller remote partition test matrix. 449# 450# Cgroup test hierarchy 451# 452# root 453# | 454# rtest (cpuset.cpus.exclusive=1-7) 455# | 456# +------+------+ 457# | | 458# p1 p2 459# +--+--+ +--+--+ 460# | | | | 461# c11 c12 c21 c22 462# 463# REMOTE_TEST_MATRIX uses the same notational convention as TEST_MATRIX. 464# Only CPUs 1-7 should be used. 465# 466REMOTE_TEST_MATRIX=( 467 # old-p1 old-p2 old-c11 old-c12 old-c21 old-c22 468 # new-p1 new-p2 new-c11 new-c12 new-c21 new-c22 ECPUs Pstate ISOLCPUS 469 # ------ ------ ------- ------- ------- ------- ----- ------ -------- 470 " X1-3 X4-6 X1-2 X3 X4-5 X6 \ 471 . . P2 P2 P2 P2 c11:1-2|c12:3|c21:4-5|c22:6 \ 472 c11:P2|c12:P2|c21:P2|c22:P2 1-6" 473 " CX1-4 . X1-2:P2 C3 . . \ 474 . . . C3-4 . . p1:3-4|c11:1-2|c12:3-4 \ 475 p1:P0|c11:P2|c12:P0 1-2" 476 " CX1-4 . X1-2:P2 . . . \ 477 X2-4 . . . . . p1:1,3-4|c11:2 \ 478 p1:P0|c11:P2 2" 479 " CX1-5 . X1-2:P2 X3-5:P1 . . \ 480 X2-4 . . . . . p1:1,5|c11:2|c12:3-4 \ 481 p1:P0|c11:P2|c12:P1 2" 482 " CX1-4 . X1-2:P2 X3-4:P1 . . \ 483 . . X2 . . . p1:1|c11:2|c12:3-4 \ 484 p1:P0|c11:P2|c12:P1 2" 485 # p1 as member, will get its effective CPUs from its parent rtest 486 " CX1-4 . X1-2:P2 X3-4:P1 . . \ 487 . . X1 CX2-4 . . p1:5-7|c11:1|c12:2-4 \ 488 p1:P0|c11:P2|c12:P1 1" 489 " CX1-4 X5-6:P1 . . . . \ 490 . . X1-2:P2 X4-5:P1 . X1-7:P2 p1:3|c11:1-2|c12:4:c22:5-6 \ 491 p1:P0|p2:P1|c11:P2|c12:P1|c22:P2 \ 492 1-2,4-6|1-2,5-6" 493 # c12 whose cpuset.cpus CPUs are all granted to c11 will become invalid partition 494 " C1-5:P1 . C1-4:P1 C2-3 . . \ 495 . . . P1 . . p1:5|c11:1-4|c12:5 \ 496 p1:P1|c11:P1|c12:P-1" 497 # Narrowing cpuset.cpus to previously sibling-excluded CPUs should 498 # not return CPUs that were never actually owned. 499 " C1-4:P1 . C1-2:P1 C1-3:P2 . . \ 500 . . . C3 . . p1:4|c11:1-2|c12:3 \ 501 p1:P1|c11:P1|c12:P2 3" 502 # Expanding cpuset.cpus to include a previously sibling-excluded CPU 503 # after the sibling has become a member should correctly request it. 504 " C1-4:P1 . C1-2:P1 C1-3:P2 . . \ 505 . . P0 C2-3 . . p1:1,4|c11:1|c12:2-3 \ 506 p1:P1|c11:P0|c12:P2 2-3" 507 # Changing a sibling partition's cpuset.cpus to overlap with another 508 # sibling partition should invalidate itself and return only actually 509 # allocated CPUs (effective_xcpus) to the parent. 510 " C1-4:P1 . C1-2:P1 C2-4:P2 . . \ 511 . . . C1-2 . . p1:3-4|c11:1-2|c12:3-4 \ 512 p1:P1|c11:P1|c12:P-2" 513 # Cpusets with empty cpuset.cpus should inherit parent's effective_cpus 514 " C1-4:P1 C5-6 C1-2 . C5 . \ 515 . P1 P1 . . . p1:3-4|p2:5-6|c11:1-2|c12:3-4|c21:5|c22:5-6 \ 516 p1:P1|p2:P1|c11:P1" 517 " C1-4:P1 C5-6 C1-2 . C5 . \ 518 . P1 P1 . O5=0 . p1:3-4|p2:6|c11:1-2|c12:3-4|c21:6|c22:6 \ 519 p1:P1|p2:P1|c11:P1" 520) 521 522# 523# Write to the cpu online file 524# $1 - <c>=<v> where <c> = cpu number, <v> value to be written 525# 526write_cpu_online() 527{ 528 CPU=${1%=*} 529 VAL=${1#*=} 530 CPUFILE=//sys/devices/system/cpu/cpu${CPU}/online 531 echo $VAL > $CPUFILE || return 1 532 if [[ $VAL -eq 0 ]] 533 then 534 OFFLINE_CPUS="$OFFLINE_CPUS $CPU" 535 else 536 [[ -n "$OFFLINE_CPUS" ]] && { 537 OFFLINE_CPUS=$(echo $CPU $CPU $OFFLINE_CPUS | fmt -1 |\ 538 sort | uniq -u) 539 } 540 fi 541 pause 0.05 542} 543 544# 545# Set controller state 546# $1 - cgroup directory 547# $2 - state 548# $3 - showerr 549# 550# The presence of ":" in state means transition from one to the next. 551# 552set_ctrl_state() 553{ 554 TMPMSG=/tmp/.msg_$$ 555 CGRP=$1 556 STATE=$2 557 SHOWERR=${3} 558 HASERR=0 559 REDIRECT="2> $TMPMSG" 560 [[ -z "$STATE" || "$STATE" = '.' ]] && return 0 561 [[ $VERBOSE -gt 0 ]] && SHOWERR=1 562 563 rm -f $TMPMSG 564 for CMD in $(echo $STATE | sed -e "s/:/ /g") 565 do 566 TFILE=$CGRP/cgroup.procs 567 PFILE=$CGRP/cpuset.cpus.partition 568 CFILE=$CGRP/cpuset.cpus 569 XFILE=$CGRP/cpuset.cpus.exclusive 570 571 # Enable cpuset controller if not enabled yet 572 [[ -f $CFILE ]] || { 573 COMM="echo +cpuset > $CGRP/../cgroup.subtree_control" 574 eval $COMM $REDIRECT 575 } 576 case $CMD in 577 X*) 578 CPUS=${CMD#?} 579 COMM="echo $CPUS > $XFILE" 580 eval $COMM $REDIRECT 581 ;; 582 CX*) 583 CPUS=${CMD#??} 584 COMM="echo $CPUS > $CFILE; echo $CPUS > $XFILE" 585 eval $COMM $REDIRECT 586 ;; 587 C*) CPUS=${CMD#?} 588 COMM="echo $CPUS > $CFILE" 589 eval $COMM $REDIRECT 590 ;; 591 P*) VAL=${CMD#?} 592 case $VAL in 593 0) VAL=member 594 ;; 595 1) VAL=root 596 ;; 597 2) VAL=isolated 598 ;; 599 *) 600 echo "Invalid partition state - $VAL" 601 exit 1 602 ;; 603 esac 604 COMM="echo $VAL > $PFILE" 605 eval $COMM $REDIRECT 606 ;; 607 O*) VAL=${CMD#?} 608 COMM="write_cpu_online $VAL" 609 eval $COMM $REDIRECT 610 ;; 611 T*) COMM="echo 0 > $TFILE" 612 eval $COMM $REDIRECT 613 ;; 614 *) echo "Unknown command: $CMD" 615 exit 1 616 ;; 617 esac 618 RET=$? 619 [[ $RET -ne 0 ]] && { 620 [[ -n "$SHOWERR" ]] && { 621 echo "$COMM" 622 cat $TMPMSG 623 } 624 HASERR=1 625 } 626 pause 0.01 627 rm -f $TMPMSG 628 done 629 return $HASERR 630} 631 632set_ctrl_state_noerr() 633{ 634 CGRP=$1 635 STATE=$2 636 [[ -d $CGRP ]] || mkdir $CGRP 637 set_ctrl_state $CGRP $STATE 1 638 [[ $? -ne 0 ]] && { 639 echo "ERROR: Failed to set $2 to cgroup $1!" 640 exit 1 641 } 642} 643 644online_cpus() 645{ 646 [[ -n "$OFFLINE_CPUS" ]] && { 647 for C in $OFFLINE_CPUS 648 do 649 write_cpu_online ${C}=1 650 done 651 } 652} 653 654# 655# Remove all the test cgroup directories 656# 657reset_cgroup_states() 658{ 659 echo 0 > $CGROUP2/cgroup.procs 660 online_cpus 661 rmdir $RESET_LIST > /dev/null 2>&1 662} 663 664dump_states() 665{ 666 for DIR in $CGROUP_LIST 667 do 668 CPUS=$DIR/cpuset.cpus 669 ECPUS=$DIR/cpuset.cpus.effective 670 XCPUS=$DIR/cpuset.cpus.exclusive 671 XECPUS=$DIR/cpuset.cpus.exclusive.effective 672 PRS=$DIR/cpuset.cpus.partition 673 PCPUS=$DIR/.__DEBUG__.cpuset.cpus.subpartitions 674 ISCPUS=$DIR/cpuset.cpus.isolated 675 [[ -e $CPUS ]] && echo "$CPUS: $(cat $CPUS)" 676 [[ -e $XCPUS ]] && echo "$XCPUS: $(cat $XCPUS)" 677 [[ -e $ECPUS ]] && echo "$ECPUS: $(cat $ECPUS)" 678 [[ -e $XECPUS ]] && echo "$XECPUS: $(cat $XECPUS)" 679 [[ -e $PRS ]] && echo "$PRS: $(cat $PRS)" 680 [[ -e $PCPUS ]] && echo "$PCPUS: $(cat $PCPUS)" 681 [[ -e $ISCPUS ]] && echo "$ISCPUS: $(cat $ISCPUS)" 682 done 683} 684 685# 686# Set the actual cgroup directory into $CGRP_DIR 687# $1 - cgroup name 688# 689set_cgroup_dir() 690{ 691 CGRP_DIR=$1 692 [[ $CGRP_DIR = A2 ]] && CGRP_DIR=A1/A2 693 [[ $CGRP_DIR = A3 ]] && CGRP_DIR=A1/A2/A3 694 [[ $CGRP_DIR = c11 ]] && CGRP_DIR=p1/c11 695 [[ $CGRP_DIR = c12 ]] && CGRP_DIR=p1/c12 696 [[ $CGRP_DIR = c21 ]] && CGRP_DIR=p2/c21 697 [[ $CGRP_DIR = c22 ]] && CGRP_DIR=p2/c22 698} 699 700# 701# Check effective cpus 702# $1 - check string, format: <cgroup>:<cpu-list>[|<cgroup>:<cpu-list>]* 703# 704check_effective_cpus() 705{ 706 CHK_STR=$1 707 for CHK in $(echo $CHK_STR | sed -e "s/|/ /g") 708 do 709 set -- $(echo $CHK | sed -e "s/:/ /g") 710 CGRP=$1 711 EXPECTED_CPUS=$2 712 ACTUAL_CPUS= 713 if [[ $CGRP = X* ]] 714 then 715 CGRP=${CGRP#X} 716 FILE=cpuset.cpus.exclusive.effective 717 else 718 FILE=cpuset.cpus.effective 719 fi 720 set_cgroup_dir $CGRP 721 [[ -e $CGRP_DIR/$FILE ]] || return 1 722 ACTUAL_CPUS=$(cat $CGRP_DIR/$FILE) 723 [[ $EXPECTED_CPUS = $ACTUAL_CPUS ]] || return 1 724 done 725} 726 727# 728# Check cgroup states 729# $1 - check string, format: <cgroup>:<state>[|<cgroup>:<state>]* 730# 731check_cgroup_states() 732{ 733 CHK_STR=$1 734 for CHK in $(echo $CHK_STR | sed -e "s/|/ /g") 735 do 736 set -- $(echo $CHK | sed -e "s/:/ /g") 737 CGRP=$1 738 EXPECTED_STATE=$2 739 FILE= 740 EVAL=$(expr substr $EXPECTED_STATE 2 2) 741 742 set_cgroup_dir $CGRP 743 case $EXPECTED_STATE in 744 P*) FILE=$CGRP_DIR/cpuset.cpus.partition 745 ;; 746 *) echo "Unknown state: $EXPECTED_STATE!" 747 exit 1 748 ;; 749 esac 750 ACTUAL_STATE=$(cat $FILE) 751 752 case "$ACTUAL_STATE" in 753 member) VAL=0 754 ;; 755 root) VAL=1 756 ;; 757 isolated) 758 VAL=2 759 ;; 760 "root invalid"*) 761 VAL=-1 762 ;; 763 "isolated invalid"*) 764 VAL=-2 765 ;; 766 esac 767 [[ $EVAL != $VAL ]] && return 1 768 769 # 770 # For root partition, dump sched-domains info to console if 771 # verbose mode set for manual comparison with sched debug info. 772 # 773 [[ $VAL -eq 1 && $VERBOSE -gt 0 ]] && { 774 DOMS=$(cat $CGRP_DIR/cpuset.cpus.effective) 775 [[ -n "$DOMS" ]] && 776 echo " [$CGRP_DIR] sched-domain: $DOMS" > $CONSOLE 777 } 778 done 779 return 0 780} 781 782# 783# Get isolated (including offline) CPUs by looking at 784# /sys/kernel/debug/sched/domains and cpuset.cpus.isolated control file, 785# if available, and compare that with the expected value. 786# 787# Note that isolated CPUs from the sched/domains context include offline 788# CPUs as well as CPUs in non-isolated 1-CPU partition. Those CPUs may 789# not be included in the cpuset.cpus.isolated control file which contains 790# only CPUs in isolated partitions as well as those that are isolated at 791# boot time. 792# 793# $1 - expected isolated cpu list(s) <isolcpus1>{|<isolcpus2>} 794# <isolcpus1> - expected sched/domains value 795# <isolcpus2> - cpuset.cpus.isolated value = <isolcpus1> if not defined 796# 797check_isolcpus() 798{ 799 EXPECTED_ISOLCPUS=$1 800 ISCPUS=${CGROUP2}/cpuset.cpus.isolated 801 ISOLCPUS=$(cat $ISCPUS) 802 LASTISOLCPU= 803 SCHED_DOMAINS=/sys/kernel/debug/sched/domains 804 if [[ $EXPECTED_ISOLCPUS = . ]] 805 then 806 EXPECTED_ISOLCPUS= 807 EXPECTED_SDOMAIN= 808 elif [[ $(expr $EXPECTED_ISOLCPUS : ".*|.*") > 0 ]] 809 then 810 set -- $(echo $EXPECTED_ISOLCPUS | sed -e "s/|/ /g") 811 EXPECTED_ISOLCPUS=$2 812 EXPECTED_SDOMAIN=$1 813 else 814 EXPECTED_SDOMAIN=$EXPECTED_ISOLCPUS 815 fi 816 817 # 818 # Appending pre-isolated CPUs 819 # Even though CPU #8 isn't used for testing, it can't be pre-isolated 820 # to make appending those CPUs easier. 821 # 822 [[ -n "$BOOT_ISOLCPUS" ]] && { 823 EXPECTED_ISOLCPUS=${EXPECTED_ISOLCPUS:+${EXPECTED_ISOLCPUS},}${BOOT_ISOLCPUS} 824 EXPECTED_SDOMAIN=${EXPECTED_SDOMAIN:+${EXPECTED_SDOMAIN},}${BOOT_ISOLCPUS} 825 } 826 827 # 828 # Check cpuset.cpus.isolated cpumask 829 # 830 [[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && { 831 # Take a 50ms pause and try again 832 pause 0.05 833 ISOLCPUS=$(cat $ISCPUS) 834 } 835 [[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && return 1 836 ISOLCPUS= 837 EXPECTED_ISOLCPUS=$EXPECTED_SDOMAIN 838 839 # 840 # Use the sched domain in debugfs to check isolated CPUs, if available 841 # 842 [[ -d $SCHED_DOMAINS ]] || return 0 843 844 for ((CPU=0; CPU < $NR_CPUS; CPU++)) 845 do 846 [[ -n "$(ls ${SCHED_DOMAINS}/cpu$CPU)" ]] && continue 847 848 if [[ -z "$LASTISOLCPU" ]] 849 then 850 ISOLCPUS=$CPU 851 LASTISOLCPU=$CPU 852 elif [[ "$LASTISOLCPU" -eq $((CPU - 1)) ]] 853 then 854 echo $ISOLCPUS | grep -q "\<$LASTISOLCPU\$" 855 if [[ $? -eq 0 ]] 856 then 857 ISOLCPUS=${ISOLCPUS}- 858 fi 859 LASTISOLCPU=$CPU 860 else 861 if [[ $ISOLCPUS = *- ]] 862 then 863 ISOLCPUS=${ISOLCPUS}$LASTISOLCPU 864 fi 865 ISOLCPUS=${ISOLCPUS},$CPU 866 LASTISOLCPU=$CPU 867 fi 868 done 869 [[ "$ISOLCPUS" = *- ]] && ISOLCPUS=${ISOLCPUS}$LASTISOLCPU 870 871 [[ "$EXPECTED_SDOMAIN" = "$ISOLCPUS" ]] 872} 873 874test_fail() 875{ 876 TESTNUM=$1 877 TESTTYPE=$2 878 ADDINFO=$3 879 echo "Test $TEST[$TESTNUM] failed $TESTTYPE check!" 880 [[ -n "$ADDINFO" ]] && echo "*** $ADDINFO ***" 881 eval echo \${$TEST[$I]} 882 echo 883 dump_states 884 exit 1 885} 886 887# 888# Check to see if there are unexpected isolated CPUs left beyond the boot 889# time isolated ones. 890# 891null_isolcpus_check() 892{ 893 [[ $VERBOSE -gt 0 ]] || return 0 894 # Retry a few times before printing error 895 RETRY=0 896 while [[ $RETRY -lt 8 ]] 897 do 898 pause 0.02 899 check_isolcpus "." 900 [[ $? -eq 0 ]] && return 0 901 ((RETRY++)) 902 done 903 echo "Unexpected isolated CPUs: $ISOLCPUS" 904 dump_states 905 exit 1 906} 907 908# 909# Check state transition test result 910# $1 - Test number 911# $2 - Expected effective CPU values 912# $3 - Expected partition states 913# $4 - Expected isolated CPUs 914# 915check_test_results() 916{ 917 _NR=$1 918 _ECPUS="$2" 919 _PSTATES="$3" 920 _ISOLCPUS="$4" 921 922 [[ -n "$_ECPUS" && "$_ECPUS" != . ]] && { 923 check_effective_cpus $_ECPUS 924 [[ $? -ne 0 ]] && test_fail $_NR "effective CPU" \ 925 "Cgroup $CGRP: expected $EXPECTED_CPUS, got $ACTUAL_CPUS" 926 } 927 928 [[ -n "$_PSTATES" && "$_PSTATES" != . ]] && { 929 check_cgroup_states $_PSTATES 930 [[ $? -ne 0 ]] && test_fail $_NR states \ 931 "Cgroup $CGRP: expected $EXPECTED_STATE, got $ACTUAL_STATE" 932 } 933 934 # Compare the expected isolated CPUs with the actual ones, 935 # if available 936 [[ -n "$_ISOLCPUS" ]] && { 937 check_isolcpus $_ISOLCPUS 938 [[ $? -ne 0 ]] && { 939 [[ -n "$BOOT_ISOLCPUS" ]] && _ISOLCPUS=${_ISOLCPUS},${BOOT_ISOLCPUS} 940 test_fail $_NR "isolated CPU" \ 941 "Expect $_ISOLCPUS, get $ISOLCPUS instead" 942 } 943 } 944 reset_cgroup_states 945 # 946 # Check to see if effective cpu list changes 947 # 948 _NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective) 949 RETRY=0 950 while [[ $_NEWLIST != $CPULIST && $RETRY -lt 8 ]] 951 do 952 # Wait a bit longer & recheck a few times 953 pause 0.02 954 ((RETRY++)) 955 _NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective) 956 done 957 [[ $_NEWLIST != $CPULIST ]] && { 958 echo "Effective cpus changed to $_NEWLIST after test $_NR!" 959 exit 1 960 } 961 null_isolcpus_check 962 [[ $VERBOSE -gt 0 ]] && echo "Test $I done." 963} 964 965# 966# Run cpuset state transition test 967# $1 - test matrix name 968# 969# This test is somewhat fragile as delays (sleep x) are added in various 970# places to make sure state changes are fully propagated before the next 971# action. These delays may need to be adjusted if running in a slower machine. 972# 973run_state_test() 974{ 975 TEST=$1 976 CGROUP_LIST=". A1 A1/A2 A1/A2/A3 B1" 977 RESET_LIST="A1/A2/A3 A1/A2 A1 B1" 978 I=0 979 eval CNT="\${#$TEST[@]}" 980 981 reset_cgroup_states 982 console_msg "Running state transition test ..." 983 984 while [[ $I -lt $CNT ]] 985 do 986 echo "Running test $I ..." > $CONSOLE 987 [[ $VERBOSE -gt 1 ]] && { 988 echo "" 989 eval echo \${$TEST[$I]} 990 } 991 eval set -- "\${$TEST[$I]}" 992 OLD_A1=$1 993 OLD_A2=$2 994 OLD_A3=$3 995 OLD_B1=$4 996 NEW_A1=$5 997 NEW_A2=$6 998 NEW_A3=$7 999 NEW_B1=$8 1000 RESULT=$9 1001 ECPUS=${10} 1002 STATES=${11} 1003 ICPUS=${12} 1004 1005 set_ctrl_state_noerr A1 $OLD_A1 1006 set_ctrl_state_noerr A1/A2 $OLD_A2 1007 set_ctrl_state_noerr A1/A2/A3 $OLD_A3 1008 set_ctrl_state_noerr B1 $OLD_B1 1009 1010 RETVAL=0 1011 set_ctrl_state A1 $NEW_A1; ((RETVAL += $?)) 1012 set_ctrl_state A1/A2 $NEW_A2; ((RETVAL += $?)) 1013 set_ctrl_state A1/A2/A3 $NEW_A3; ((RETVAL += $?)) 1014 set_ctrl_state B1 $NEW_B1; ((RETVAL += $?)) 1015 1016 [[ $RETVAL -ne $RESULT ]] && test_fail $I result 1017 1018 check_test_results $I "$ECPUS" "$STATES" "$ICPUS" 1019 ((I++)) 1020 done 1021 echo "All $I tests of $TEST PASSED." 1022} 1023 1024# 1025# Run cpuset remote partition state transition test 1026# $1 - test matrix name 1027# 1028run_remote_state_test() 1029{ 1030 TEST=$1 1031 [[ -d rtest ]] || mkdir rtest 1032 cd rtest 1033 echo +cpuset > cgroup.subtree_control 1034 echo "1-7" > cpuset.cpus 1035 echo "1-7" > cpuset.cpus.exclusive 1036 CGROUP_LIST=".. . p1 p2 p1/c11 p1/c12 p2/c21 p2/c22" 1037 RESET_LIST="p1/c11 p1/c12 p2/c21 p2/c22 p1 p2" 1038 I=0 1039 eval CNT="\${#$TEST[@]}" 1040 1041 reset_cgroup_states 1042 console_msg "Running remote partition state transition test ..." 1043 1044 while [[ $I -lt $CNT ]] 1045 do 1046 echo "Running test $I ..." > $CONSOLE 1047 [[ $VERBOSE -gt 1 ]] && { 1048 echo "" 1049 eval echo \${$TEST[$I]} 1050 } 1051 eval set -- "\${$TEST[$I]}" 1052 OLD_p1=$1 1053 OLD_p2=$2 1054 OLD_c11=$3 1055 OLD_c12=$4 1056 OLD_c21=$5 1057 OLD_c22=$6 1058 NEW_p1=$7 1059 NEW_p2=$8 1060 NEW_c11=$9 1061 NEW_c12=${10} 1062 NEW_c21=${11} 1063 NEW_c22=${12} 1064 ECPUS=${13} 1065 STATES=${14} 1066 ICPUS=${15} 1067 1068 set_ctrl_state_noerr p1 $OLD_p1 1069 set_ctrl_state_noerr p2 $OLD_p2 1070 set_ctrl_state_noerr p1/c11 $OLD_c11 1071 set_ctrl_state_noerr p1/c12 $OLD_c12 1072 set_ctrl_state_noerr p2/c21 $OLD_c21 1073 set_ctrl_state_noerr p2/c22 $OLD_c22 1074 1075 RETVAL=0 1076 set_ctrl_state p1 $NEW_p1 ; ((RETVAL += $?)) 1077 set_ctrl_state p2 $NEW_p2 ; ((RETVAL += $?)) 1078 set_ctrl_state p1/c11 $NEW_c11; ((RETVAL += $?)) 1079 set_ctrl_state p1/c12 $NEW_c12; ((RETVAL += $?)) 1080 set_ctrl_state p2/c21 $NEW_c21; ((RETVAL += $?)) 1081 set_ctrl_state p2/c22 $NEW_c22; ((RETVAL += $?)) 1082 1083 [[ $RETVAL -ne 0 ]] && test_fail $I result 1084 1085 check_test_results $I "$ECPUS" "$STATES" "$ICPUS" 1086 ((I++)) 1087 done 1088 cd .. 1089 rmdir rtest 1090 echo "All $I tests of $TEST PASSED." 1091} 1092 1093# 1094# Testing the new "isolated" partition root type 1095# 1096test_isolated() 1097{ 1098 cd $CGROUP2/test 1099 echo 2-3 > cpuset.cpus 1100 TYPE=$(cat cpuset.cpus.partition) 1101 [[ $TYPE = member ]] || echo member > cpuset.cpus.partition 1102 1103 console_msg "Change from member to root" 1104 test_partition root 1105 1106 console_msg "Change from root to isolated" 1107 test_partition isolated 1108 1109 console_msg "Change from isolated to member" 1110 test_partition member 1111 1112 console_msg "Change from member to isolated" 1113 test_partition isolated 1114 1115 console_msg "Change from isolated to root" 1116 test_partition root 1117 1118 console_msg "Change from root to member" 1119 test_partition member 1120 1121 # 1122 # Testing partition root with no cpu 1123 # 1124 console_msg "Distribute all cpus to child partition" 1125 echo +cpuset > cgroup.subtree_control 1126 test_partition root 1127 1128 mkdir A1 1129 cd A1 1130 echo 2-3 > cpuset.cpus 1131 test_partition root 1132 test_effective_cpus 2-3 1133 cd .. 1134 test_effective_cpus "" 1135 1136 console_msg "Moving task to partition test" 1137 test_add_proc "No space left" 1138 cd A1 1139 test_add_proc "" 1140 cd .. 1141 1142 console_msg "Shrink and expand child partition" 1143 cd A1 1144 echo 2 > cpuset.cpus 1145 cd .. 1146 test_effective_cpus 3 1147 cd A1 1148 echo 2-3 > cpuset.cpus 1149 cd .. 1150 test_effective_cpus "" 1151 1152 # Cleaning up 1153 console_msg "Cleaning up" 1154 echo $$ > $CGROUP2/cgroup.procs 1155 [[ -d A1 ]] && rmdir A1 1156 null_isolcpus_check 1157 pause 0.05 1158} 1159 1160# 1161# Select an online CPU isolated from scheduler domains at boot. 1162# $1: test name used in the skip message 1163# 1164get_boot_isolated_cpu() 1165{ 1166 TEST_NAME=$1 1167 BOOT_ISOLATED_FILE=/sys/devices/system/cpu/isolated 1168 1169 [[ -r $BOOT_ISOLATED_FILE ]] || { 1170 echo "$TEST_NAME test SKIPPED: boot isolation state unavailable" 1171 return 1 1172 } 1173 BOOT_CPUS=$(cat $BOOT_ISOLATED_FILE) 1174 [[ -n "$BOOT_CPUS" ]] || { 1175 echo "$TEST_NAME test SKIPPED: no boot-isolated CPU" 1176 return 1 1177 } 1178 1179 BOOT_CPU=$(echo "$BOOT_CPUS" | sed -e 's/[,-].*//') 1180 CPU_ONLINE=/sys/devices/system/cpu/cpu${BOOT_CPU}/online 1181 [[ ! -e $CPU_ONLINE || $(cat $CPU_ONLINE) -eq 1 ]] || { 1182 echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is offline" 1183 return 1 1184 } 1185} 1186 1187# 1188# A CPU isolated at boot must stay isolated after it is released by a dynamic 1189# isolated partition. 1190# 1191test_boot_isolated() 1192{ 1193 TEST_NAME="Boot-isolated CPU partition release" 1194 get_boot_isolated_cpu "$TEST_NAME" || return 0 1195 echo "Running $TEST_NAME test ..." 1196 1197 cd $CGROUP2/test 1198 echo member > cpuset.cpus.partition 1199 echo $BOOT_CPU > cpuset.cpus 1200 [[ $(cat cpuset.cpus.effective) = "$BOOT_CPU" ]] || { 1201 echo "$TEST_NAME test SKIPPED: CPU $BOOT_CPU is unavailable" 1202 echo "" > cpuset.cpus 1203 cd $CGROUP2 1204 return 0 1205 } 1206 test_partition isolated 1207 test_partition member 1208 check_isolcpus "." || { 1209 echo "Boot-isolated CPU $BOOT_CPU was lost after partition release" 1210 exit 1 1211 } 1212 echo "" > cpuset.cpus 1213 cd $CGROUP2 1214 echo "$TEST_NAME test PASSED." 1215} 1216 1217# 1218# Wait for inotify event for the given file and read it 1219# $1: cgroup file to wait for 1220# $2: file to store the read result 1221# 1222wait_inotify() 1223{ 1224 CGROUP_FILE=$1 1225 OUTPUT_FILE=$2 1226 1227 $WAIT_INOTIFY $CGROUP_FILE 1228 cat $CGROUP_FILE > $OUTPUT_FILE 1229} 1230 1231# 1232# Test if inotify events are properly generated when going into and out of 1233# invalid partition state. 1234# 1235test_inotify() 1236{ 1237 ERR=0 1238 PRS=/tmp/.prs_$$ 1239 cd $CGROUP2/test 1240 [[ -f $WAIT_INOTIFY ]] || { 1241 echo "wait_inotify not found, inotify test SKIPPED." 1242 return 1243 } 1244 1245 pause 0.01 1246 echo 1 > cpuset.cpus 1247 echo 0 > cgroup.procs 1248 echo root > cpuset.cpus.partition 1249 pause 0.01 1250 rm -f $PRS 1251 wait_inotify $PWD/cpuset.cpus.partition $PRS & 1252 pause 0.01 1253 set_ctrl_state . "O1=0" 1254 pause 0.01 1255 check_cgroup_states ".:P-1" 1256 if [[ $? -ne 0 ]] 1257 then 1258 echo "FAILED: Inotify test - partition not invalid" 1259 ERR=1 1260 elif [[ ! -f $PRS ]] 1261 then 1262 echo "FAILED: Inotify test - event not generated" 1263 ERR=1 1264 kill %1 1265 elif [[ $(cat $PRS) != "root invalid"* ]] 1266 then 1267 echo "FAILED: Inotify test - incorrect state" 1268 cat $PRS 1269 ERR=1 1270 fi 1271 online_cpus 1272 echo member > cpuset.cpus.partition 1273 echo 0 > ../cgroup.procs 1274 if [[ $ERR -ne 0 ]] 1275 then 1276 exit 1 1277 else 1278 echo "Inotify test PASSED" 1279 fi 1280 echo member > cpuset.cpus.partition 1281 echo "" > cpuset.cpus 1282} 1283 1284trap cleanup 0 2 3 6 1285run_state_test TEST_MATRIX 1286run_remote_state_test REMOTE_TEST_MATRIX 1287test_isolated 1288test_boot_isolated 1289test_inotify 1290echo "All tests PASSED." 1291