Merge tag 'i3c/for-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
[linux-block.git] / tools / testing / selftests / cgroup / test_cpuset_prs.sh
CommitLineData
a8c52eba
WL
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Test for cpuset v2 partition root state (PRS)
5#
105f3fe9 6# The sched verbose flag can be optionally set so that the console log
a8c52eba
WL
7# can be examined for the correct setting of scheduling domain.
8#
9
10skip_test() {
11 echo "$1"
12 echo "Test SKIPPED"
12101424 13 exit 4 # ksft_skip
a8c52eba
WL
14}
15
16[[ $(id -u) -eq 0 ]] || skip_test "Test must be run as root!"
17
a8c52eba
WL
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!"
105f3fe9
WL
25SUBPARTS_CPUS=$CGROUP2/.__DEBUG__.cpuset.cpus.subpartitions
26CPULIST=$(cat $CGROUP2/cpuset.cpus.effective)
a8c52eba 27
105f3fe9
WL
28NR_CPUS=$(lscpu | grep "^CPU(s):" | sed -e "s/.*:[[:space:]]*//")
29[[ $NR_CPUS -lt 8 ]] && skip_test "Test needs at least 8 cpus available!"
a8c52eba
WL
30
31# Set verbose flag and delay factor
32PROG=$1
105f3fe9 33VERBOSE=0
a8c52eba 34DELAY_FACTOR=1
1bf33285 35SCHED_DEBUG=
a8c52eba
WL
36while [[ "$1" = -* ]]
37do
38 case "$1" in
105f3fe9 39 -v) ((VERBOSE++))
1bf33285
WL
40 # Enable sched/verbose can slow thing down
41 [[ $DELAY_FACTOR -eq 1 ]] &&
42 DELAY_FACTOR=2
a8c52eba
WL
43 ;;
44 -d) DELAY_FACTOR=$2
45 shift
a8c52eba
WL
46 ;;
47 *) echo "Usage: $PROG [-v] [-d <delay-factor>"
48 exit
49 ;;
50 esac
51 shift
52done
53
1bf33285 54# Set sched verbose flag if available when "-v" option is specified
105f3fe9 55if [[ $VERBOSE -gt 0 && -d /sys/kernel/debug/sched ]]
1bf33285
WL
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
a8c52eba
WL
62cd $CGROUP2
63echo +cpuset > cgroup.subtree_control
105f3fe9
WL
64
65#
66# If cpuset has been set up and used in child cgroups, we may not be able to
67# create partition under root cgroup because of the CPU exclusivity rule.
68# So we are going to skip the test if this is the case.
69#
a8c52eba 70[[ -d test ]] || mkdir test
105f3fe9
WL
71echo 0-6 > test/cpuset.cpus
72echo root > test/cpuset.cpus.partition
73cat test/cpuset.cpus.partition | grep -q invalid
74RESULT=$?
75echo member > test/cpuset.cpus.partition
76echo "" > test/cpuset.cpus
77[[ $RESULT -eq 0 ]] && skip_test "Child cgroups are using cpuset!"
a8c52eba 78
1e85591d
KB
79cleanup()
80{
81 online_cpus
105f3fe9 82 cd $CGROUP2
1e85591d 83 rmdir A1/A2/A3 A1/A2 A1 B1 > /dev/null 2>&1
1e85591d 84 rmdir test > /dev/null 2>&1
1bf33285
WL
85 [[ -n "$SCHED_DEBUG" ]] &&
86 echo "$SCHED_DEBUG" > /sys/kernel/debug/sched/verbose
1e85591d
KB
87}
88
a8c52eba
WL
89# Pause in ms
90pause()
91{
92 DELAY=$1
93 LOOP=0
94 while [[ $LOOP -lt $DELAY_FACTOR ]]
95 do
96 sleep $DELAY
97 ((LOOP++))
98 done
99 return 0
100}
101
102console_msg()
103{
104 MSG=$1
105 echo "$MSG"
106 echo "" > /dev/console
107 echo "$MSG" > /dev/console
108 pause 0.01
109}
110
111test_partition()
112{
113 EXPECTED_VAL=$1
114 echo $EXPECTED_VAL > cpuset.cpus.partition
115 [[ $? -eq 0 ]] || exit 1
116 ACTUAL_VAL=$(cat cpuset.cpus.partition)
117 [[ $ACTUAL_VAL != $EXPECTED_VAL ]] && {
105f3fe9 118 echo "cpuset.cpus.partition: expect $EXPECTED_VAL, found $ACTUAL_VAL"
a8c52eba
WL
119 echo "Test FAILED"
120 exit 1
121 }
122}
123
124test_effective_cpus()
125{
126 EXPECTED_VAL=$1
127 ACTUAL_VAL=$(cat cpuset.cpus.effective)
128 [[ "$ACTUAL_VAL" != "$EXPECTED_VAL" ]] && {
105f3fe9 129 echo "cpuset.cpus.effective: expect '$EXPECTED_VAL', found '$ACTUAL_VAL'"
a8c52eba
WL
130 echo "Test FAILED"
131 exit 1
132 }
133}
134
135# Adding current process to cgroup.procs as a test
136test_add_proc()
137{
138 OUTSTR="$1"
139 ERRMSG=$((echo $$ > cgroup.procs) |& cat)
140 echo $ERRMSG | grep -q "$OUTSTR"
141 [[ $? -ne 0 ]] && {
142 echo "cgroup.procs: expect '$OUTSTR', got '$ERRMSG'"
143 echo "Test FAILED"
144 exit 1
145 }
146 echo $$ > $CGROUP2/cgroup.procs # Move out the task
147}
148
a8c52eba
WL
149#
150# Cpuset controller state transition test matrix.
151#
152# Cgroup test hierarchy
153#
105f3fe9
WL
154# root -- A1 -- A2 -- A3
155# +- B1
a8c52eba 156#
105f3fe9 157# P<v> = set cpus.partition (0:member, 1:root, 2:isolated)
46c521ba
WL
158# C<l> = add cpu-list to cpuset.cpus
159# X<l> = add cpu-list to cpuset.cpus.exclusive
a8c52eba
WL
160# S<p> = use prefix in subtree_control
161# T = put a task into cgroup
105f3fe9 162# O<c>=<v> = Write <v> to CPU online file of <c>
a8c52eba
WL
163#
164SETUP_A123_PARTITIONS="C1-3:P1:S+ C2-3:P1:S+ C3:P1"
165TEST_MATRIX=(
105f3fe9
WL
166 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
167 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
168 " C0-1 . . C2-3 S+ C4-5 . . 0 A2:0-1"
169 " C0-1 . . C2-3 P1 . . . 0 "
170 " C0-1 . . C2-3 P1:S+ C0-1:P1 . . 0 "
171 " C0-1 . . C2-3 P1:S+ C1:P1 . . 0 "
172 " C0-1:S+ . . C2-3 . . . P1 0 "
173 " C0-1:P1 . . C2-3 S+ C1 . . 0 "
174 " C0-1:P1 . . C2-3 S+ C1:P1 . . 0 "
175 " C0-1:P1 . . C2-3 S+ C1:P1 . P1 0 "
176 " C0-1:P1 . . C2-3 C4-5 . . . 0 A1:4-5"
177 " C0-1:P1 . . C2-3 S+:C4-5 . . . 0 A1:4-5"
178 " C0-1 . . C2-3:P1 . . . C2 0 "
179 " C0-1 . . C2-3:P1 . . . C4-5 0 B1:4-5"
180 "C0-3:P1:S+ C2-3:P1 . . . . . . 0 A1:0-1,A2:2-3"
181 "C0-3:P1:S+ C2-3:P1 . . C1-3 . . . 0 A1:1,A2:2-3"
182 "C2-3:P1:S+ C3:P1 . . C3 . . . 0 A1:,A2:3 A1:P1,A2:P1"
183 "C2-3:P1:S+ C3:P1 . . C3 P0 . . 0 A1:3,A2:3 A1:P1,A2:P0"
184 "C2-3:P1:S+ C2:P1 . . C2-4 . . . 0 A1:3-4,A2:2"
185 "C2-3:P1:S+ C3:P1 . . C3 . . C0-2 0 A1:,B1:0-2 A1:P1,A2:P1"
186 "$SETUP_A123_PARTITIONS . C2-3 . . . 0 A1:,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
a8c52eba
WL
187
188 # CPU offlining cases:
105f3fe9
WL
189 " C0-1 . . C2-3 S+ C4-5 . O2=0 0 A1:0-1,B1:3"
190 "C0-3:P1:S+ C2-3:P1 . . O2=0 . . . 0 A1:0-1,A2:3"
191 "C0-3:P1:S+ C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1,A2:2-3"
192 "C0-3:P1:S+ C2-3:P1 . . O1=0 . . . 0 A1:0,A2:2-3"
193 "C0-3:P1:S+ C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1,A2:2-3"
194 "C2-3:P1:S+ C3:P1 . . O3=0 O3=1 . . 0 A1:2,A2:3 A1:P1,A2:P1"
195 "C2-3:P1:S+ C3:P2 . . O3=0 O3=1 . . 0 A1:2,A2:3 A1:P1,A2:P2"
196 "C2-3:P1:S+ C3:P1 . . O2=0 O2=1 . . 0 A1:2,A2:3 A1:P1,A2:P1"
197 "C2-3:P1:S+ C3:P2 . . O2=0 O2=1 . . 0 A1:2,A2:3 A1:P1,A2:P2"
198 "C2-3:P1:S+ C3:P1 . . O2=0 . . . 0 A1:,A2:3 A1:P1,A2:P1"
199 "C2-3:P1:S+ C3:P1 . . O3=0 . . . 0 A1:2,A2: A1:P1,A2:P1"
200 "C2-3:P1:S+ C3:P1 . . T:O2=0 . . . 0 A1:3,A2:3 A1:P1,A2:P-1"
201 "C2-3:P1:S+ C3:P1 . . . T:O3=0 . . 0 A1:2,A2:2 A1:P1,A2:P-1"
202 "$SETUP_A123_PARTITIONS . O1=0 . . . 0 A1:,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
203 "$SETUP_A123_PARTITIONS . O2=0 . . . 0 A1:1,A2:,A3:3 A1:P1,A2:P1,A3:P1"
204 "$SETUP_A123_PARTITIONS . O3=0 . . . 0 A1:1,A2:2,A3: A1:P1,A2:P1,A3:P1"
205 "$SETUP_A123_PARTITIONS . T:O1=0 . . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1"
206 "$SETUP_A123_PARTITIONS . . T:O2=0 . . 0 A1:1,A2:3,A3:3 A1:P1,A2:P1,A3:P-1"
207 "$SETUP_A123_PARTITIONS . . . T:O3=0 . 0 A1:1,A2:2,A3:2 A1:P1,A2:P1,A3:P-1"
208 "$SETUP_A123_PARTITIONS . T:O1=0 O1=1 . . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
209 "$SETUP_A123_PARTITIONS . . T:O2=0 O2=1 . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
210 "$SETUP_A123_PARTITIONS . . . T:O3=0 O3=1 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
211 "$SETUP_A123_PARTITIONS . T:O1=0 O2=0 O1=1 . 0 A1:1,A2:,A3:3 A1:P1,A2:P1,A3:P1"
212 "$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"
213
214 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
215 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
216 #
217 # Remote partition and cpuset.cpus.exclusive tests
218 #
219 " C0-3:S+ C1-3:S+ C2-3 . X2-3 . . . 0 A1:0-3,A2:1-3,A3:2-3,XA1:2-3"
220 " 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"
221 " 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"
222 " 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"
223 " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:C3 . 0 A1:0-2,A2:1-2,A3:3 A1:P0,A3:P2 3"
224 " 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"
225 " C0-3:S+ C1-3:S+ C2-3 C4-5 . . . P2 0 B1:4-5 B1:P2 4-5"
226 " 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"
227 " 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"
228 " 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"
229 " 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"
230
231 # Nested remote/local partition tests
232 " 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 \
233 A1:P0,A2:P1,A3:P2,B1:P1 2-3"
234 " 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 \
72c6303a 235 A1:P0,A2:P1,A3:P2,B1:P1 2-4,2-3"
105f3fe9 236 " 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 \
72c6303a 237 A1:P0,A2:P1,A3:P2,B1:P1 2-4,3"
105f3fe9 238 " C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1,A2:2-3,A3:4 \
72c6303a 239 A1:P0,A2:P2,A3:P1 2-4,2-3"
105f3fe9
WL
240 " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
241 . . X5 . . 0 A1:0-4,A2:1-4,A3:2-4 \
14060dfc 242 A1:P0,A2:P-2,A3:P-1"
105f3fe9
WL
243 " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
244 . . . X1 . 0 A1:0-1,A2:2-4,A3:2-4 \
245 A1:P0,A2:P2,A3:P-1 2-4"
246
247 # Remote partition offline tests
248 " 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"
249 " 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"
250 " 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"
72c6303a 251 " 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,"
105f3fe9
WL
252
253 # An invalidated remote partition cannot self-recover from hotplug
254 " 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"
255
256 # cpus.exclusive.effective clearing test
46c521ba 257 " C0-3:S+ C1-3:S+ C2 . X2-3:X . . . 0 A1:0-3,A2:1-3,A3:2,XA1:"
105f3fe9 258
46c521ba
WL
259 # Invalid to valid remote partition transition test
260 " C0-3:S+ C1-3 . . . X3:P2 . . 0 A1:0-3,A2:1-3,XA2: A2:P-2"
105f3fe9 261 " C0-3:S+ C1-3:X3:P2
46c521ba 262 . . X2-3 P2 . . 0 A1:0-2,A2:3,XA2:3 A2:P2 3"
105f3fe9
WL
263
264 # Invalid to valid local partition direct transition tests
46c521ba
WL
265 " C1-3:S+:P2 C2-3:X1:P2 . . . . . . 0 A1:1-3,XA1:1-3,A2:2-3:XA2: A1:P2,A2:P-2 1-3"
266 " C1-3:S+:P2 C2-3:X1:P2 . . . X3:P2 . . 0 A1:1-2,XA1:1-3,A2:3:XA2:3 A1:P2,A2:P2 1-3"
267 " C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4,B1:4-6 A1:P-2,B1:P0"
268 " C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3,B1:4-6 A1:P2,B1:P0 0-3"
269 " C0-3:P2 . . C3-5:C4-5 . . . . 0 A1:0-3,B1:4-5 A1:P2,B1:P0 0-3"
105f3fe9
WL
270
271 # Local partition invalidation tests
272 " C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
273 . . . . . 0 A1:1,A2:2,A3:3 A1:P2,A2:P2,A3:P2 1-3"
274 " C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
275 . . X4 . . 0 A1:1-3,A2:1-3,A3:2-3,XA2:,XA3: A1:P2,A2:P-2,A3:P-2 1-3"
276 " C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
277 . . C4 . . 0 A1:1-3,A2:1-3,A3:2-3,XA2:,XA3: A1:P2,A2:P-2,A3:P-2 1-3"
46c521ba
WL
278 # Local partition CPU change tests
279 " C0-5:S+:P2 C4-5:S+:P1 . . . C3-5 . . 0 A1:0-2,A2:3-5 A1:P2,A2:P1 0-2"
280 " C0-5:S+:P2 C4-5:S+:P1 . . C1-5 . . . 0 A1:1-3,A2:4-5 A1:P2,A2:P1 1-3"
105f3fe9
WL
281
282 # cpus_allowed/exclusive_cpus update tests
283 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
284 . C4 . P2 . 0 A1:4,A2:4,XA2:,XA3:,A3:4 \
14060dfc 285 A1:P0,A3:P-2"
105f3fe9
WL
286 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
287 . X1 . P2 . 0 A1:0-3,A2:1-3,XA1:1,XA2:,XA3:,A3:2-3 \
14060dfc 288 A1:P0,A3:P-2"
105f3fe9
WL
289 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
290 . . C3 P2 . 0 A1:0-2,A2:0-2,XA2:3,XA3:3,A3:3 \
291 A1:P0,A3:P2 3"
292 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
293 . . X3 P2 . 0 A1:0-2,A2:1-2,XA2:3,XA3:3,A3:3 \
294 A1:P0,A3:P2 3"
295 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
296 . . X3 . . 0 A1:0-3,A2:1-3,XA2:3,XA3:3,A3:2-3 \
14060dfc 297 A1:P0,A3:P-2"
105f3fe9
WL
298 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
299 . . C3 . . 0 A1:0-3,A2:3,XA2:3,XA3:3,A3:3 \
14060dfc 300 A1:P0,A3:P-2"
105f3fe9
WL
301 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
302 . C4 . . . 0 A1:4,A2:4,A3:4,XA1:,XA2:,XA3 \
14060dfc 303 A1:P0,A3:P-2"
105f3fe9
WL
304
305 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
306 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
a8c52eba
WL
307 #
308 # Incorrect change to cpuset.cpus invalidates partition root
309 #
310 # Adding CPUs to partition root that are not in parent's
311 # cpuset.cpus is allowed, but those extra CPUs are ignored.
105f3fe9 312 "C2-3:P1:S+ C3:P1 . . . C2-4 . . 0 A1:,A2:2-3 A1:P1,A2:P1"
a8c52eba
WL
313
314 # Taking away all CPUs from parent or itself if there are tasks
315 # will make the partition invalid.
105f3fe9
WL
316 "C2-3:P1:S+ C3:P1 . . T C2-3 . . 0 A1:2-3,A2:2-3 A1:P1,A2:P-1"
317 " C3:P1:S+ C3 . . T P1 . . 0 A1:3,A2:3 A1:P1,A2:P-1"
318 "$SETUP_A123_PARTITIONS . T:C2-3 . . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1"
319 "$SETUP_A123_PARTITIONS . T:C2-3:C1-3 . . . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
a8c52eba
WL
320
321 # Changing a partition root to member makes child partitions invalid
105f3fe9
WL
322 "C2-3:P1:S+ C3:P1 . . P0 . . . 0 A1:2-3,A2:3 A1:P0,A2:P-1"
323 "$SETUP_A123_PARTITIONS . C2-3 P0 . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P0,A3:P-1"
a8c52eba
WL
324
325 # cpuset.cpus can contains cpus not in parent's cpuset.cpus as long
326 # as they overlap.
105f3fe9 327 "C2-3:P1:S+ . . . . C3-4:P1 . . 0 A1:2,A2:3 A1:P1,A2:P1"
a8c52eba
WL
328
329 # Deletion of CPUs distributed to child cgroup is allowed.
105f3fe9 330 "C0-1:P1:S+ C1 . C2-3 C4-5 . . . 0 A1:4-5,A2:4-5"
a8c52eba
WL
331
332 # To become a valid partition root, cpuset.cpus must overlap parent's
333 # cpuset.cpus.
105f3fe9 334 " C0-1:P1 . . C2-3 S+ C4-5:P1 . . 0 A1:0-1,A2:0-1 A1:P1,A2:P-1"
a8c52eba
WL
335
336 # Enabling partition with child cpusets is allowed
105f3fe9 337 " C0-1:S+ C1 . C2-3 P1 . . . 0 A1:0-1,A2:1 A1:P1"
a8c52eba
WL
338
339 # A partition root with non-partition root parent is invalid, but it
340 # can be made valid if its parent becomes a partition root too.
105f3fe9
WL
341 " C0-1:S+ C1 . C2-3 . P2 . . 0 A1:0-1,A2:1 A1:P0,A2:P-2"
342 " C0-1:S+ C1:P2 . C2-3 P1 . . . 0 A1:0,A2:1 A1:P1,A2:P2"
a8c52eba
WL
343
344 # A non-exclusive cpuset.cpus change will invalidate partition and its siblings
105f3fe9
WL
345 " C0-1:P1 . . C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P-1,B1:P0"
346 " C0-1:P1 . . P1:C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P-1,B1:P-1"
347 " C0-1 . . P1:C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P0,B1:P-1"
a8c52eba 348
105f3fe9
WL
349 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
350 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
a8c52eba
WL
351 # Failure cases:
352
353 # A task cannot be added to a partition with no cpu
105f3fe9
WL
354 "C2-3:P1:S+ C3:P1 . . O2=0:T . . . 1 A1:,A2:3 A1:P1,A2:P1"
355
356 # Changes to cpuset.cpus.exclusive that violate exclusivity rule is rejected
357 " C0-3 . . C4-5 X0-3 . . X3-5 1 A1:0-3,B1:4-5"
a8c52eba
WL
358)
359
360#
361# Write to the cpu online file
105f3fe9 362# $1 - <c>=<v> where <c> = cpu number, <v> value to be written
a8c52eba
WL
363#
364write_cpu_online()
365{
105f3fe9
WL
366 CPU=${1%=*}
367 VAL=${1#*=}
a8c52eba
WL
368 CPUFILE=//sys/devices/system/cpu/cpu${CPU}/online
369 if [[ $VAL -eq 0 ]]
370 then
371 OFFLINE_CPUS="$OFFLINE_CPUS $CPU"
372 else
373 [[ -n "$OFFLINE_CPUS" ]] && {
374 OFFLINE_CPUS=$(echo $CPU $CPU $OFFLINE_CPUS | fmt -1 |\
375 sort | uniq -u)
376 }
377 fi
378 echo $VAL > $CPUFILE
72c6303a 379 pause 0.05
a8c52eba
WL
380}
381
382#
383# Set controller state
384# $1 - cgroup directory
385# $2 - state
386# $3 - showerr
387#
388# The presence of ":" in state means transition from one to the next.
389#
390set_ctrl_state()
391{
392 TMPMSG=/tmp/.msg_$$
393 CGRP=$1
394 STATE=$2
105f3fe9 395 SHOWERR=${3}
a8c52eba
WL
396 CTRL=${CTRL:=$CONTROLLER}
397 HASERR=0
398 REDIRECT="2> $TMPMSG"
399 [[ -z "$STATE" || "$STATE" = '.' ]] && return 0
105f3fe9 400 [[ $VERBOSE -gt 0 ]] && SHOWERR=1
a8c52eba
WL
401
402 rm -f $TMPMSG
403 for CMD in $(echo $STATE | sed -e "s/:/ /g")
404 do
405 TFILE=$CGRP/cgroup.procs
406 SFILE=$CGRP/cgroup.subtree_control
407 PFILE=$CGRP/cpuset.cpus.partition
408 CFILE=$CGRP/cpuset.cpus
105f3fe9 409 XFILE=$CGRP/cpuset.cpus.exclusive
a8c52eba
WL
410 S=$(expr substr $CMD 1 1)
411 if [[ $S = S ]]
412 then
413 PREFIX=${CMD#?}
414 COMM="echo ${PREFIX}${CTRL} > $SFILE"
415 eval $COMM $REDIRECT
105f3fe9
WL
416 elif [[ $S = X ]]
417 then
418 CPUS=${CMD#?}
419 COMM="echo $CPUS > $XFILE"
420 eval $COMM $REDIRECT
a8c52eba
WL
421 elif [[ $S = C ]]
422 then
423 CPUS=${CMD#?}
424 COMM="echo $CPUS > $CFILE"
425 eval $COMM $REDIRECT
426 elif [[ $S = P ]]
427 then
428 VAL=${CMD#?}
429 case $VAL in
430 0) VAL=member
431 ;;
432 1) VAL=root
433 ;;
434 2) VAL=isolated
435 ;;
436 *)
437 echo "Invalid partition state - $VAL"
438 exit 1
439 ;;
440 esac
441 COMM="echo $VAL > $PFILE"
442 eval $COMM $REDIRECT
443 elif [[ $S = O ]]
444 then
445 VAL=${CMD#?}
446 write_cpu_online $VAL
447 elif [[ $S = T ]]
448 then
449 COMM="echo 0 > $TFILE"
450 eval $COMM $REDIRECT
451 fi
452 RET=$?
453 [[ $RET -ne 0 ]] && {
454 [[ -n "$SHOWERR" ]] && {
455 echo "$COMM"
456 cat $TMPMSG
457 }
458 HASERR=1
459 }
460 pause 0.01
461 rm -f $TMPMSG
462 done
463 return $HASERR
464}
465
466set_ctrl_state_noerr()
467{
468 CGRP=$1
469 STATE=$2
470 [[ -d $CGRP ]] || mkdir $CGRP
471 set_ctrl_state $CGRP $STATE 1
472 [[ $? -ne 0 ]] && {
473 echo "ERROR: Failed to set $2 to cgroup $1!"
474 exit 1
475 }
476}
477
478online_cpus()
479{
480 [[ -n "OFFLINE_CPUS" ]] && {
481 for C in $OFFLINE_CPUS
482 do
105f3fe9 483 write_cpu_online ${C}=1
a8c52eba
WL
484 done
485 }
486}
487
488#
489# Return 1 if the list of effective cpus isn't the same as the initial list.
490#
491reset_cgroup_states()
492{
493 echo 0 > $CGROUP2/cgroup.procs
494 online_cpus
495 rmdir A1/A2/A3 A1/A2 A1 B1 > /dev/null 2>&1
105f3fe9
WL
496 pause 0.02
497 set_ctrl_state . R-
a8c52eba
WL
498 pause 0.01
499}
500
501dump_states()
502{
105f3fe9 503 for DIR in . A1 A1/A2 A1/A2/A3 B1
a8c52eba 504 do
105f3fe9 505 CPUS=$DIR/cpuset.cpus
a8c52eba 506 ECPUS=$DIR/cpuset.cpus.effective
105f3fe9
WL
507 XCPUS=$DIR/cpuset.cpus.exclusive
508 XECPUS=$DIR/cpuset.cpus.exclusive.effective
a8c52eba 509 PRS=$DIR/cpuset.cpus.partition
105f3fe9 510 PCPUS=$DIR/.__DEBUG__.cpuset.cpus.subpartitions
877c737d 511 ISCPUS=$DIR/cpuset.cpus.isolated
105f3fe9
WL
512 [[ -e $CPUS ]] && echo "$CPUS: $(cat $CPUS)"
513 [[ -e $XCPUS ]] && echo "$XCPUS: $(cat $XCPUS)"
514 [[ -e $ECPUS ]] && echo "$ECPUS: $(cat $ECPUS)"
515 [[ -e $XECPUS ]] && echo "$XECPUS: $(cat $XECPUS)"
516 [[ -e $PRS ]] && echo "$PRS: $(cat $PRS)"
517 [[ -e $PCPUS ]] && echo "$PCPUS: $(cat $PCPUS)"
72c6303a 518 [[ -e $ISCPUS ]] && echo "$ISCPUS: $(cat $ISCPUS)"
a8c52eba
WL
519 done
520}
521
522#
523# Check effective cpus
524# $1 - check string, format: <cgroup>:<cpu-list>[,<cgroup>:<cpu-list>]*
525#
526check_effective_cpus()
527{
528 CHK_STR=$1
529 for CHK in $(echo $CHK_STR | sed -e "s/,/ /g")
530 do
531 set -- $(echo $CHK | sed -e "s/:/ /g")
532 CGRP=$1
533 CPUS=$2
105f3fe9
WL
534 if [[ $CGRP = X* ]]
535 then
536 CGRP=${CGRP#X}
537 FILE=cpuset.cpus.exclusive.effective
538 else
539 FILE=cpuset.cpus.effective
540 fi
a8c52eba
WL
541 [[ $CGRP = A2 ]] && CGRP=A1/A2
542 [[ $CGRP = A3 ]] && CGRP=A1/A2/A3
105f3fe9
WL
543 [[ -e $CGRP/$FILE ]] || return 1
544 [[ $CPUS = $(cat $CGRP/$FILE) ]] || return 1
a8c52eba
WL
545 done
546}
547
548#
549# Check cgroup states
550# $1 - check string, format: <cgroup>:<state>[,<cgroup>:<state>]*
551#
552check_cgroup_states()
553{
554 CHK_STR=$1
555 for CHK in $(echo $CHK_STR | sed -e "s/,/ /g")
556 do
557 set -- $(echo $CHK | sed -e "s/:/ /g")
558 CGRP=$1
559 STATE=$2
560 FILE=
561 EVAL=$(expr substr $STATE 2 2)
562 [[ $CGRP = A2 ]] && CGRP=A1/A2
563 [[ $CGRP = A3 ]] && CGRP=A1/A2/A3
564
565 case $STATE in
566 P*) FILE=$CGRP/cpuset.cpus.partition
567 ;;
568 *) echo "Unknown state: $STATE!"
569 exit 1
570 ;;
571 esac
572 VAL=$(cat $FILE)
573
574 case "$VAL" in
575 member) VAL=0
576 ;;
577 root) VAL=1
578 ;;
579 isolated)
580 VAL=2
581 ;;
582 "root invalid"*)
583 VAL=-1
584 ;;
585 "isolated invalid"*)
586 VAL=-2
587 ;;
588 esac
589 [[ $EVAL != $VAL ]] && return 1
590 done
591 return 0
592}
593
105f3fe9
WL
594#
595# Get isolated (including offline) CPUs by looking at
877c737d 596# /sys/kernel/debug/sched/domains and cpuset.cpus.isolated control file,
72c6303a 597# if available, and compare that with the expected value.
105f3fe9 598#
72c6303a
WL
599# Note that isolated CPUs from the sched/domains context include offline
600# CPUs as well as CPUs in non-isolated 1-CPU partition. Those CPUs may
877c737d 601# not be included in the cpuset.cpus.isolated control file which contains
72c6303a 602# only CPUs in isolated partitions.
105f3fe9 603#
72c6303a
WL
604# $1 - expected isolated cpu list(s) <isolcpus1>{,<isolcpus2>}
605# <isolcpus1> - expected sched/domains value
877c737d 606# <isolcpus2> - cpuset.cpus.isolated value = <isolcpus1> if not defined
105f3fe9
WL
607#
608check_isolcpus()
609{
610 EXPECT_VAL=$1
611 ISOLCPUS=
612 LASTISOLCPU=
613 SCHED_DOMAINS=/sys/kernel/debug/sched/domains
877c737d 614 ISCPUS=${CGROUP2}/cpuset.cpus.isolated
72c6303a
WL
615 if [[ $EXPECT_VAL = . ]]
616 then
617 EXPECT_VAL=
618 EXPECT_VAL2=
619 elif [[ $(expr $EXPECT_VAL : ".*,.*") > 0 ]]
620 then
621 set -- $(echo $EXPECT_VAL | sed -e "s/,/ /g")
622 EXPECT_VAL=$1
623 EXPECT_VAL2=$2
624 else
625 EXPECT_VAL2=$EXPECT_VAL
626 fi
627
628 #
629 # Check the debug isolated cpumask, if present
630 #
631 [[ -f $ISCPUS ]] && {
632 ISOLCPUS=$(cat $ISCPUS)
633 [[ "$EXPECT_VAL2" != "$ISOLCPUS" ]] && {
634 # Take a 50ms pause and try again
635 pause 0.05
636 ISOLCPUS=$(cat $ISCPUS)
637 }
638 [[ "$EXPECT_VAL2" != "$ISOLCPUS" ]] && return 1
639 ISOLCPUS=
640 }
641
642 #
643 # Use the sched domain in debugfs to check isolated CPUs, if available
644 #
105f3fe9 645 [[ -d $SCHED_DOMAINS ]] || return 0
105f3fe9
WL
646
647 for ((CPU=0; CPU < $NR_CPUS; CPU++))
648 do
649 [[ -n "$(ls ${SCHED_DOMAINS}/cpu$CPU)" ]] && continue
650
651 if [[ -z "$LASTISOLCPU" ]]
652 then
653 ISOLCPUS=$CPU
654 LASTISOLCPU=$CPU
655 elif [[ "$LASTISOLCPU" -eq $((CPU - 1)) ]]
656 then
657 echo $ISOLCPUS | grep -q "\<$LASTISOLCPU\$"
658 if [[ $? -eq 0 ]]
659 then
660 ISOLCPUS=${ISOLCPUS}-
661 fi
662 LASTISOLCPU=$CPU
663 else
664 if [[ $ISOLCPUS = *- ]]
665 then
666 ISOLCPUS=${ISOLCPUS}$LASTISOLCPU
667 fi
668 ISOLCPUS=${ISOLCPUS},$CPU
669 LASTISOLCPU=$CPU
670 fi
671 done
672 [[ "$ISOLCPUS" = *- ]] && ISOLCPUS=${ISOLCPUS}$LASTISOLCPU
673 [[ "$EXPECT_VAL" = "$ISOLCPUS" ]]
674}
675
676test_fail()
677{
678 TESTNUM=$1
679 TESTTYPE=$2
680 ADDINFO=$3
681 echo "Test $TEST[$TESTNUM] failed $TESTTYPE check!"
682 [[ -n "$ADDINFO" ]] && echo "*** $ADDINFO ***"
683 eval echo \${$TEST[$I]}
684 echo
685 dump_states
686 exit 1
687}
688
72c6303a
WL
689#
690# Check to see if there are unexpected isolated CPUs left
691#
692null_isolcpus_check()
693{
694 [[ $VERBOSE -gt 0 ]] || return 0
877c737d
WL
695 # Retry a few times before printing error
696 RETRY=0
697 while [[ $RETRY -lt 5 ]]
698 do
699 pause 0.01
700 check_isolcpus "."
701 [[ $? -eq 0 ]] && return 0
702 ((RETRY++))
703 done
704 echo "Unexpected isolated CPUs: $ISOLCPUS"
705 dump_states
706 exit 1
72c6303a
WL
707}
708
a8c52eba
WL
709#
710# Run cpuset state transition test
711# $1 - test matrix name
712#
713# This test is somewhat fragile as delays (sleep x) are added in various
714# places to make sure state changes are fully propagated before the next
715# action. These delays may need to be adjusted if running in a slower machine.
716#
717run_state_test()
718{
719 TEST=$1
720 CONTROLLER=cpuset
a8c52eba
WL
721 I=0
722 eval CNT="\${#$TEST[@]}"
723
724 reset_cgroup_states
a8c52eba
WL
725 console_msg "Running state transition test ..."
726
727 while [[ $I -lt $CNT ]]
728 do
729 echo "Running test $I ..." > /dev/console
105f3fe9
WL
730 [[ $VERBOSE -gt 1 ]] && {
731 echo ""
732 eval echo \${$TEST[$I]}
733 }
a8c52eba 734 eval set -- "\${$TEST[$I]}"
105f3fe9
WL
735 OLD_A1=$1
736 OLD_A2=$2
737 OLD_A3=$3
738 OLD_B1=$4
739 NEW_A1=$5
740 NEW_A2=$6
741 NEW_A3=$7
742 NEW_B1=$8
743 RESULT=$9
744 ECPUS=${10}
745 STATES=${11}
746 ICPUS=${12}
747
748 set_ctrl_state_noerr B1 $OLD_B1
a8c52eba
WL
749 set_ctrl_state_noerr A1 $OLD_A1
750 set_ctrl_state_noerr A1/A2 $OLD_A2
751 set_ctrl_state_noerr A1/A2/A3 $OLD_A3
a8c52eba
WL
752 RETVAL=0
753 set_ctrl_state A1 $NEW_A1; ((RETVAL += $?))
754 set_ctrl_state A1/A2 $NEW_A2; ((RETVAL += $?))
755 set_ctrl_state A1/A2/A3 $NEW_A3; ((RETVAL += $?))
756 set_ctrl_state B1 $NEW_B1; ((RETVAL += $?))
757
105f3fe9 758 [[ $RETVAL -ne $RESULT ]] && test_fail $I result
a8c52eba
WL
759
760 [[ -n "$ECPUS" && "$ECPUS" != . ]] && {
761 check_effective_cpus $ECPUS
105f3fe9 762 [[ $? -ne 0 ]] && test_fail $I "effective CPU"
a8c52eba
WL
763 }
764
105f3fe9 765 [[ -n "$STATES" && "$STATES" != . ]] && {
a8c52eba 766 check_cgroup_states $STATES
105f3fe9 767 [[ $? -ne 0 ]] && test_fail $I states
a8c52eba
WL
768 }
769
105f3fe9
WL
770 # Compare the expected isolated CPUs with the actual ones,
771 # if available
772 [[ -n "$ICPUS" ]] && {
773 check_isolcpus $ICPUS
774 [[ $? -ne 0 ]] && test_fail $I "isolated CPU" \
775 "Expect $ICPUS, get $ISOLCPUS instead"
776 }
a8c52eba
WL
777 reset_cgroup_states
778 #
779 # Check to see if effective cpu list changes
780 #
a8c52eba 781 NEWLIST=$(cat cpuset.cpus.effective)
105f3fe9 782 RETRY=0
877c737d 783 while [[ $NEWLIST != $CPULIST && $RETRY -lt 8 ]]
105f3fe9
WL
784 do
785 # Wait a bit longer & recheck a few times
786 pause 0.01
787 ((RETRY++))
788 NEWLIST=$(cat cpuset.cpus.effective)
789 done
a8c52eba
WL
790 [[ $NEWLIST != $CPULIST ]] && {
791 echo "Effective cpus changed to $NEWLIST after test $I!"
792 exit 1
793 }
72c6303a 794 null_isolcpus_check
105f3fe9 795 [[ $VERBOSE -gt 0 ]] && echo "Test $I done."
a8c52eba
WL
796 ((I++))
797 done
798 echo "All $I tests of $TEST PASSED."
a8c52eba
WL
799}
800
14060dfc
WL
801#
802# Testing the new "isolated" partition root type
803#
804test_isolated()
805{
806 cd $CGROUP2/test
807 echo 2-3 > cpuset.cpus
808 TYPE=$(cat cpuset.cpus.partition)
809 [[ $TYPE = member ]] || echo member > cpuset.cpus.partition
810
811 console_msg "Change from member to root"
812 test_partition root
813
814 console_msg "Change from root to isolated"
815 test_partition isolated
816
817 console_msg "Change from isolated to member"
818 test_partition member
819
820 console_msg "Change from member to isolated"
821 test_partition isolated
822
823 console_msg "Change from isolated to root"
824 test_partition root
825
826 console_msg "Change from root to member"
827 test_partition member
828
829 #
830 # Testing partition root with no cpu
831 #
832 console_msg "Distribute all cpus to child partition"
833 echo +cpuset > cgroup.subtree_control
834 test_partition root
835
836 mkdir A1
837 cd A1
838 echo 2-3 > cpuset.cpus
839 test_partition root
840 test_effective_cpus 2-3
841 cd ..
842 test_effective_cpus ""
843
844 console_msg "Moving task to partition test"
845 test_add_proc "No space left"
846 cd A1
847 test_add_proc ""
848 cd ..
849
850 console_msg "Shrink and expand child partition"
851 cd A1
852 echo 2 > cpuset.cpus
853 cd ..
854 test_effective_cpus 3
855 cd A1
856 echo 2-3 > cpuset.cpus
857 cd ..
858 test_effective_cpus ""
859
860 # Cleaning up
861 console_msg "Cleaning up"
862 echo $$ > $CGROUP2/cgroup.procs
863 [[ -d A1 ]] && rmdir A1
72c6303a 864 null_isolcpus_check
14060dfc
WL
865}
866
a8c52eba
WL
867#
868# Wait for inotify event for the given file and read it
869# $1: cgroup file to wait for
870# $2: file to store the read result
871#
872wait_inotify()
873{
874 CGROUP_FILE=$1
875 OUTPUT_FILE=$2
876
877 $WAIT_INOTIFY $CGROUP_FILE
878 cat $CGROUP_FILE > $OUTPUT_FILE
879}
880
881#
882# Test if inotify events are properly generated when going into and out of
883# invalid partition state.
884#
885test_inotify()
886{
887 ERR=0
888 PRS=/tmp/.prs_$$
105f3fe9 889 cd $CGROUP2/test
a8c52eba
WL
890 [[ -f $WAIT_INOTIFY ]] || {
891 echo "wait_inotify not found, inotify test SKIPPED."
892 return
893 }
894
895 pause 0.01
896 echo 1 > cpuset.cpus
897 echo 0 > cgroup.procs
898 echo root > cpuset.cpus.partition
899 pause 0.01
900 rm -f $PRS
901 wait_inotify $PWD/cpuset.cpus.partition $PRS &
902 pause 0.01
105f3fe9 903 set_ctrl_state . "O1=0"
a8c52eba
WL
904 pause 0.01
905 check_cgroup_states ".:P-1"
906 if [[ $? -ne 0 ]]
907 then
908 echo "FAILED: Inotify test - partition not invalid"
909 ERR=1
910 elif [[ ! -f $PRS ]]
911 then
912 echo "FAILED: Inotify test - event not generated"
913 ERR=1
914 kill %1
915 elif [[ $(cat $PRS) != "root invalid"* ]]
916 then
917 echo "FAILED: Inotify test - incorrect state"
918 cat $PRS
919 ERR=1
920 fi
921 online_cpus
922 echo member > cpuset.cpus.partition
923 echo 0 > ../cgroup.procs
924 if [[ $ERR -ne 0 ]]
925 then
926 exit 1
927 else
928 echo "Inotify test PASSED"
929 fi
930}
931
1e85591d 932trap cleanup 0 2 3 6
a8c52eba
WL
933run_state_test TEST_MATRIX
934test_isolated
935test_inotify
936echo "All tests PASSED."