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