2 # SPDX-License-Identifier: GPL-2.0
4 # Test for cpuset v2 partition root state (PRS)
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.
16 [[ $
(id
-u) -eq 0 ]] || skip_test
"Test must be run as root!"
19 # Get wait_inotify location
20 WAIT_INOTIFY
=$
(cd $
(dirname $0); pwd)/wait_inotify
22 # Find cgroup v2 mount point
23 CGROUP2
=$
(mount
-t cgroup2 |
head -1 |
awk -e '{print $3}')
24 [[ -n "$CGROUP2" ]] || skip_test
"Cgroup v2 mount point not found!"
25 SUBPARTS_CPUS
=$CGROUP2/.__DEBUG__.cpuset.cpus.subpartitions
26 CPULIST
=$
(cat $CGROUP2/cpuset.cpus.effective
)
28 NR_CPUS
=$
(lscpu |
grep "^CPU(s):" |
sed -e "s/.*:[[:space:]]*//")
29 [[ $NR_CPUS -lt 8 ]] && skip_test
"Test needs at least 8 cpus available!"
31 # Check to see if /dev/console exists and is writable
32 if [[ -c /dev
/console
&& -w /dev
/console
]]
39 # Set verbose flag and delay factor
48 # Enable sched/verbose can slow thing down
49 [[ $DELAY_FACTOR -eq 1 ]] &&
55 *) echo "Usage: $PROG [-v] [-d <delay-factor>"
62 # Set sched verbose flag if available when "-v" option is specified
63 if [[ $VERBOSE -gt 0 && -d /sys
/kernel
/debug
/sched
]]
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
71 echo +cpuset
> cgroup.subtree_control
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.
78 [[ -d test ]] || mkdir
test
79 echo 0-6 > test
/cpuset.cpus
80 echo root
> test
/cpuset.cpus.partition
81 cat test
/cpuset.cpus.partition |
grep -q invalid
83 echo member
> test
/cpuset.cpus.partition
84 echo "" > test
/cpuset.cpus
85 [[ $RESULT -eq 0 ]] && skip_test
"Child cgroups are using cpuset!"
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-7
90 # that will be used by this script for testing purpose. If not, some of
91 # the tests may fail incorrectly. These isolated CPUs will also be removed
92 # before being compared with the expected results.
94 BOOT_ISOLCPUS
=$
(cat $CGROUP2/cpuset.cpus.isolated
)
95 if [[ -n "$BOOT_ISOLCPUS" ]]
97 [[ $
(echo $BOOT_ISOLCPUS |
sed -e "s/[,-].*//") -le 7 ]] &&
98 skip_test
"Pre-isolated CPUs ($BOOT_ISOLCPUS) overlap CPUs to be tested"
99 echo "Pre-isolated CPUs: $BOOT_ISOLCPUS"
105 rmdir A
1/A
2/A3 A
1/A2 A1 B1
> /dev
/null
2>&1
106 rmdir test > /dev
/null
2>&1
107 [[ -n "$SCHED_DEBUG" ]] &&
108 echo "$SCHED_DEBUG" > /sys
/kernel
/debug
/sched
/verbose
116 while [[ $LOOP -lt $DELAY_FACTOR ]]
129 echo "$MSG" > $CONSOLE
136 echo $EXPECTED_VAL > cpuset.cpus.partition
137 [[ $?
-eq 0 ]] ||
exit 1
138 ACTUAL_VAL
=$
(cat cpuset.cpus.partition
)
139 [[ $ACTUAL_VAL != $EXPECTED_VAL ]] && {
140 echo "cpuset.cpus.partition: expect $EXPECTED_VAL, found $ACTUAL_VAL"
146 test_effective_cpus
()
149 ACTUAL_VAL
=$
(cat cpuset.cpus.effective
)
150 [[ "$ACTUAL_VAL" != "$EXPECTED_VAL" ]] && {
151 echo "cpuset.cpus.effective: expect '$EXPECTED_VAL', found '$ACTUAL_VAL'"
157 # Adding current process to cgroup.procs as a test
161 ERRMSG
=$
((echo $$
> cgroup.procs
) |
& cat)
162 echo $ERRMSG |
grep -q "$OUTSTR"
164 echo "cgroup.procs: expect '$OUTSTR', got '$ERRMSG'"
168 echo $$
> $CGROUP2/cgroup.procs
# Move out the task
172 # Cpuset controller state transition test matrix.
174 # Cgroup test hierarchy
176 # root -- A1 -- A2 -- A3
179 # P<v> = set cpus.partition (0:member, 1:root, 2:isolated)
180 # C<l> = add cpu-list to cpuset.cpus
181 # X<l> = add cpu-list to cpuset.cpus.exclusive
182 # S<p> = use prefix in subtree_control
183 # T = put a task into cgroup
184 # O<c>=<v> = Write <v> to CPU online file of <c>
186 # ECPUs - effective CPUs of cpusets
187 # Pstate - partition root state
188 # ISOLCPUS - isolated CPUs (<icpus>[,<icpus2>])
190 # Note that if there are 2 fields in ISOLCPUS, the first one is for
191 # sched-debug matching which includes offline CPUs and single-CPU partitions
192 # while the second one is for matching cpuset.cpus.isolated.
194 SETUP_A123_PARTITIONS
="C1-3:P1:S+ C2-3:P1:S+ C3:P1"
196 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
197 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
198 " C0-1 . . C2-3 S+ C4-5 . . 0 A2:0-1"
199 " C0-1 . . C2-3 P1 . . . 0 "
200 " C0-1 . . C2-3 P1:S+ C0-1:P1 . . 0 "
201 " C0-1 . . C2-3 P1:S+ C1:P1 . . 0 "
202 " C0-1:S+ . . C2-3 . . . P1 0 "
203 " C0-1:P1 . . C2-3 S+ C1 . . 0 "
204 " C0-1:P1 . . C2-3 S+ C1:P1 . . 0 "
205 " C0-1:P1 . . C2-3 S+ C1:P1 . P1 0 "
206 " C0-1:P1 . . C2-3 C4-5 . . . 0 A1:4-5"
207 " C0-1:P1 . . C2-3 S+:C4-5 . . . 0 A1:4-5"
208 " C0-1 . . C2-3:P1 . . . C2 0 "
209 " C0-1 . . C2-3:P1 . . . C4-5 0 B1:4-5"
210 "C0-3:P1:S+ C2-3:P1 . . . . . . 0 A1:0-1,A2:2-3"
211 "C0-3:P1:S+ C2-3:P1 . . C1-3 . . . 0 A1:1,A2:2-3"
212 "C2-3:P1:S+ C3:P1 . . C3 . . . 0 A1:,A2:3 A1:P1,A2:P1"
213 "C2-3:P1:S+ C3:P1 . . C3 P0 . . 0 A1:3,A2:3 A1:P1,A2:P0"
214 "C2-3:P1:S+ C2:P1 . . C2-4 . . . 0 A1:3-4,A2:2"
215 "C2-3:P1:S+ C3:P1 . . C3 . . C0-2 0 A1:,B1:0-2 A1:P1,A2:P1"
216 "$SETUP_A123_PARTITIONS . C2-3 . . . 0 A1:,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
218 # CPU offlining cases:
219 " C0-1 . . C2-3 S+ C4-5 . O2=0 0 A1:0-1,B1:3"
220 "C0-3:P1:S+ C2-3:P1 . . O2=0 . . . 0 A1:0-1,A2:3"
221 "C0-3:P1:S+ C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1,A2:2-3"
222 "C0-3:P1:S+ C2-3:P1 . . O1=0 . . . 0 A1:0,A2:2-3"
223 "C0-3:P1:S+ C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1,A2:2-3"
224 "C2-3:P1:S+ C3:P1 . . O3=0 O3=1 . . 0 A1:2,A2:3 A1:P1,A2:P1"
225 "C2-3:P1:S+ C3:P2 . . O3=0 O3=1 . . 0 A1:2,A2:3 A1:P1,A2:P2"
226 "C2-3:P1:S+ C3:P1 . . O2=0 O2=1 . . 0 A1:2,A2:3 A1:P1,A2:P1"
227 "C2-3:P1:S+ C3:P2 . . O2=0 O2=1 . . 0 A1:2,A2:3 A1:P1,A2:P2"
228 "C2-3:P1:S+ C3:P1 . . O2=0 . . . 0 A1:,A2:3 A1:P1,A2:P1"
229 "C2-3:P1:S+ C3:P1 . . O3=0 . . . 0 A1:2,A2: A1:P1,A2:P1"
230 "C2-3:P1:S+ C3:P1 . . T:O2=0 . . . 0 A1:3,A2:3 A1:P1,A2:P-1"
231 "C2-3:P1:S+ C3:P1 . . . T:O3=0 . . 0 A1:2,A2:2 A1:P1,A2:P-1"
232 "$SETUP_A123_PARTITIONS . O1=0 . . . 0 A1:,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
233 "$SETUP_A123_PARTITIONS . O2=0 . . . 0 A1:1,A2:,A3:3 A1:P1,A2:P1,A3:P1"
234 "$SETUP_A123_PARTITIONS . O3=0 . . . 0 A1:1,A2:2,A3: A1:P1,A2:P1,A3:P1"
235 "$SETUP_A123_PARTITIONS . T:O1=0 . . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1"
236 "$SETUP_A123_PARTITIONS . . T:O2=0 . . 0 A1:1,A2:3,A3:3 A1:P1,A2:P1,A3:P-1"
237 "$SETUP_A123_PARTITIONS . . . T:O3=0 . 0 A1:1,A2:2,A3:2 A1:P1,A2:P1,A3:P-1"
238 "$SETUP_A123_PARTITIONS . T:O1=0 O1=1 . . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
239 "$SETUP_A123_PARTITIONS . . T:O2=0 O2=1 . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
240 "$SETUP_A123_PARTITIONS . . . T:O3=0 O3=1 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
241 "$SETUP_A123_PARTITIONS . T:O1=0 O2=0 O1=1 . 0 A1:1,A2:,A3:3 A1:P1,A2:P1,A3:P1"
242 "$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"
244 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
245 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
247 # Remote partition and cpuset.cpus.exclusive tests
249 " C0-3:S+ C1-3:S+ C2-3 . X2-3 . . . 0 A1:0-3,A2:1-3,A3:2-3,XA1:2-3"
250 " 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"
251 " 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"
252 " 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"
253 " 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"
254 " 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"
255 " C0-3:S+ C1-3:S+ C2-3 C4-5 . . . P2 0 B1:4-5 B1:P2 4-5"
256 " 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"
257 " 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"
258 " 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"
259 " 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"
260 " C4:X0-3:S+ X1-3:S+ X2-3 . . P2 . . 0 A1:4,A2:1-3,A3:1-3 A2:P2 1-3"
261 " C4:X0-3:S+ X1-3:S+ X2-3 . . . P2 . 0 A1:4,A2:4,A3:2-3 A3:P2 2-3"
263 # Nested remote/local partition tests
264 " 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 \
265 A1:P0,A2:P1,A3:P2,B1:P1 2-3"
266 " 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 \
267 A1:P0,A2:P1,A3:P2,B1:P1 2-4,2-3"
268 " 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 \
269 A1:P0,A2:P1,A3:P0,B1:P1"
270 " 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 \
271 A1:P0,A2:P1,A3:P2,B1:P1 2-4,3"
272 " C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1,A2:2-3,A3:4 \
273 A1:P0,A2:P2,A3:P1 2-4,2-3"
274 " 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 \
276 " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
277 . . X5 . . 0 A1:0-4,A2:1-4,A3:2-4 \
279 " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
280 . . . X1 . 0 A1:0-1,A2:2-4,A3:2-4 \
281 A1:P0,A2:P2,A3:P-1 2-4"
283 # Remote partition offline tests
284 " 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"
285 " 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"
286 " 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"
287 " 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,"
289 # An invalidated remote partition cannot self-recover from hotplug
290 " 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"
292 # cpus.exclusive.effective clearing test
293 " C0-3:S+ C1-3:S+ C2 . X2-3:X . . . 0 A1:0-3,A2:1-3,A3:2,XA1:"
295 # Invalid to valid remote partition transition test
296 " C0-3:S+ C1-3 . . . X3:P2 . . 0 A1:0-3,A2:1-3,XA2: A2:P-2"
298 . . X2-3 P2 . . 0 A1:0-2,A2:3,XA2:3 A2:P2 3"
300 # Invalid to valid local partition direct transition tests
301 " C1-3:S+:P2 X4:P2 . . . . . . 0 A1:1-3,XA1:1-3,A2:1-3:XA2: A1:P2,A2:P-2 1-3"
302 " 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"
303 " C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4,B1:4-6 A1:P-2,B1:P0"
304 " C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3,B1:4-6 A1:P2,B1:P0 0-3"
305 " C0-3:P2 . . C3-5:C4-5 . . . . 0 A1:0-3,B1:4-5 A1:P2,B1:P0 0-3"
307 # Local partition invalidation tests
308 " C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
309 . . . . . 0 A1:1,A2:2,A3:3 A1:P2,A2:P2,A3:P2 1-3"
310 " C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
311 . . X4 . . 0 A1:1-3,A2:1-3,A3:2-3,XA2:,XA3: A1:P2,A2:P-2,A3:P-2 1-3"
312 " C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
313 . . C4:X . . 0 A1:1-3,A2:1-3,A3:2-3,XA2:,XA3: A1:P2,A2:P-2,A3:P-2 1-3"
314 # Local partition CPU change tests
315 " C0-5:S+:P2 C4-5:S+:P1 . . . C3-5 . . 0 A1:0-2,A2:3-5 A1:P2,A2:P1 0-2"
316 " C0-5:S+:P2 C4-5:S+:P1 . . C1-5 . . . 0 A1:1-3,A2:4-5 A1:P2,A2:P1 1-3"
318 # cpus_allowed/exclusive_cpus update tests
319 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
320 . X:C4 . P2 . 0 A1:4,A2:4,XA2:,XA3:,A3:4 \
322 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
323 . X1 . P2 . 0 A1:0-3,A2:1-3,XA1:1,XA2:,XA3:,A3:2-3 \
325 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
326 . . X3 P2 . 0 A1:0-2,A2:1-2,XA2:3,XA3:3,A3:3 \
328 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
329 . . X3 . . 0 A1:0-3,A2:1-3,XA2:3,XA3:3,A3:2-3 \
331 " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
332 . X4 . . . 0 A1:0-3,A2:1-3,A3:2-3,XA1:4,XA2:,XA3 \
335 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
336 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
338 # Incorrect change to cpuset.cpus[.exclusive] invalidates partition root
340 # Adding CPUs to partition root that are not in parent's
341 # cpuset.cpus is allowed, but those extra CPUs are ignored.
342 "C2-3:P1:S+ C3:P1 . . . C2-4 . . 0 A1:,A2:2-3 A1:P1,A2:P1"
344 # Taking away all CPUs from parent or itself if there are tasks
345 # will make the partition invalid.
346 "C2-3:P1:S+ C3:P1 . . T C2-3 . . 0 A1:2-3,A2:2-3 A1:P1,A2:P-1"
347 " C3:P1:S+ C3 . . T P1 . . 0 A1:3,A2:3 A1:P1,A2:P-1"
348 "$SETUP_A123_PARTITIONS . T:C2-3 . . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P-1,A3:P-1"
349 "$SETUP_A123_PARTITIONS . T:C2-3:C1-3 . . . 0 A1:1,A2:2,A3:3 A1:P1,A2:P1,A3:P1"
351 # Changing a partition root to member makes child partitions invalid
352 "C2-3:P1:S+ C3:P1 . . P0 . . . 0 A1:2-3,A2:3 A1:P0,A2:P-1"
353 "$SETUP_A123_PARTITIONS . C2-3 P0 . . 0 A1:2-3,A2:2-3,A3:3 A1:P1,A2:P0,A3:P-1"
355 # cpuset.cpus can contains cpus not in parent's cpuset.cpus as long
357 "C2-3:P1:S+ . . . . C3-4:P1 . . 0 A1:2,A2:3 A1:P1,A2:P1"
359 # Deletion of CPUs distributed to child cgroup is allowed.
360 "C0-1:P1:S+ C1 . C2-3 C4-5 . . . 0 A1:4-5,A2:4-5"
362 # To become a valid partition root, cpuset.cpus must overlap parent's
364 " C0-1:P1 . . C2-3 S+ C4-5:P1 . . 0 A1:0-1,A2:0-1 A1:P1,A2:P-1"
366 # Enabling partition with child cpusets is allowed
367 " C0-1:S+ C1 . C2-3 P1 . . . 0 A1:0-1,A2:1 A1:P1"
369 # A partition root with non-partition root parent is invalid, but it
370 # can be made valid if its parent becomes a partition root too.
371 " C0-1:S+ C1 . C2-3 . P2 . . 0 A1:0-1,A2:1 A1:P0,A2:P-2"
372 " C0-1:S+ C1:P2 . C2-3 P1 . . . 0 A1:0,A2:1 A1:P1,A2:P2"
374 # A non-exclusive cpuset.cpus change will invalidate partition and its siblings
375 " C0-1:P1 . . C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P-1,B1:P0"
376 " C0-1:P1 . . P1:C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P-1,B1:P-1"
377 " C0-1 . . P1:C2-3 C0-2 . . . 0 A1:0-2,B1:2-3 A1:P0,B1:P-1"
379 # cpuset.cpus can overlap with sibling cpuset.cpus.exclusive but not subsumed by it
380 " C0-3 . . C4-5 X5 . . . 0 A1:0-3,B1:4-5"
382 # Child partition root that try to take all CPUs from parent partition
383 # with tasks will remain invalid.
384 " C1-4:P1:S+ P1 . . . . . . 0 A1:1-4,A2:1-4 A1:P1,A2:P-1"
385 " C1-4:P1:S+ P1 . . . C1-4 . . 0 A1,A2:1-4 A1:P1,A2:P1"
386 " C1-4:P1:S+ P1 . . T C1-4 . . 0 A1:1-4,A2:1-4 A1:P1,A2:P-1"
388 # Clearing of cpuset.cpus with a preset cpuset.cpus.exclusive shouldn't
389 # affect cpuset.cpus.exclusive.effective.
390 " C1-4:X3:S+ C1:X3 . . . C . . 0 A2:1-4,XA2:3"
392 # old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
393 # ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
396 # A task cannot be added to a partition with no cpu
397 "C2-3:P1:S+ C3:P1 . . O2=0:T . . . 1 A1:,A2:3 A1:P1,A2:P1"
399 # Changes to cpuset.cpus.exclusive that violate exclusivity rule is rejected
400 " C0-3 . . C4-5 X0-3 . . X3-5 1 A1:0-3,B1:4-5"
402 # cpuset.cpus cannot be a subset of sibling cpuset.cpus.exclusive
403 " C0-3 . . C4-5 X3-5 . . . 1 A1:0-3,B1:4-5"
407 # Write to the cpu online file
408 # $1 - <c>=<v> where <c> = cpu number, <v> value to be written
414 CPUFILE
=//sys
/devices
/system
/cpu
/cpu
${CPU}/online
417 OFFLINE_CPUS
="$OFFLINE_CPUS $CPU"
419 [[ -n "$OFFLINE_CPUS" ]] && {
420 OFFLINE_CPUS
=$
(echo $CPU $CPU $OFFLINE_CPUS |
fmt -1 |\
429 # Set controller state
430 # $1 - cgroup directory
434 # The presence of ":" in state means transition from one to the next.
442 CTRL
=${CTRL:=$CONTROLLER}
444 REDIRECT
="2> $TMPMSG"
445 [[ -z "$STATE" ||
"$STATE" = '.' ]] && return 0
446 [[ $VERBOSE -gt 0 ]] && SHOWERR
=1
449 for CMD
in $
(echo $STATE |
sed -e "s/:/ /g")
451 TFILE
=$CGRP/cgroup.procs
452 SFILE
=$CGRP/cgroup.subtree_control
453 PFILE
=$CGRP/cpuset.cpus.partition
454 CFILE
=$CGRP/cpuset.cpus
455 XFILE
=$CGRP/cpuset.cpus.exclusive
456 S
=$
(expr substr
$CMD 1 1)
460 COMM
="echo ${PREFIX}${CTRL} > $SFILE"
465 COMM
="echo $CPUS > $XFILE"
470 COMM
="echo $CPUS > $CFILE"
483 echo "Invalid partition state - $VAL"
487 COMM
="echo $VAL > $PFILE"
492 write_cpu_online
$VAL
495 COMM
="echo 0 > $TFILE"
499 [[ $RET -ne 0 ]] && {
500 [[ -n "$SHOWERR" ]] && {
512 set_ctrl_state_noerr
()
516 [[ -d $CGRP ]] || mkdir
$CGRP
517 set_ctrl_state
$CGRP $STATE 1
519 echo "ERROR: Failed to set $2 to cgroup $1!"
526 [[ -n "OFFLINE_CPUS" ]] && {
527 for C
in $OFFLINE_CPUS
529 write_cpu_online
${C}=1
535 # Return 1 if the list of effective cpus isn't the same as the initial list.
537 reset_cgroup_states
()
539 echo 0 > $CGROUP2/cgroup.procs
541 rmdir A
1/A
2/A3 A
1/A2 A1 B1
> /dev
/null
2>&1
549 for DIR
in . A1 A
1/A2 A
1/A
2/A3 B1
551 CPUS
=$DIR/cpuset.cpus
552 ECPUS
=$DIR/cpuset.cpus.effective
553 XCPUS
=$DIR/cpuset.cpus.exclusive
554 XECPUS
=$DIR/cpuset.cpus.exclusive.effective
555 PRS
=$DIR/cpuset.cpus.partition
556 PCPUS
=$DIR/.__DEBUG__.cpuset.cpus.subpartitions
557 ISCPUS
=$DIR/cpuset.cpus.isolated
558 [[ -e $CPUS ]] && echo "$CPUS: $(cat $CPUS)"
559 [[ -e $XCPUS ]] && echo "$XCPUS: $(cat $XCPUS)"
560 [[ -e $ECPUS ]] && echo "$ECPUS: $(cat $ECPUS)"
561 [[ -e $XECPUS ]] && echo "$XECPUS: $(cat $XECPUS)"
562 [[ -e $PRS ]] && echo "$PRS: $(cat $PRS)"
563 [[ -e $PCPUS ]] && echo "$PCPUS: $(cat $PCPUS)"
564 [[ -e $ISCPUS ]] && echo "$ISCPUS: $(cat $ISCPUS)"
569 # Check effective cpus
570 # $1 - check string, format: <cgroup>:<cpu-list>[,<cgroup>:<cpu-list>]*
572 check_effective_cpus
()
575 for CHK
in $
(echo $CHK_STR |
sed -e "s/,/ /g")
577 set -- $
(echo $CHK |
sed -e "s/:/ /g")
583 FILE
=cpuset.cpus.exclusive.effective
585 FILE
=cpuset.cpus.effective
587 [[ $CGRP = A2
]] && CGRP
=A
1/A2
588 [[ $CGRP = A3
]] && CGRP
=A
1/A
2/A3
589 [[ -e $CGRP/$FILE ]] ||
return 1
590 [[ $CPUS = $
(cat $CGRP/$FILE) ]] ||
return 1
595 # Check cgroup states
596 # $1 - check string, format: <cgroup>:<state>[,<cgroup>:<state>]*
598 check_cgroup_states
()
601 for CHK
in $
(echo $CHK_STR |
sed -e "s/,/ /g")
603 set -- $
(echo $CHK |
sed -e "s/:/ /g")
608 EVAL
=$
(expr substr
$STATE 2 2)
609 [[ $CGRP = A2
]] && CGRP_DIR
=A
1/A2
610 [[ $CGRP = A3
]] && CGRP_DIR
=A
1/A
2/A3
613 P
*) FILE
=$CGRP_DIR/cpuset.cpus.partition
615 *) echo "Unknown state: $STATE!"
636 [[ $EVAL != $VAL ]] && return 1
639 # For root partition, dump sched-domains info to console if
640 # verbose mode set for manual comparison with sched debug info.
642 [[ $VAL -eq 1 && $VERBOSE -gt 0 ]] && {
643 DOMS
=$
(cat $CGRP_DIR/cpuset.cpus.effective
)
645 echo " [$CGRP] sched-domain: $DOMS" > $CONSOLE
652 # Get isolated (including offline) CPUs by looking at
653 # /sys/kernel/debug/sched/domains and cpuset.cpus.isolated control file,
654 # if available, and compare that with the expected value.
656 # Note that isolated CPUs from the sched/domains context include offline
657 # CPUs as well as CPUs in non-isolated 1-CPU partition. Those CPUs may
658 # not be included in the cpuset.cpus.isolated control file which contains
659 # only CPUs in isolated partitions as well as those that are isolated at
662 # $1 - expected isolated cpu list(s) <isolcpus1>{,<isolcpus2>}
663 # <isolcpus1> - expected sched/domains value
664 # <isolcpus2> - cpuset.cpus.isolated value = <isolcpus1> if not defined
671 SCHED_DOMAINS
=/sys
/kernel
/debug
/sched
/domains
672 ISCPUS
=${CGROUP2}/cpuset.cpus.isolated
673 if [[ $EXPECT_VAL = .
]]
677 elif [[ $
(expr $EXPECT_VAL : ".*,.*") > 0 ]]
679 set -- $
(echo $EXPECT_VAL |
sed -e "s/,/ /g")
683 EXPECT_VAL2
=$EXPECT_VAL
687 # Check cpuset.cpus.isolated cpumask
689 if [[ -z "$BOOT_ISOLCPUS" ]]
691 ISOLCPUS
=$
(cat $ISCPUS)
693 ISOLCPUS
=$
(cat $ISCPUS |
sed -e "s/,*$BOOT_ISOLCPUS//")
695 [[ "$EXPECT_VAL2" != "$ISOLCPUS" ]] && {
696 # Take a 50ms pause and try again
698 ISOLCPUS
=$
(cat $ISCPUS)
700 [[ "$EXPECT_VAL2" != "$ISOLCPUS" ]] && return 1
704 # Use the sched domain in debugfs to check isolated CPUs, if available
706 [[ -d $SCHED_DOMAINS ]] ||
return 0
708 for ((CPU
=0; CPU
< $NR_CPUS; CPU
++))
710 [[ -n "$(ls ${SCHED_DOMAINS}/cpu$CPU)" ]] && continue
712 if [[ -z "$LASTISOLCPU" ]]
716 elif [[ "$LASTISOLCPU" -eq $
((CPU
- 1)) ]]
718 echo $ISOLCPUS |
grep -q "\<$LASTISOLCPU\$"
721 ISOLCPUS
=${ISOLCPUS}-
725 if [[ $ISOLCPUS = *- ]]
727 ISOLCPUS
=${ISOLCPUS}$LASTISOLCPU
729 ISOLCPUS
=${ISOLCPUS},$CPU
733 [[ "$ISOLCPUS" = *- ]] && ISOLCPUS
=${ISOLCPUS}$LASTISOLCPU
734 [[ -n "BOOT_ISOLCPUS" ]] &&
735 ISOLCPUS
=$
(echo $ISOLCPUS |
sed -e "s/,*$BOOT_ISOLCPUS//")
737 [[ "$EXPECT_VAL" = "$ISOLCPUS" ]]
745 echo "Test $TEST[$TESTNUM] failed $TESTTYPE check!"
746 [[ -n "$ADDINFO" ]] && echo "*** $ADDINFO ***"
747 eval echo \
${$TEST[$I]}
754 # Check to see if there are unexpected isolated CPUs left beyond the boot
755 # time isolated ones.
757 null_isolcpus_check
()
759 [[ $VERBOSE -gt 0 ]] ||
return 0
760 # Retry a few times before printing error
762 while [[ $RETRY -lt 8 ]]
766 [[ $?
-eq 0 ]] && return 0
769 echo "Unexpected isolated CPUs: $ISOLCPUS"
775 # Run cpuset state transition test
776 # $1 - test matrix name
778 # This test is somewhat fragile as delays (sleep x) are added in various
779 # places to make sure state changes are fully propagated before the next
780 # action. These delays may need to be adjusted if running in a slower machine.
787 eval CNT
="\${#$TEST[@]}"
790 console_msg
"Running state transition test ..."
792 while [[ $I -lt $CNT ]]
794 echo "Running test $I ..." > $CONSOLE
795 [[ $VERBOSE -gt 1 ]] && {
797 eval echo \
${$TEST[$I]}
799 eval set -- "\${$TEST[$I]}"
813 set_ctrl_state_noerr B1
$OLD_B1
814 set_ctrl_state_noerr A1
$OLD_A1
815 set_ctrl_state_noerr A
1/A2
$OLD_A2
816 set_ctrl_state_noerr A
1/A
2/A3
$OLD_A3
818 set_ctrl_state A1
$NEW_A1; ((RETVAL
+= $?
))
819 set_ctrl_state A
1/A2
$NEW_A2; ((RETVAL
+= $?
))
820 set_ctrl_state A
1/A
2/A3
$NEW_A3; ((RETVAL
+= $?
))
821 set_ctrl_state B1
$NEW_B1; ((RETVAL
+= $?
))
823 [[ $RETVAL -ne $RESULT ]] && test_fail
$I result
825 [[ -n "$ECPUS" && "$ECPUS" != .
]] && {
826 check_effective_cpus
$ECPUS
827 [[ $?
-ne 0 ]] && test_fail
$I "effective CPU"
830 [[ -n "$STATES" && "$STATES" != .
]] && {
831 check_cgroup_states
$STATES
832 [[ $?
-ne 0 ]] && test_fail
$I states
835 # Compare the expected isolated CPUs with the actual ones,
837 [[ -n "$ICPUS" ]] && {
838 check_isolcpus
$ICPUS
839 [[ $?
-ne 0 ]] && test_fail
$I "isolated CPU" \
840 "Expect $ICPUS, get $ISOLCPUS instead"
844 # Check to see if effective cpu list changes
846 NEWLIST
=$
(cat cpuset.cpus.effective
)
848 while [[ $NEWLIST != $CPULIST && $RETRY -lt 8 ]]
850 # Wait a bit longer & recheck a few times
853 NEWLIST
=$
(cat cpuset.cpus.effective
)
855 [[ $NEWLIST != $CPULIST ]] && {
856 echo "Effective cpus changed to $NEWLIST after test $I!"
860 [[ $VERBOSE -gt 0 ]] && echo "Test $I done."
863 echo "All $I tests of $TEST PASSED."
867 # Testing the new "isolated" partition root type
872 echo 2-3 > cpuset.cpus
873 TYPE
=$
(cat cpuset.cpus.partition
)
874 [[ $TYPE = member
]] ||
echo member
> cpuset.cpus.partition
876 console_msg
"Change from member to root"
879 console_msg
"Change from root to isolated"
880 test_partition isolated
882 console_msg
"Change from isolated to member"
883 test_partition member
885 console_msg
"Change from member to isolated"
886 test_partition isolated
888 console_msg
"Change from isolated to root"
891 console_msg
"Change from root to member"
892 test_partition member
895 # Testing partition root with no cpu
897 console_msg
"Distribute all cpus to child partition"
898 echo +cpuset
> cgroup.subtree_control
903 echo 2-3 > cpuset.cpus
905 test_effective_cpus
2-3
907 test_effective_cpus
""
909 console_msg
"Moving task to partition test"
910 test_add_proc
"No space left"
915 console_msg
"Shrink and expand child partition"
919 test_effective_cpus
3
921 echo 2-3 > cpuset.cpus
923 test_effective_cpus
""
926 console_msg
"Cleaning up"
927 echo $$
> $CGROUP2/cgroup.procs
928 [[ -d A1
]] && rmdir A1
933 # Wait for inotify event for the given file and read it
934 # $1: cgroup file to wait for
935 # $2: file to store the read result
942 $WAIT_INOTIFY $CGROUP_FILE
943 cat $CGROUP_FILE > $OUTPUT_FILE
947 # Test if inotify events are properly generated when going into and out of
948 # invalid partition state.
955 [[ -f $WAIT_INOTIFY ]] ||
{
956 echo "wait_inotify not found, inotify test SKIPPED."
962 echo 0 > cgroup.procs
963 echo root
> cpuset.cpus.partition
966 wait_inotify
$PWD/cpuset.cpus.partition
$PRS &
968 set_ctrl_state .
"O1=0"
970 check_cgroup_states
".:P-1"
973 echo "FAILED: Inotify test - partition not invalid"
977 echo "FAILED: Inotify test - event not generated"
980 elif [[ $
(cat $PRS) != "root invalid"* ]]
982 echo "FAILED: Inotify test - incorrect state"
987 echo member
> cpuset.cpus.partition
988 echo 0 > ..
/cgroup.procs
993 echo "Inotify test PASSED"
998 run_state_test TEST_MATRIX
1001 echo "All tests PASSED."