File Index
Files and directories
Sign in
FILE

test_cpuset_prs.sh

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/cgroup/test_cpuset_prs.sh BASH
   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."
~/ Read-only file preview.