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