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