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 is set, if available, 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 0 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!" 25 26CPUS=$(lscpu | grep "^CPU(s):" | sed -e "s/.*:[[:space:]]*//") 27[[ $CPUS -lt 8 ]] && skip_test "Test needs at least 8 cpus available!" 28 29# Set verbose flag and delay factor 30PROG=$1 31VERBOSE= 32DELAY_FACTOR=1 33SCHED_DEBUG= 34while [[ "$1" = -* ]] 35do 36 case "$1" in 37 -v) VERBOSE=1 38 # Enable sched/verbose can slow thing down 39 [[ $DELAY_FACTOR -eq 1 ]] && 40 DELAY_FACTOR=2 41 break 42 ;; 43 -d) DELAY_FACTOR=$2 44 shift 45 break 46 ;; 47 *) echo "Usage: $PROG [-v] [-d <delay-factor>" 48 exit 49 ;; 50 esac 51 shift 52done 53 54# Set sched verbose flag if available when "-v" option is specified 55if [[ -n "$VERBOSE" && -d /sys/kernel/debug/sched ]] 56then 57 # Used to restore the original setting during cleanup 58 SCHED_DEBUG=$(cat /sys/kernel/debug/sched/verbose) 59 echo Y > /sys/kernel/debug/sched/verbose 60fi 61 62cd $CGROUP2 63echo +cpuset > cgroup.subtree_control 64[[ -d test ]] || mkdir test 65cd test 66 67cleanup() 68{ 69 online_cpus 70 rmdir A1/A2/A3 A1/A2 A1 B1 > /dev/null 2>&1 71 cd .. 72 rmdir test > /dev/null 2>&1 73 [[ -n "$SCHED_DEBUG" ]] && 74 echo "$SCHED_DEBUG" > /sys/kernel/debug/sched/verbose 75} 76 77# Pause in ms 78pause() 79{ 80 DELAY=$1 81 LOOP=0 82 while [[ $LOOP -lt $DELAY_FACTOR ]] 83 do 84 sleep $DELAY 85 ((LOOP++)) 86 done 87 return 0 88} 89 90console_msg() 91{ 92 MSG=$1 93 echo "$MSG" 94 echo "" > /dev/console 95 echo "$MSG" > /dev/console 96 pause 0.01 97} 98 99test_partition() 100{ 101 EXPECTED_VAL=$1 102 echo $EXPECTED_VAL > cpuset.cpus.partition 103 [[ $? -eq 0 ]] || exit 1 104 ACTUAL_VAL=$(cat cpuset.cpus.partition) 105 [[ $ACTUAL_VAL != $EXPECTED_VAL ]] && { 106 echo "cpuset.cpus.partition: expect $EXPECTED_VAL, found $EXPECTED_VAL" 107 echo "Test FAILED" 108 exit 1 109 } 110} 111 112test_effective_cpus() 113{ 114 EXPECTED_VAL=$1 115 ACTUAL_VAL=$(cat cpuset.cpus.effective) 116 [[ "$ACTUAL_VAL" != "$EXPECTED_VAL" ]] && { 117 echo "cpuset.cpus.effective: expect '$EXPECTED_VAL', found '$EXPECTED_VAL'" 118 echo "Test FAILED" 119 exit 1 120 } 121} 122 123# Adding current process to cgroup.procs as a test 124test_add_proc() 125{ 126 OUTSTR="$1" 127 ERRMSG=$((echo $$ > cgroup.procs) |& cat) 128 echo $ERRMSG | grep -q "$OUTSTR" 129 [[ $? -ne 0 ]] && { 130 echo "cgroup.procs: expect '$OUTSTR', got '$ERRMSG'" 131 echo "Test FAILED" 132 exit 1 133 } 134 echo $$ > $CGROUP2/cgroup.procs # Move out the task 135} 136 137# 138# Testing the new "isolated" partition root type 139# 140test_isolated() 141{ 142 echo 2-3 > cpuset.cpus 143 TYPE=$(cat cpuset.cpus.partition) 144 [[ $TYPE = member ]] || echo member > cpuset.cpus.partition 145 146 console_msg "Change from member to root" 147 test_partition root 148 149 console_msg "Change from root to isolated" 150 test_partition isolated 151 152 console_msg "Change from isolated to member" 153 test_partition member 154 155 console_msg "Change from member to isolated" 156 test_partition isolated 157 158 console_msg "Change from isolated to root" 159 test_partition root 160 161 console_msg "Change from root to member" 162 test_partition member 163 164 # 165 # Testing partition root with no cpu 166 # 167 console_msg "Distribute all cpus to child partition" 168 echo +cpuset > cgroup.subtree_control 169 test_partition root 170 171 mkdir A1 172 cd A1 173 echo 2-3 > cpuset.cpus 174 test_partition root 175 test_effective_cpus 2-3 176 cd .. 177 test_effective_cpus "" 178 179 console_msg "Moving task to partition test" 180 test_add_proc "No space left" 181 cd A1 182 test_add_proc "" 183 cd .. 184 185 console_msg "Shrink and expand child partition" 186 cd A1 187 echo 2 > cpuset.cpus 188 cd .. 189 test_effective_cpus 3 190 cd A1 191 echo 2-3 > cpuset.cpus 192 cd .. 193 test_effective_cpus "" 194 195 # Cleaning up 196 console_msg "Cleaning up" 197 echo $$ > $CGROUP2/cgroup.procs 198 [[ -d A1 ]] && rmdir A1 199} 200 201# 202# Cpuset controller state transition test matrix. 203# 204# Cgroup test hierarchy 205# 206# test -- A1 -- A2 -- A3 207# \- B1 208# 209# P<v> = set cpus.partition (0:member, 1:root, 2:isolated, -1:root invalid) 210# C<l> = add cpu-list 211# S<p> = use prefix in subtree_control 212# T = put a task into cgroup 213# O<c>-<v> = Write <v> to CPU online file of <c> 214# 215SETUP_A123_PARTITIONS="C1-3:P1:S+ C2-3:P1:S+ C3:P1" 216TEST_MATRIX=( 217 # test old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate 218 # ---- ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ 219 " S+ C0-1 . . C2-3 S+ C4-5 . . 0 A2:0-1" 220 " S+ C0-1 . . C2-3 P1 . . . 0 " 221 " S+ C0-1 . . C2-3 P1:S+ C0-1:P1 . . 0 " 222 " S+ C0-1 . . C2-3 P1:S+ C1:P1 . . 0 " 223 " S+ C0-1:S+ . . C2-3 . . . P1 0 " 224 " S+ C0-1:P1 . . C2-3 S+ C1 . . 0 " 225 " S+ C0-1:P1 . . C2-3 S+ C1:P1 . . 0 " 226 " S+ C0-1:P1 . . C2-3 S+ C1:P1 . P1 0 " 227 " S+ C0-1:P1 . . C2-3 C4-5 . . . 0 A1:4-5" 228 " S+ C0-1:P1 . . C2-3 S+:C4-5 . . . 0 A1:4-5" 229 " S+ C0-1 . . C2-3:P1 . . . C2 0 " 230 " S+ C0-1 . . C2-3:P1 . . . C4-5 0 B1:4-5" 231 " S+ C0-3:P1:S+ C2-3:P1 . . . . . . 0 A1:0-1,A2:2-3" 232 " S+ C0-3:P1:S+ C2-3:P1 . . C1-3 . . . 0 A1:1,A2:2-3" 233 " S+ C2-3:P1:S+ C3:P1 . . C3 . . . 0 A1:,A2:3 A1:P1,A2:P1" 234 " S+ C2-3:P1:S+ C3:P1 . . C3 P0 . . 0 A1:3,A2:3 A1:P1,A2:P0" 235 " S+ C2-3:P1:S+ C2:P1 . . C2-4 . . . 0 A1:3-4,A2:2" 236 " S+ C2-3:P1:S+ C3:P1 . . C3 . . C0-2 0 A1:,B1:0-2 A1:P1,A2:P1" 237 " S+ $SETUP_A123_PARTITIONS . C2-3 . . . 0 A1:,A2:2,A3:3 A1:P1,A2:P1,A3:P1" 238 239 # CPU offlining cases: 240 " S+ C0-1 . . C2-3 S+ C4-5 . O2-0 0 A1:0-1,B1:3" 241 " S+ C0-3:P1:S+ C2-3:P1 . . O2-0 . . . 0 A1:0-1,A2:3" 242 " S+ C0-3:P1:S+ C2-3:P1 . . O2-0 O2-1 . . 0 A1:0-1,A2:2-3" 243 " S+ C0-3:P1:S+ C2-3:P1 . . O1-0 . . . 0 A1:0,A2:2-3" 244 " S+ C0-3:P1:S+ C2-3:P1 . . O1-0 O1-1 . . 0 A1:0-1,A2:2-3" 245 " S+ C2-3:P1:S+ C3:P1 . . O3-0 O3-1 . . 0 A1:2,A2:3 A1:P1,A2:P1" 246 " S+ C2-3:P1:S+ C3:P2 . . O3-0 O3-1 . . 0 A1:2,A2:3 A1:P1,A2:P2" 247 " S+ C2-3:P1:S+ C3:P1 . . O2-0 O2-1 . . 0 A1:2,A2:3 A1:P1,A2:P1" 248 " S+ C2-3:P1:S+ C3:P2 . . O2-0 O2-1 . . 0 A1:2,A2:3 A1:P1,A2:P2" 249 " S+ C2-3:P1:S+ C3:P1 . . O2-0 . . . 0 A1:,A2:3 A1:P1,A2:P1" 250 " S+ C2-3:P1:S+ C3:P1 . . O3-0 . . . 0 A1:2,A2: A1:P1,A2:P1" 251 " S+ C2-3:P1:S+ C3:P1 . . T:O2-0 . . . 0 A1:3,A2:3 A1:P1,A2:P-1" 252 " S+ C2-3:P1:S+ C3:P1 . . . T:O3-0 . . 0 A1:2,A2:2 A1:P1,A2:P-1" 253 " S+ $SETUP_A123_PARTITIONS . O1-0 . . . 0 A1:,A2:2,A3:3 A1:P1,A2:P1,A3:P1" 254 " S+ $SETUP_A123_PARTITIONS . O2-0 . . . 0 A1:1,A2:,A3:3 A1:P1,A2:P1,A3:P1" 255 " S+ $SETUP_A123_PARTITIONS . O3-0 . . . 0 A1:1,A2:2,A3: A1:P1,A2:P1,A3:P1" 256 " S+ $SETUP_A123_PARTITIONS . T:O1-0 . . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1" 257 " S+ $SETUP_A123_PARTITIONS . . T:O2-0 . . 0 A1:1,A2:3,A3:3 A1:P1,A2:P1,A3:P-1" 258 " S+ $SETUP_A123_PARTITIONS . . . T:O3-0 . 0 A1:1,A2:2,A3:2 A1:P1,A2:P1,A3:P-1" 259 " S+ $SETUP_A123_PARTITIONS . T:O1-0 O1-1 . . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1" 260 " S+ $SETUP_A123_PARTITIONS . . T:O2-0 O2-1 . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1" 261 " S+ $SETUP_A123_PARTITIONS . . . T:O3-0 O3-1 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1" 262 " S+ $SETUP_A123_PARTITIONS . T:O1-0 O2-0 O1-1 . 0 A1:1,A2:,A3:3 A1:P1,A2:P1,A3:P1" 263 " S+ $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" 264 265 # test old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate 266 # ---- ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ 267 # 268 # Incorrect change to cpuset.cpus invalidates partition root 269 # 270 # Adding CPUs to partition root that are not in parent's 271 # cpuset.cpus is allowed, but those extra CPUs are ignored. 272 " S+ C2-3:P1:S+ C3:P1 . . . C2-4 . . 0 A1:,A2:2-3 A1:P1,A2:P1" 273 274 # Taking away all CPUs from parent or itself if there are tasks 275 # will make the partition invalid. 276 " S+ C2-3:P1:S+ C3:P1 . . T C2-3 . . 0 A1:2-3,A2:2-3 A1:P1,A2:P-1" 277 " S+ C3:P1:S+ C3 . . T P1 . . 0 A1:3,A2:3 A1:P1,A2:P-1" 278 " S+ $SETUP_A123_PARTITIONS . T:C2-3 . . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1" 279 " S+ $SETUP_A123_PARTITIONS . T:C2-3:C1-3 . . . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1" 280 281 # Changing a partition root to member makes child partitions invalid 282 " S+ C2-3:P1:S+ C3:P1 . . P0 . . . 0 A1:2-3,A2:3 A1:P0,A2:P-1" 283 " S+ $SETUP_A123_PARTITIONS . C2-3 P0 . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P0,A3:P-1" 284 285 # cpuset.cpus can contains cpus not in parent's cpuset.cpus as long 286 # as they overlap. 287 " S+ C2-3:P1:S+ . . . . C3-4:P1 . . 0 A1:2,A2:3 A1:P1,A2:P1" 288 289 # Deletion of CPUs distributed to child cgroup is allowed. 290 " S+ C0-1:P1:S+ C1 . C2-3 C4-5 . . . 0 A1:4-5,A2:4-5" 291 292 # To become a valid partition root, cpuset.cpus must overlap parent's 293 # cpuset.cpus. 294 " S+ C0-1:P1 . . C2-3 S+ C4-5:P1 . . 0 A1:0-1,A2:0-1 A1:P1,A2:P-1" 295 296 # Enabling partition with child cpusets is allowed 297 " S+ C0-1:S+ C1 . C2-3 P1 . . . 0 A1:0-1,A2:1 A1:P1" 298 299 # A partition root with non-partition root parent is invalid, but it 300 # can be made valid if its parent becomes a partition root too. 301 " S+ C0-1:S+ C1 . C2-3 . P2 . . 0 A1:0-1,A2:1 A1:P0,A2:P-2" 302 " S+ C0-1:S+ C1:P2 . C2-3 P1 . . . 0 A1:0,A2:1 A1:P1,A2:P2" 303 304 # A non-exclusive cpuset.cpus change will invalidate partition and its siblings 305 " S+ C0-1:P1 . . C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P-1,B1:P0" 306 " S+ C0-1:P1 . . P1:C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P-1,B1:P-1" 307 " S+ C0-1 . . P1:C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P0,B1:P-1" 308 309 # test old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate 310 # ---- ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ 311 # Failure cases: 312 313 # A task cannot be added to a partition with no cpu 314 " S+ C2-3:P1:S+ C3:P1 . . O2-0:T . . . 1 A1:,A2:3 A1:P1,A2:P1" 315) 316 317# 318# Write to the cpu online file 319# $1 - <c>-<v> where <c> = cpu number, <v> value to be written 320# 321write_cpu_online() 322{ 323 CPU=${1%-*} 324 VAL=${1#*-} 325 CPUFILE=//sys/devices/system/cpu/cpu${CPU}/online 326 if [[ $VAL -eq 0 ]] 327 then 328 OFFLINE_CPUS="$OFFLINE_CPUS $CPU" 329 else 330 [[ -n "$OFFLINE_CPUS" ]] && { 331 OFFLINE_CPUS=$(echo $CPU $CPU $OFFLINE_CPUS | fmt -1 |\ 332 sort | uniq -u) 333 } 334 fi 335 echo $VAL > $CPUFILE 336 pause 0.01 337} 338 339# 340# Set controller state 341# $1 - cgroup directory 342# $2 - state 343# $3 - showerr 344# 345# The presence of ":" in state means transition from one to the next. 346# 347set_ctrl_state() 348{ 349 TMPMSG=/tmp/.msg_$$ 350 CGRP=$1 351 STATE=$2 352 SHOWERR=${3}${VERBOSE} 353 CTRL=${CTRL:=$CONTROLLER} 354 HASERR=0 355 REDIRECT="2> $TMPMSG" 356 [[ -z "$STATE" || "$STATE" = '.' ]] && return 0 357 358 rm -f $TMPMSG 359 for CMD in $(echo $STATE | sed -e "s/:/ /g") 360 do 361 TFILE=$CGRP/cgroup.procs 362 SFILE=$CGRP/cgroup.subtree_control 363 PFILE=$CGRP/cpuset.cpus.partition 364 CFILE=$CGRP/cpuset.cpus 365 S=$(expr substr $CMD 1 1) 366 if [[ $S = S ]] 367 then 368 PREFIX=${CMD#?} 369 COMM="echo ${PREFIX}${CTRL} > $SFILE" 370 eval $COMM $REDIRECT 371 elif [[ $S = C ]] 372 then 373 CPUS=${CMD#?} 374 COMM="echo $CPUS > $CFILE" 375 eval $COMM $REDIRECT 376 elif [[ $S = P ]] 377 then 378 VAL=${CMD#?} 379 case $VAL in 380 0) VAL=member 381 ;; 382 1) VAL=root 383 ;; 384 2) VAL=isolated 385 ;; 386 *) 387 echo "Invalid partition state - $VAL" 388 exit 1 389 ;; 390 esac 391 COMM="echo $VAL > $PFILE" 392 eval $COMM $REDIRECT 393 elif [[ $S = O ]] 394 then 395 VAL=${CMD#?} 396 write_cpu_online $VAL 397 elif [[ $S = T ]] 398 then 399 COMM="echo 0 > $TFILE" 400 eval $COMM $REDIRECT 401 fi 402 RET=$? 403 [[ $RET -ne 0 ]] && { 404 [[ -n "$SHOWERR" ]] && { 405 echo "$COMM" 406 cat $TMPMSG 407 } 408 HASERR=1 409 } 410 pause 0.01 411 rm -f $TMPMSG 412 done 413 return $HASERR 414} 415 416set_ctrl_state_noerr() 417{ 418 CGRP=$1 419 STATE=$2 420 [[ -d $CGRP ]] || mkdir $CGRP 421 set_ctrl_state $CGRP $STATE 1 422 [[ $? -ne 0 ]] && { 423 echo "ERROR: Failed to set $2 to cgroup $1!" 424 exit 1 425 } 426} 427 428online_cpus() 429{ 430 [[ -n "OFFLINE_CPUS" ]] && { 431 for C in $OFFLINE_CPUS 432 do 433 write_cpu_online ${C}-1 434 done 435 } 436} 437 438# 439# Return 1 if the list of effective cpus isn't the same as the initial list. 440# 441reset_cgroup_states() 442{ 443 echo 0 > $CGROUP2/cgroup.procs 444 online_cpus 445 rmdir A1/A2/A3 A1/A2 A1 B1 > /dev/null 2>&1 446 set_ctrl_state . S- 447 pause 0.01 448} 449 450dump_states() 451{ 452 for DIR in A1 A1/A2 A1/A2/A3 B1 453 do 454 ECPUS=$DIR/cpuset.cpus.effective 455 PRS=$DIR/cpuset.cpus.partition 456 [[ -e $ECPUS ]] && echo "$ECPUS: $(cat $ECPUS)" 457 [[ -e $PRS ]] && echo "$PRS: $(cat $PRS)" 458 done 459} 460 461# 462# Check effective cpus 463# $1 - check string, format: <cgroup>:<cpu-list>[,<cgroup>:<cpu-list>]* 464# 465check_effective_cpus() 466{ 467 CHK_STR=$1 468 for CHK in $(echo $CHK_STR | sed -e "s/,/ /g") 469 do 470 set -- $(echo $CHK | sed -e "s/:/ /g") 471 CGRP=$1 472 CPUS=$2 473 [[ $CGRP = A2 ]] && CGRP=A1/A2 474 [[ $CGRP = A3 ]] && CGRP=A1/A2/A3 475 FILE=$CGRP/cpuset.cpus.effective 476 [[ -e $FILE ]] || return 1 477 [[ $CPUS = $(cat $FILE) ]] || return 1 478 done 479} 480 481# 482# Check cgroup states 483# $1 - check string, format: <cgroup>:<state>[,<cgroup>:<state>]* 484# 485check_cgroup_states() 486{ 487 CHK_STR=$1 488 for CHK in $(echo $CHK_STR | sed -e "s/,/ /g") 489 do 490 set -- $(echo $CHK | sed -e "s/:/ /g") 491 CGRP=$1 492 STATE=$2 493 FILE= 494 EVAL=$(expr substr $STATE 2 2) 495 [[ $CGRP = A2 ]] && CGRP=A1/A2 496 [[ $CGRP = A3 ]] && CGRP=A1/A2/A3 497 498 case $STATE in 499 P*) FILE=$CGRP/cpuset.cpus.partition 500 ;; 501 *) echo "Unknown state: $STATE!" 502 exit 1 503 ;; 504 esac 505 VAL=$(cat $FILE) 506 507 case "$VAL" in 508 member) VAL=0 509 ;; 510 root) VAL=1 511 ;; 512 isolated) 513 VAL=2 514 ;; 515 "root invalid"*) 516 VAL=-1 517 ;; 518 "isolated invalid"*) 519 VAL=-2 520 ;; 521 esac 522 [[ $EVAL != $VAL ]] && return 1 523 done 524 return 0 525} 526 527# 528# Run cpuset state transition test 529# $1 - test matrix name 530# 531# This test is somewhat fragile as delays (sleep x) are added in various 532# places to make sure state changes are fully propagated before the next 533# action. These delays may need to be adjusted if running in a slower machine. 534# 535run_state_test() 536{ 537 TEST=$1 538 CONTROLLER=cpuset 539 CPULIST=0-6 540 I=0 541 eval CNT="\${#$TEST[@]}" 542 543 reset_cgroup_states 544 echo $CPULIST > cpuset.cpus 545 echo root > cpuset.cpus.partition 546 console_msg "Running state transition test ..." 547 548 while [[ $I -lt $CNT ]] 549 do 550 echo "Running test $I ..." > /dev/console 551 eval set -- "\${$TEST[$I]}" 552 ROOT=$1 553 OLD_A1=$2 554 OLD_A2=$3 555 OLD_A3=$4 556 OLD_B1=$5 557 NEW_A1=$6 558 NEW_A2=$7 559 NEW_A3=$8 560 NEW_B1=$9 561 RESULT=${10} 562 ECPUS=${11} 563 STATES=${12} 564 565 set_ctrl_state_noerr . $ROOT 566 set_ctrl_state_noerr A1 $OLD_A1 567 set_ctrl_state_noerr A1/A2 $OLD_A2 568 set_ctrl_state_noerr A1/A2/A3 $OLD_A3 569 set_ctrl_state_noerr B1 $OLD_B1 570 RETVAL=0 571 set_ctrl_state A1 $NEW_A1; ((RETVAL += $?)) 572 set_ctrl_state A1/A2 $NEW_A2; ((RETVAL += $?)) 573 set_ctrl_state A1/A2/A3 $NEW_A3; ((RETVAL += $?)) 574 set_ctrl_state B1 $NEW_B1; ((RETVAL += $?)) 575 576 [[ $RETVAL -ne $RESULT ]] && { 577 echo "Test $TEST[$I] failed result check!" 578 eval echo \"\${$TEST[$I]}\" 579 dump_states 580 exit 1 581 } 582 583 [[ -n "$ECPUS" && "$ECPUS" != . ]] && { 584 check_effective_cpus $ECPUS 585 [[ $? -ne 0 ]] && { 586 echo "Test $TEST[$I] failed effective CPU check!" 587 eval echo \"\${$TEST[$I]}\" 588 echo 589 dump_states 590 exit 1 591 } 592 } 593 594 [[ -n "$STATES" ]] && { 595 check_cgroup_states $STATES 596 [[ $? -ne 0 ]] && { 597 echo "FAILED: Test $TEST[$I] failed states check!" 598 eval echo \"\${$TEST[$I]}\" 599 echo 600 dump_states 601 exit 1 602 } 603 } 604 605 reset_cgroup_states 606 # 607 # Check to see if effective cpu list changes 608 # 609 pause 0.05 610 NEWLIST=$(cat cpuset.cpus.effective) 611 [[ $NEWLIST != $CPULIST ]] && { 612 echo "Effective cpus changed to $NEWLIST after test $I!" 613 exit 1 614 } 615 [[ -n "$VERBOSE" ]] && echo "Test $I done." 616 ((I++)) 617 done 618 echo "All $I tests of $TEST PASSED." 619 620 echo member > cpuset.cpus.partition 621} 622 623# 624# Wait for inotify event for the given file and read it 625# $1: cgroup file to wait for 626# $2: file to store the read result 627# 628wait_inotify() 629{ 630 CGROUP_FILE=$1 631 OUTPUT_FILE=$2 632 633 $WAIT_INOTIFY $CGROUP_FILE 634 cat $CGROUP_FILE > $OUTPUT_FILE 635} 636 637# 638# Test if inotify events are properly generated when going into and out of 639# invalid partition state. 640# 641test_inotify() 642{ 643 ERR=0 644 PRS=/tmp/.prs_$$ 645 [[ -f $WAIT_INOTIFY ]] || { 646 echo "wait_inotify not found, inotify test SKIPPED." 647 return 648 } 649 650 pause 0.01 651 echo 1 > cpuset.cpus 652 echo 0 > cgroup.procs 653 echo root > cpuset.cpus.partition 654 pause 0.01 655 rm -f $PRS 656 wait_inotify $PWD/cpuset.cpus.partition $PRS & 657 pause 0.01 658 set_ctrl_state . "O1-0" 659 pause 0.01 660 check_cgroup_states ".:P-1" 661 if [[ $? -ne 0 ]] 662 then 663 echo "FAILED: Inotify test - partition not invalid" 664 ERR=1 665 elif [[ ! -f $PRS ]] 666 then 667 echo "FAILED: Inotify test - event not generated" 668 ERR=1 669 kill %1 670 elif [[ $(cat $PRS) != "root invalid"* ]] 671 then 672 echo "FAILED: Inotify test - incorrect state" 673 cat $PRS 674 ERR=1 675 fi 676 online_cpus 677 echo member > cpuset.cpus.partition 678 echo 0 > ../cgroup.procs 679 if [[ $ERR -ne 0 ]] 680 then 681 exit 1 682 else 683 echo "Inotify test PASSED" 684 fi 685} 686 687trap cleanup 0 2 3 6 688run_state_test TEST_MATRIX 689test_isolated 690test_inotify 691echo "All tests PASSED." 692cd .. 693rmdir test 694