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 -e '{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# S<p> = use prefix in subtree_control 200# T = put a task into cgroup 201# CX<l> = add cpu-list to both cpuset.cpus and cpuset.cpus.exclusive 202# O<c>=<v> = Write <v> to CPU online file of <c> 203# 204# ECPUs - effective CPUs of cpusets 205# Pstate - partition root state 206# ISOLCPUS - isolated CPUs (<icpus>[,<icpus2>]) 207# 208# Note that if there are 2 fields in ISOLCPUS, the first one is for 209# sched-debug matching which includes offline CPUs and single-CPU partitions 210# while the second one is for matching cpuset.cpus.isolated. 211# 212SETUP_A123_PARTITIONS="C1-3:P1:S+ C2-3:P1:S+ C3:P1" 213TEST_MATRIX=( 214 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS 215 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- 216 " C0-1 . . C2-3 S+ C4-5 . . 0 A2:0-1" 217 " C0-1 . . C2-3 P1 . . . 0 " 218 " C0-1 . . C2-3 P1:S+ C0-1:P1 . . 0 " 219 " C0-1 . . C2-3 P1:S+ C1:P1 . . 0 " 220 " C0-1:S+ . . C2-3 . . . P1 0 " 221 " C0-1:P1 . . C2-3 S+ C1 . . 0 " 222 " C0-1:P1 . . C2-3 S+ C1:P1 . . 0 " 223 " C0-1:P1 . . C2-3 S+ C1:P1 . P1 0 " 224 " C0-1:P1 . . C2-3 C4-5 . . . 0 A1:4-5" 225 " C0-1:P1 . . C2-3 S+:C4-5 . . . 0 A1:4-5" 226 " C0-1 . . C2-3:P1 . . . C2 0 " 227 " C0-1 . . C2-3:P1 . . . C4-5 0 B1:4-5" 228 "C0-3:P1:S+ C2-3:P1 . . . . . . 0 A1:0-1|A2:2-3|XA2:2-3" 229 "C0-3:P1:S+ C2-3:P1 . . C1-3 . . . 0 A1:1|A2:2-3|XA2:2-3" 230 "C2-3:P1:S+ C3:P1 . . C3 . . . 0 A1:|A2:3|XA2:3 A1:P1|A2:P1" 231 "C2-3:P1:S+ C3:P1 . . C3 P0 . . 0 A1:3|A2:3 A1:P1|A2:P0" 232 "C2-3:P1:S+ C2:P1 . . C2-4 . . . 0 A1:3-4|A2:2" 233 "C2-3:P1:S+ C3:P1 . . C3 . . C0-2 0 A1:|B1:0-2 A1:P1|A2:P1" 234 "$SETUP_A123_PARTITIONS . C2-3 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 235 236 # CPU offlining cases: 237 " C0-1 . . C2-3 S+ C4-5 . O2=0 0 A1:0-1|B1:3" 238 "C0-3:P1:S+ C2-3:P1 . . O2=0 . . . 0 A1:0-1|A2:3" 239 "C0-3:P1:S+ C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1|A2:2-3" 240 "C0-3:P1:S+ C2-3:P1 . . O1=0 . . . 0 A1:0|A2:2-3" 241 "C0-3:P1:S+ C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1|A2:2-3" 242 "C2-3:P1:S+ C3:P1 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P1" 243 "C2-3:P1:S+ C3:P2 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P2" 244 "C2-3:P1:S+ C3:P1 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P1" 245 "C2-3:P1:S+ C3:P2 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P2" 246 "C2-3:P1:S+ C3:P1 . . O2=0 . . . 0 A1:|A2:3 A1:P1|A2:P1" 247 "C2-3:P1:S+ C3:P1 . . O3=0 . . . 0 A1:2|A2: A1:P1|A2:P1" 248 "C2-3:P1:S+ C3:P1 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-1" 249 "C2-3:P1:S+ C3:P1 . . . T:O3=0 . . 0 A1:2|A2:2 A1:P1|A2:P-1" 250 "$SETUP_A123_PARTITIONS . O1=0 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 251 "$SETUP_A123_PARTITIONS . O2=0 . . . 0 A1:1|A2:|A3:3 A1:P1|A2:P1|A3:P1" 252 "$SETUP_A123_PARTITIONS . O3=0 . . . 0 A1:1|A2:2|A3: A1:P1|A2:P1|A3:P1" 253 "$SETUP_A123_PARTITIONS . T:O1=0 . . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1" 254 "$SETUP_A123_PARTITIONS . . T:O2=0 . . 0 A1:1|A2:3|A3:3 A1:P1|A2:P1|A3:P-1" 255 "$SETUP_A123_PARTITIONS . . . T:O3=0 . 0 A1:1|A2:2|A3:2 A1:P1|A2:P1|A3:P-1" 256 "$SETUP_A123_PARTITIONS . T:O1=0 O1=1 . . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 257 "$SETUP_A123_PARTITIONS . . T:O2=0 O2=1 . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 258 "$SETUP_A123_PARTITIONS . . . T:O3=0 O3=1 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1" 259 "$SETUP_A123_PARTITIONS . T:O1=0 O2=0 O1=1 . 0 A1:1|A2:|A3:3 A1:P1|A2:P1|A3:P1" 260 "$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" 261 262 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS 263 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ -------- 264 # 265 # Remote partition and cpuset.cpus.exclusive tests 266 # 267 " C0-3:S+ C1-3:S+ C2-3 . X2-3 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:2-3" 268 " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3:P2 . . 0 A1:0-1|A2:2-3|A3:2-3 A1:P0|A2:P2 2-3" 269 " C0-3:S+ C1-3:S+ C2-3 . X2-3 X3:P2 . . 0 A1:0-2|A2:3|A3:3 A1:P0|A2:P2 3" 270 " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3" 271 " C0-3:S+ C1-3:S+ 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" 272 " C0-3:S+ C1-3:S+ C2-3 C2-3 . . . P2 0 A1:0-1|A2:1|A3:1|B1:2-3 A1:P0|A3:P0|B1:P2" 273 " C0-3:S+ C1-3:S+ C2-3 C4-5 . . . P2 0 B1:4-5 B1:P2 4-5" 274 " C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4" 275 " C0-3:S+ C1-3:S+ 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" 276 " C0-3:S+ C1-3:S+ C2-3 C4 X1-3 X1-3:P2 P2 . 0 A2:1|A3:2-3 A2:P2|A3:P2 1-3" 277 " C0-3:S+ C1-3:S+ 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" 278 " C4:X0-3:S+ X1-3:S+ X2-3 . . P2 . . 0 A1:4|A2:1-3|A3:1-3 A2:P2 1-3" 279 " C4:X0-3:S+ X1-3:S+ X2-3 . . . P2 . 0 A1:4|A2:4|A3:2-3 A3:P2 2-3" 280 281 # Nested remote/local partition tests 282 " C0-3:S+ C1-3:S+ C2-3 C4-5 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4-5 \ 283 A1:P0|A2:P1|A3:P2|B1:P1 2-3" 284 " C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4 \ 285 A1:P0|A2:P1|A3:P2|B1:P1 2-4|2-3" 286 " C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 . P1 0 A1:0-1|A2:2-3|A3:2-3|B1:4 \ 287 A1:P0|A2:P1|A3:P0|B1:P1" 288 " C0-3:S+ C1-3:S+ C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:2|A3:3|B1:4 \ 289 A1:P0|A2:P1|A3:P2|B1:P1 2-4|3" 290 " C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1|A2:2-3|A3:4 \ 291 A1:P0|A2:P2|A3:P1 2-4|2-3" 292 " C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1|A2:2|A3:3-4 \ 293 A1:P0|A2:P2|A3:P1 2" 294 " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \ 295 . . X5 . . 0 A1:0-4|A2:1-4|A3:2-4 \ 296 A1:P0|A2:P-2|A3:P-1 ." 297 " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \ 298 . . . X1 . 0 A1:0-1|A2:2-4|A3:2-4 \ 299 A1:P0|A2:P2|A3:P-1 2-4" 300 301 # Remote partition offline tests 302 " C0-3:S+ C1-3:S+ 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" 303 " C0-3:S+ C1-3:S+ 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" 304 " C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 P2:O3=0 . 0 A1:0-2|A2:1-2|A3: A1:P0|A3:P2 3" 305 " C0-3:S+ C1-3:S+ 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|" 306 307 # An invalidated remote partition cannot self-recover from hotplug 308 " C0-3:S+ C1-3:S+ 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 ." 309 310 # cpus.exclusive.effective clearing test 311 " C0-3:S+ C1-3:S+ C2 . X2-3:X . . . 0 A1:0-3|A2:1-3|A3:2|XA1:" 312 313 # Invalid to valid remote partition transition test 314 " C0-3:S+ C1-3 . . . X3:P2 . . 0 A1:0-3|A2:1-3|XA2: A2:P-2 ." 315 " C0-3:S+ C1-3:X3:P2 316 . . 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:S+:P2 X4:P2 . . . . . . 0 A1:1-3|XA1:1-3|A2:1-3:XA2: A1:P2|A2:P-2 1-3" 320 " C1-3:S+: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:S+:P2 C1-3:X2-3:S+: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:S+:P2 C1-3:X2-3:S+: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:S+:P2 C1-3:X2-3:S+: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:S+:P2 C4-5:S+:P1 . . . C3-5 . . 0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2" 333 " C0-5:S+:P2 C4-5:S+: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:S+ C1-3:X2-3:S+ 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:S+ C1-3:X2-3:S+ 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:S+ C1-3:X2-3:S+ 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:S+ C1-3:X2-3:S+ 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:S+ C1-3:X2-3:S+ 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:S+ 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:S+ C3:P1 . . T C2-3 . . 0 A1:2-3|A2:2-3 A1:P1|A2:P-1" 364 " C3:P1:S+ 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:S+ 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:S+ . . . . 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:S+ 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 S+ 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:S+ 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:S+ C1 . C2-3 . P2 . . 0 A1:0-1|A2:1 A1:P0|A2:P-2" 389 " C0-1:S+ 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:S+ P1 . . . . . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1" 402 " C1-4:P1:S+ P1 . . . C1-4 . . 0 A1|A2:1-4 A1:P1|A2:P1" 403 " C1-4:P1:S+ 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:S+ 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:S+ 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:S+ 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:S+ 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:S+ 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:S+ 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:S+ X4-6:S+ 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:S+ . 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:S+ . X1-2:P2 . . . \ 475 X2-4 . . . . . p1:1,3-4|c11:2 \ 476 p1:P0|c11:P2 2" 477 " CX1-5:S+ . 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:S+ . 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:S+ . 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:S+ X5-6:P1:S+ . . . . \ 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:S+ . C1-4:P1 C2-3 . . \ 493 . . . P1 . . p1:5|c11:1-4|c12:5 \ 494 p1:P1|c11:P1|c12:P-1" 495) 496 497# 498# Write to the cpu online file 499# $1 - <c>=<v> where <c> = cpu number, <v> value to be written 500# 501write_cpu_online() 502{ 503 CPU=${1%=*} 504 VAL=${1#*=} 505 CPUFILE=//sys/devices/system/cpu/cpu${CPU}/online 506 if [[ $VAL -eq 0 ]] 507 then 508 OFFLINE_CPUS="$OFFLINE_CPUS $CPU" 509 else 510 [[ -n "$OFFLINE_CPUS" ]] && { 511 OFFLINE_CPUS=$(echo $CPU $CPU $OFFLINE_CPUS | fmt -1 |\ 512 sort | uniq -u) 513 } 514 fi 515 echo $VAL > $CPUFILE 516 pause 0.05 517} 518 519# 520# Set controller state 521# $1 - cgroup directory 522# $2 - state 523# $3 - showerr 524# 525# The presence of ":" in state means transition from one to the next. 526# 527set_ctrl_state() 528{ 529 TMPMSG=/tmp/.msg_$$ 530 CGRP=$1 531 STATE=$2 532 SHOWERR=${3} 533 CTRL=${CTRL:=$CONTROLLER} 534 HASERR=0 535 REDIRECT="2> $TMPMSG" 536 [[ -z "$STATE" || "$STATE" = '.' ]] && return 0 537 [[ $VERBOSE -gt 0 ]] && SHOWERR=1 538 539 rm -f $TMPMSG 540 for CMD in $(echo $STATE | sed -e "s/:/ /g") 541 do 542 TFILE=$CGRP/cgroup.procs 543 SFILE=$CGRP/cgroup.subtree_control 544 PFILE=$CGRP/cpuset.cpus.partition 545 CFILE=$CGRP/cpuset.cpus 546 XFILE=$CGRP/cpuset.cpus.exclusive 547 case $CMD in 548 S*) PREFIX=${CMD#?} 549 COMM="echo ${PREFIX}${CTRL} > $SFILE" 550 eval $COMM $REDIRECT 551 ;; 552 X*) 553 CPUS=${CMD#?} 554 COMM="echo $CPUS > $XFILE" 555 eval $COMM $REDIRECT 556 ;; 557 CX*) 558 CPUS=${CMD#??} 559 COMM="echo $CPUS > $CFILE; echo $CPUS > $XFILE" 560 eval $COMM $REDIRECT 561 ;; 562 C*) CPUS=${CMD#?} 563 COMM="echo $CPUS > $CFILE" 564 eval $COMM $REDIRECT 565 ;; 566 P*) VAL=${CMD#?} 567 case $VAL in 568 0) VAL=member 569 ;; 570 1) VAL=root 571 ;; 572 2) VAL=isolated 573 ;; 574 *) 575 echo "Invalid partition state - $VAL" 576 exit 1 577 ;; 578 esac 579 COMM="echo $VAL > $PFILE" 580 eval $COMM $REDIRECT 581 ;; 582 O*) VAL=${CMD#?} 583 write_cpu_online $VAL 584 ;; 585 T*) COMM="echo 0 > $TFILE" 586 eval $COMM $REDIRECT 587 ;; 588 *) echo "Unknown command: $CMD" 589 exit 1 590 ;; 591 esac 592 RET=$? 593 [[ $RET -ne 0 ]] && { 594 [[ -n "$SHOWERR" ]] && { 595 echo "$COMM" 596 cat $TMPMSG 597 } 598 HASERR=1 599 } 600 pause 0.01 601 rm -f $TMPMSG 602 done 603 return $HASERR 604} 605 606set_ctrl_state_noerr() 607{ 608 CGRP=$1 609 STATE=$2 610 [[ -d $CGRP ]] || mkdir $CGRP 611 set_ctrl_state $CGRP $STATE 1 612 [[ $? -ne 0 ]] && { 613 echo "ERROR: Failed to set $2 to cgroup $1!" 614 exit 1 615 } 616} 617 618online_cpus() 619{ 620 [[ -n "OFFLINE_CPUS" ]] && { 621 for C in $OFFLINE_CPUS 622 do 623 write_cpu_online ${C}=1 624 done 625 } 626} 627 628# 629# Remove all the test cgroup directories 630# 631reset_cgroup_states() 632{ 633 echo 0 > $CGROUP2/cgroup.procs 634 online_cpus 635 rmdir $RESET_LIST > /dev/null 2>&1 636} 637 638dump_states() 639{ 640 for DIR in $CGROUP_LIST 641 do 642 CPUS=$DIR/cpuset.cpus 643 ECPUS=$DIR/cpuset.cpus.effective 644 XCPUS=$DIR/cpuset.cpus.exclusive 645 XECPUS=$DIR/cpuset.cpus.exclusive.effective 646 PRS=$DIR/cpuset.cpus.partition 647 PCPUS=$DIR/.__DEBUG__.cpuset.cpus.subpartitions 648 ISCPUS=$DIR/cpuset.cpus.isolated 649 [[ -e $CPUS ]] && echo "$CPUS: $(cat $CPUS)" 650 [[ -e $XCPUS ]] && echo "$XCPUS: $(cat $XCPUS)" 651 [[ -e $ECPUS ]] && echo "$ECPUS: $(cat $ECPUS)" 652 [[ -e $XECPUS ]] && echo "$XECPUS: $(cat $XECPUS)" 653 [[ -e $PRS ]] && echo "$PRS: $(cat $PRS)" 654 [[ -e $PCPUS ]] && echo "$PCPUS: $(cat $PCPUS)" 655 [[ -e $ISCPUS ]] && echo "$ISCPUS: $(cat $ISCPUS)" 656 done 657} 658 659# 660# Set the actual cgroup directory into $CGRP_DIR 661# $1 - cgroup name 662# 663set_cgroup_dir() 664{ 665 CGRP_DIR=$1 666 [[ $CGRP_DIR = A2 ]] && CGRP_DIR=A1/A2 667 [[ $CGRP_DIR = A3 ]] && CGRP_DIR=A1/A2/A3 668 [[ $CGRP_DIR = c11 ]] && CGRP_DIR=p1/c11 669 [[ $CGRP_DIR = c12 ]] && CGRP_DIR=p1/c12 670 [[ $CGRP_DIR = c21 ]] && CGRP_DIR=p2/c21 671 [[ $CGRP_DIR = c22 ]] && CGRP_DIR=p2/c22 672} 673 674# 675# Check effective cpus 676# $1 - check string, format: <cgroup>:<cpu-list>[|<cgroup>:<cpu-list>]* 677# 678check_effective_cpus() 679{ 680 CHK_STR=$1 681 for CHK in $(echo $CHK_STR | sed -e "s/|/ /g") 682 do 683 set -- $(echo $CHK | sed -e "s/:/ /g") 684 CGRP=$1 685 EXPECTED_CPUS=$2 686 ACTUAL_CPUS= 687 if [[ $CGRP = X* ]] 688 then 689 CGRP=${CGRP#X} 690 FILE=cpuset.cpus.exclusive.effective 691 else 692 FILE=cpuset.cpus.effective 693 fi 694 set_cgroup_dir $CGRP 695 [[ -e $CGRP_DIR/$FILE ]] || return 1 696 ACTUAL_CPUS=$(cat $CGRP_DIR/$FILE) 697 [[ $EXPECTED_CPUS = $ACTUAL_CPUS ]] || return 1 698 done 699} 700 701# 702# Check cgroup states 703# $1 - check string, format: <cgroup>:<state>[|<cgroup>:<state>]* 704# 705check_cgroup_states() 706{ 707 CHK_STR=$1 708 for CHK in $(echo $CHK_STR | sed -e "s/|/ /g") 709 do 710 set -- $(echo $CHK | sed -e "s/:/ /g") 711 CGRP=$1 712 EXPECTED_STATE=$2 713 FILE= 714 EVAL=$(expr substr $EXPECTED_STATE 2 2) 715 716 set_cgroup_dir $CGRP 717 case $EXPECTED_STATE in 718 P*) FILE=$CGRP_DIR/cpuset.cpus.partition 719 ;; 720 *) echo "Unknown state: $EXPECTED_STATE!" 721 exit 1 722 ;; 723 esac 724 ACTUAL_STATE=$(cat $FILE) 725 726 case "$ACTUAL_STATE" in 727 member) VAL=0 728 ;; 729 root) VAL=1 730 ;; 731 isolated) 732 VAL=2 733 ;; 734 "root invalid"*) 735 VAL=-1 736 ;; 737 "isolated invalid"*) 738 VAL=-2 739 ;; 740 esac 741 [[ $EVAL != $VAL ]] && return 1 742 743 # 744 # For root partition, dump sched-domains info to console if 745 # verbose mode set for manual comparison with sched debug info. 746 # 747 [[ $VAL -eq 1 && $VERBOSE -gt 0 ]] && { 748 DOMS=$(cat $CGRP_DIR/cpuset.cpus.effective) 749 [[ -n "$DOMS" ]] && 750 echo " [$CGRP_DIR] sched-domain: $DOMS" > $CONSOLE 751 } 752 done 753 return 0 754} 755 756# 757# Get isolated (including offline) CPUs by looking at 758# /sys/kernel/debug/sched/domains and cpuset.cpus.isolated control file, 759# if available, and compare that with the expected value. 760# 761# Note that isolated CPUs from the sched/domains context include offline 762# CPUs as well as CPUs in non-isolated 1-CPU partition. Those CPUs may 763# not be included in the cpuset.cpus.isolated control file which contains 764# only CPUs in isolated partitions as well as those that are isolated at 765# boot time. 766# 767# $1 - expected isolated cpu list(s) <isolcpus1>{,<isolcpus2>} 768# <isolcpus1> - expected sched/domains value 769# <isolcpus2> - cpuset.cpus.isolated value = <isolcpus1> if not defined 770# 771check_isolcpus() 772{ 773 EXPECTED_ISOLCPUS=$1 774 ISCPUS=${CGROUP2}/cpuset.cpus.isolated 775 ISOLCPUS=$(cat $ISCPUS) 776 LASTISOLCPU= 777 SCHED_DOMAINS=/sys/kernel/debug/sched/domains 778 if [[ $EXPECTED_ISOLCPUS = . ]] 779 then 780 EXPECTED_ISOLCPUS= 781 EXPECTED_SDOMAIN= 782 elif [[ $(expr $EXPECTED_ISOLCPUS : ".*|.*") > 0 ]] 783 then 784 set -- $(echo $EXPECTED_ISOLCPUS | sed -e "s/|/ /g") 785 EXPECTED_ISOLCPUS=$2 786 EXPECTED_SDOMAIN=$1 787 else 788 EXPECTED_SDOMAIN=$EXPECTED_ISOLCPUS 789 fi 790 791 # 792 # Appending pre-isolated CPUs 793 # Even though CPU #8 isn't used for testing, it can't be pre-isolated 794 # to make appending those CPUs easier. 795 # 796 [[ -n "$BOOT_ISOLCPUS" ]] && { 797 EXPECTED_ISOLCPUS=${EXPECTED_ISOLCPUS:+${EXPECTED_ISOLCPUS},}${BOOT_ISOLCPUS} 798 EXPECTED_SDOMAIN=${EXPECTED_SDOMAIN:+${EXPECTED_SDOMAIN},}${BOOT_ISOLCPUS} 799 } 800 801 # 802 # Check cpuset.cpus.isolated cpumask 803 # 804 [[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && { 805 # Take a 50ms pause and try again 806 pause 0.05 807 ISOLCPUS=$(cat $ISCPUS) 808 } 809 [[ "$EXPECTED_ISOLCPUS" != "$ISOLCPUS" ]] && return 1 810 ISOLCPUS= 811 EXPECTED_ISOLCPUS=$EXPECTED_SDOMAIN 812 813 # 814 # Use the sched domain in debugfs to check isolated CPUs, if available 815 # 816 [[ -d $SCHED_DOMAINS ]] || return 0 817 818 for ((CPU=0; CPU < $NR_CPUS; CPU++)) 819 do 820 [[ -n "$(ls ${SCHED_DOMAINS}/cpu$CPU)" ]] && continue 821 822 if [[ -z "$LASTISOLCPU" ]] 823 then 824 ISOLCPUS=$CPU 825 LASTISOLCPU=$CPU 826 elif [[ "$LASTISOLCPU" -eq $((CPU - 1)) ]] 827 then 828 echo $ISOLCPUS | grep -q "\<$LASTISOLCPU\$" 829 if [[ $? -eq 0 ]] 830 then 831 ISOLCPUS=${ISOLCPUS}- 832 fi 833 LASTISOLCPU=$CPU 834 else 835 if [[ $ISOLCPUS = *- ]] 836 then 837 ISOLCPUS=${ISOLCPUS}$LASTISOLCPU 838 fi 839 ISOLCPUS=${ISOLCPUS},$CPU 840 LASTISOLCPU=$CPU 841 fi 842 done 843 [[ "$ISOLCPUS" = *- ]] && ISOLCPUS=${ISOLCPUS}$LASTISOLCPU 844 845 [[ "$EXPECTED_SDOMAIN" = "$ISOLCPUS" ]] 846} 847 848test_fail() 849{ 850 TESTNUM=$1 851 TESTTYPE=$2 852 ADDINFO=$3 853 echo "Test $TEST[$TESTNUM] failed $TESTTYPE check!" 854 [[ -n "$ADDINFO" ]] && echo "*** $ADDINFO ***" 855 eval echo \${$TEST[$I]} 856 echo 857 dump_states 858 exit 1 859} 860 861# 862# Check to see if there are unexpected isolated CPUs left beyond the boot 863# time isolated ones. 864# 865null_isolcpus_check() 866{ 867 [[ $VERBOSE -gt 0 ]] || return 0 868 # Retry a few times before printing error 869 RETRY=0 870 while [[ $RETRY -lt 8 ]] 871 do 872 pause 0.02 873 check_isolcpus "." 874 [[ $? -eq 0 ]] && return 0 875 ((RETRY++)) 876 done 877 echo "Unexpected isolated CPUs: $ISOLCPUS" 878 dump_states 879 exit 1 880} 881 882# 883# Check state transition test result 884# $1 - Test number 885# $2 - Expected effective CPU values 886# $3 - Expected partition states 887# $4 - Expected isolated CPUs 888# 889check_test_results() 890{ 891 _NR=$1 892 _ECPUS="$2" 893 _PSTATES="$3" 894 _ISOLCPUS="$4" 895 896 [[ -n "$_ECPUS" && "$_ECPUS" != . ]] && { 897 check_effective_cpus $_ECPUS 898 [[ $? -ne 0 ]] && test_fail $_NR "effective CPU" \ 899 "Cgroup $CGRP: expected $EXPECTED_CPUS, got $ACTUAL_CPUS" 900 } 901 902 [[ -n "$_PSTATES" && "$_PSTATES" != . ]] && { 903 check_cgroup_states $_PSTATES 904 [[ $? -ne 0 ]] && test_fail $_NR states \ 905 "Cgroup $CGRP: expected $EXPECTED_STATE, got $ACTUAL_STATE" 906 } 907 908 # Compare the expected isolated CPUs with the actual ones, 909 # if available 910 [[ -n "$_ISOLCPUS" ]] && { 911 check_isolcpus $_ISOLCPUS 912 [[ $? -ne 0 ]] && { 913 [[ -n "$BOOT_ISOLCPUS" ]] && _ISOLCPUS=${_ISOLCPUS},${BOOT_ISOLCPUS} 914 test_fail $_NR "isolated CPU" \ 915 "Expect $_ISOLCPUS, get $ISOLCPUS instead" 916 } 917 } 918 reset_cgroup_states 919 # 920 # Check to see if effective cpu list changes 921 # 922 _NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective) 923 RETRY=0 924 while [[ $_NEWLIST != $CPULIST && $RETRY -lt 8 ]] 925 do 926 # Wait a bit longer & recheck a few times 927 pause 0.02 928 ((RETRY++)) 929 _NEWLIST=$(cat $CGROUP2/cpuset.cpus.effective) 930 done 931 [[ $_NEWLIST != $CPULIST ]] && { 932 echo "Effective cpus changed to $_NEWLIST after test $_NR!" 933 exit 1 934 } 935 null_isolcpus_check 936 [[ $VERBOSE -gt 0 ]] && echo "Test $I done." 937} 938 939# 940# Run cpuset state transition test 941# $1 - test matrix name 942# 943# This test is somewhat fragile as delays (sleep x) are added in various 944# places to make sure state changes are fully propagated before the next 945# action. These delays may need to be adjusted if running in a slower machine. 946# 947run_state_test() 948{ 949 TEST=$1 950 CONTROLLER=cpuset 951 CGROUP_LIST=". A1 A1/A2 A1/A2/A3 B1" 952 RESET_LIST="A1/A2/A3 A1/A2 A1 B1" 953 I=0 954 eval CNT="\${#$TEST[@]}" 955 956 reset_cgroup_states 957 console_msg "Running state transition test ..." 958 959 while [[ $I -lt $CNT ]] 960 do 961 echo "Running test $I ..." > $CONSOLE 962 [[ $VERBOSE -gt 1 ]] && { 963 echo "" 964 eval echo \${$TEST[$I]} 965 } 966 eval set -- "\${$TEST[$I]}" 967 OLD_A1=$1 968 OLD_A2=$2 969 OLD_A3=$3 970 OLD_B1=$4 971 NEW_A1=$5 972 NEW_A2=$6 973 NEW_A3=$7 974 NEW_B1=$8 975 RESULT=$9 976 ECPUS=${10} 977 STATES=${11} 978 ICPUS=${12} 979 980 set_ctrl_state_noerr A1 $OLD_A1 981 set_ctrl_state_noerr A1/A2 $OLD_A2 982 set_ctrl_state_noerr A1/A2/A3 $OLD_A3 983 set_ctrl_state_noerr B1 $OLD_B1 984 985 RETVAL=0 986 set_ctrl_state A1 $NEW_A1; ((RETVAL += $?)) 987 set_ctrl_state A1/A2 $NEW_A2; ((RETVAL += $?)) 988 set_ctrl_state A1/A2/A3 $NEW_A3; ((RETVAL += $?)) 989 set_ctrl_state B1 $NEW_B1; ((RETVAL += $?)) 990 991 [[ $RETVAL -ne $RESULT ]] && test_fail $I result 992 993 check_test_results $I "$ECPUS" "$STATES" "$ICPUS" 994 ((I++)) 995 done 996 echo "All $I tests of $TEST PASSED." 997} 998 999# 1000# Run cpuset remote partition state transition test 1001# $1 - test matrix name 1002# 1003run_remote_state_test() 1004{ 1005 TEST=$1 1006 CONTROLLER=cpuset 1007 [[ -d rtest ]] || mkdir rtest 1008 cd rtest 1009 echo +cpuset > cgroup.subtree_control 1010 echo "1-7" > cpuset.cpus 1011 echo "1-7" > cpuset.cpus.exclusive 1012 CGROUP_LIST=".. . p1 p2 p1/c11 p1/c12 p2/c21 p2/c22" 1013 RESET_LIST="p1/c11 p1/c12 p2/c21 p2/c22 p1 p2" 1014 I=0 1015 eval CNT="\${#$TEST[@]}" 1016 1017 reset_cgroup_states 1018 console_msg "Running remote partition state transition test ..." 1019 1020 while [[ $I -lt $CNT ]] 1021 do 1022 echo "Running test $I ..." > $CONSOLE 1023 [[ $VERBOSE -gt 1 ]] && { 1024 echo "" 1025 eval echo \${$TEST[$I]} 1026 } 1027 eval set -- "\${$TEST[$I]}" 1028 OLD_p1=$1 1029 OLD_p2=$2 1030 OLD_c11=$3 1031 OLD_c12=$4 1032 OLD_c21=$5 1033 OLD_c22=$6 1034 NEW_p1=$7 1035 NEW_p2=$8 1036 NEW_c11=$9 1037 NEW_c12=${10} 1038 NEW_c21=${11} 1039 NEW_c22=${12} 1040 ECPUS=${13} 1041 STATES=${14} 1042 ICPUS=${15} 1043 1044 set_ctrl_state_noerr p1 $OLD_p1 1045 set_ctrl_state_noerr p2 $OLD_p2 1046 set_ctrl_state_noerr p1/c11 $OLD_c11 1047 set_ctrl_state_noerr p1/c12 $OLD_c12 1048 set_ctrl_state_noerr p2/c21 $OLD_c21 1049 set_ctrl_state_noerr p2/c22 $OLD_c22 1050 1051 RETVAL=0 1052 set_ctrl_state p1 $NEW_p1 ; ((RETVAL += $?)) 1053 set_ctrl_state p2 $NEW_p2 ; ((RETVAL += $?)) 1054 set_ctrl_state p1/c11 $NEW_c11; ((RETVAL += $?)) 1055 set_ctrl_state p1/c12 $NEW_c12; ((RETVAL += $?)) 1056 set_ctrl_state p2/c21 $NEW_c21; ((RETVAL += $?)) 1057 set_ctrl_state p2/c22 $NEW_c22; ((RETVAL += $?)) 1058 1059 [[ $RETVAL -ne 0 ]] && test_fail $I result 1060 1061 check_test_results $I "$ECPUS" "$STATES" "$ICPUS" 1062 ((I++)) 1063 done 1064 cd .. 1065 rmdir rtest 1066 echo "All $I tests of $TEST PASSED." 1067} 1068 1069# 1070# Testing the new "isolated" partition root type 1071# 1072test_isolated() 1073{ 1074 cd $CGROUP2/test 1075 echo 2-3 > cpuset.cpus 1076 TYPE=$(cat cpuset.cpus.partition) 1077 [[ $TYPE = member ]] || echo member > cpuset.cpus.partition 1078 1079 console_msg "Change from member to root" 1080 test_partition root 1081 1082 console_msg "Change from root to isolated" 1083 test_partition isolated 1084 1085 console_msg "Change from isolated to member" 1086 test_partition member 1087 1088 console_msg "Change from member to isolated" 1089 test_partition isolated 1090 1091 console_msg "Change from isolated to root" 1092 test_partition root 1093 1094 console_msg "Change from root to member" 1095 test_partition member 1096 1097 # 1098 # Testing partition root with no cpu 1099 # 1100 console_msg "Distribute all cpus to child partition" 1101 echo +cpuset > cgroup.subtree_control 1102 test_partition root 1103 1104 mkdir A1 1105 cd A1 1106 echo 2-3 > cpuset.cpus 1107 test_partition root 1108 test_effective_cpus 2-3 1109 cd .. 1110 test_effective_cpus "" 1111 1112 console_msg "Moving task to partition test" 1113 test_add_proc "No space left" 1114 cd A1 1115 test_add_proc "" 1116 cd .. 1117 1118 console_msg "Shrink and expand child partition" 1119 cd A1 1120 echo 2 > cpuset.cpus 1121 cd .. 1122 test_effective_cpus 3 1123 cd A1 1124 echo 2-3 > cpuset.cpus 1125 cd .. 1126 test_effective_cpus "" 1127 1128 # Cleaning up 1129 console_msg "Cleaning up" 1130 echo $$ > $CGROUP2/cgroup.procs 1131 [[ -d A1 ]] && rmdir A1 1132 null_isolcpus_check 1133 pause 0.05 1134} 1135 1136# 1137# Wait for inotify event for the given file and read it 1138# $1: cgroup file to wait for 1139# $2: file to store the read result 1140# 1141wait_inotify() 1142{ 1143 CGROUP_FILE=$1 1144 OUTPUT_FILE=$2 1145 1146 $WAIT_INOTIFY $CGROUP_FILE 1147 cat $CGROUP_FILE > $OUTPUT_FILE 1148} 1149 1150# 1151# Test if inotify events are properly generated when going into and out of 1152# invalid partition state. 1153# 1154test_inotify() 1155{ 1156 ERR=0 1157 PRS=/tmp/.prs_$$ 1158 cd $CGROUP2/test 1159 [[ -f $WAIT_INOTIFY ]] || { 1160 echo "wait_inotify not found, inotify test SKIPPED." 1161 return 1162 } 1163 1164 pause 0.01 1165 echo 1 > cpuset.cpus 1166 echo 0 > cgroup.procs 1167 echo root > cpuset.cpus.partition 1168 pause 0.01 1169 rm -f $PRS 1170 wait_inotify $PWD/cpuset.cpus.partition $PRS & 1171 pause 0.01 1172 set_ctrl_state . "O1=0" 1173 pause 0.01 1174 check_cgroup_states ".:P-1" 1175 if [[ $? -ne 0 ]] 1176 then 1177 echo "FAILED: Inotify test - partition not invalid" 1178 ERR=1 1179 elif [[ ! -f $PRS ]] 1180 then 1181 echo "FAILED: Inotify test - event not generated" 1182 ERR=1 1183 kill %1 1184 elif [[ $(cat $PRS) != "root invalid"* ]] 1185 then 1186 echo "FAILED: Inotify test - incorrect state" 1187 cat $PRS 1188 ERR=1 1189 fi 1190 online_cpus 1191 echo member > cpuset.cpus.partition 1192 echo 0 > ../cgroup.procs 1193 if [[ $ERR -ne 0 ]] 1194 then 1195 exit 1 1196 else 1197 echo "Inotify test PASSED" 1198 fi 1199 echo member > cpuset.cpus.partition 1200 echo "" > cpuset.cpus 1201} 1202 1203trap cleanup 0 2 3 6 1204run_state_test TEST_MATRIX 1205run_remote_state_test REMOTE_TEST_MATRIX 1206test_isolated 1207test_inotify 1208echo "All tests PASSED." 1209