1#!/bin/sh
2
3################################################################################
4#                                                                              #
5# Copyright (c) 2009 FUJITSU LIMITED                                           #
6#                                                                              #
7# This program is free software;  you can redistribute it and#or modify        #
8# it under the terms of the GNU General Public License as published by         #
9# the Free Software Foundation; either version 2 of the License, or            #
10# (at your option) any later version.                                          #
11#                                                                              #
12# This program is distributed in the hope that it will be useful, but          #
13# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY   #
14# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License     #
15# for more details.                                                            #
16#                                                                              #
17# You should have received a copy of the GNU General Public License            #
18# along with this program;  if not, write to the Free Software                 #
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA      #
20#                                                                              #
21# Author: Miao Xie <[email protected]>                                      #
22#                                                                              #
23################################################################################
24
25export TCID="cpuset_hotplug"
26export TST_TOTAL=13
27export TST_COUNT=1
28
29. cpuset_funcs.sh
30
31check 2 1
32
33exit_status=0
34
35nr_cpus=$NR_CPUS
36nr_mems=$N_NODES
37
38cpus_all="$(seq -s, 0 $((nr_cpus-1)))"
39cpus_all="`cpuset_list_compute $cpus_all`"
40mems_all="$(seq -s, 0 $((nr_mems-1)))"
41
42# check_result <result> <expect>
43check_result()
44{
45	local result="$1"
46	local expect="$2"
47
48	case "$expect" in
49	EMPTY)
50		test -z "$result"
51		return $?
52		;;
53	*)
54		test "$expect" = "$result"
55		return $?
56		;;
57	esac
58}
59
60# root_cpu_hotplug_test <cpuhotplug> <expect_cpus> <expect_task_cpus>
61root_cpu_hotplug_test()
62{
63	local cpuhotplug="$1"
64	local expect_cpus="$2"
65	local expect_task_cpus="$3"
66
67	local root_cpus=
68	local task_cpus=
69	local tst_pid=
70	local ret=
71
72	setup_test_environment $cpuhotplug 2> $CPUSET_TMP/stderr
73	if [ $? -ne 0 ]; then
74		cpuset_log_error $CPUSET_TMP/stderr
75		tst_resm TFAIL "setup test environment(offline CPU#$HOTPLUG_CPU) failed"
76		return 1
77	fi
78
79	/bin/cat /dev/zero > /dev/null 2>&1 &
80	tst_pid=$!
81
82	cpu_hotplug $HOTPLUG_CPU $cpuhotplug 2> $CPUSET_TMP/stderr
83	if [ $? -ne 0 ]; then
84		cpuset_log_error $CPUSET_TMP/stderr
85		tst_resm TFAIL "$cpuoffline CPU#$HOTPLUG_CPU failed."
86		return 1
87	fi
88
89	# cpuset hotplug is asynchronous operation, we could end up reading a
90	# stale value here. sleep is awful, but we can't do better.
91	# See https://github.com/linux-test-project/ltp/issues/693
92	sleep 1
93
94	root_cpus="`cat $CPUSET/cpuset.cpus`"
95
96	task_cpus="`cat /sys/devices/system/cpu/present`"
97
98	check_result "$root_cpus" "$expect_cpus"
99	ret=$?
100	if [ $ret -eq 0 ]
101	then
102		check_result "$task_cpus" "$expect_task_cpus"
103		ret=$?
104		if [ $ret -ne 0 ]; then
105			tst_resm TFAIL "task's cpu present list isn't expected.(Result: $task_cpus, Expect: $expect_task_cpus)"
106		fi
107	else
108		tst_resm TFAIL "root group's cpus isn't expected(Result: $root_cpus, Expect: $expect_cpus)."
109	fi
110
111	/bin/kill -9 $tst_pid > /dev/null 2>&1
112
113	return $ret
114}
115
116# general_cpu_hotplug_test <cpuhotplug> <cpus> <expect_cpus> <expect_task_cpus>
117general_cpu_hotplug_test()
118{
119	local cpuhotplug="$1"
120	local cpus="$2"
121	local expect_cpus="$3"
122	local expect_task_cpus="$4"
123	local path="$CPUSET/1"
124
125	local tst_pid=
126	local task_cpus=
127	local ret=
128
129	setup_test_environment $cpuhotplug 2> $CPUSET_TMP/stderr
130	if [ $? -ne 0 ]; then
131		cpuset_log_error $CPUSET_TMP/stderr
132		tst_resm TFAIL "setup test environment(offline CPU#$HOTPLUG_CPU) failed"
133		return 1
134	fi
135
136	cpuset_set "$path" "$cpus" "$mems_all" "0" 2> $CPUSET_TMP/stderr
137	if [ $? -ne 0 ]; then
138		cpuset_log_error $CPUSET_TMP/stderr
139		tst_resm TFAIL "set general group parameter failed."
140		return 1
141	fi
142
143	/bin/cat /dev/zero > /dev/null 2>&1 &
144	tst_pid=$!
145
146	echo $tst_pid > "$path/tasks" 2> $CPUSET_TMP/stderr
147	if [ $? -ne 0 ]; then
148		cpuset_log_error $CPUSET_TMP/stderr
149		tst_resm TFAIL "attach test tasks to group failed."
150		/bin/kill -s SIGKILL $tst_pid
151		return 1
152	fi
153
154	cpu_hotplug $HOTPLUG_CPU $cpuhotplug 2> $CPUSET_TMP/stderr
155	if [ $? -ne 0 ]; then
156		cpuset_log_error $CPUSET_TMP/stderr
157		tst_resm TFAIL "$cpuoffline CPU#$HOTPLUG_CPU failed."
158		/bin/kill -s SIGKILL $tst_pid
159		return 1
160	fi
161
162	# cpuset hotplug is asynchronous operation, we could end up reading a
163	# stale value here. sleep is awful, but we can't do better.
164	# See https://github.com/linux-test-project/ltp/issues/693
165	sleep 1
166
167	cpus="`cat $path/cpuset.cpus`"
168
169	task_cpus="`cat /proc/$tst_pid/status | grep Cpus_allowed_list`"
170	task_cpus="`echo $task_cpus | sed -e 's/Cpus_allowed_list: //'`"
171
172	if [ "$expect_cpus" = "EMPTY" ]; then
173		local tasks=`cat $path/tasks | grep "\b$tst_pid\b"`
174		check_result "$tasks" "EMPTY"
175		if [ $? -ne 0 ]; then
176			tst_resm TFAIL "test task was still in general group, but its cpus is NULL"
177			/bin/kill -s SIGKILL $tst_pid
178			return 1
179		fi
180
181		tasks=`cat $CPUSET/tasks | grep "\b$tst_pid\b"`
182		check_result "$tasks" "$tst_pid"
183		if [ $? -ne 0 ]; then
184			tst_resm TFAIL "test task wasn't moved to parent group"
185			/bin/kill -s SIGKILL $tst_pid
186			return 1
187		fi
188		task_cpus="`cat /sys/devices/system/cpu/present`"
189	fi
190
191	check_result "$cpus" "$expect_cpus"
192	ret=$?
193	if [ $ret -eq 0 ]; then
194		check_result $task_cpus $expect_task_cpus
195		ret=$?
196		if [ $ret -ne 0 ]; then
197			tst_resm TFAIL "task's cpu present list isn't expected(Result: $task_cpus, Expect: $expect_task_cpus)."
198		fi
199	else
200		if [ "$cpus" = "" ]; then
201			cpus="EMPTY"
202		fi
203		tst_resm TFAIL "general group's cpus isn't expected(Result: $cpus, Expect: $expect_cpus)."
204	fi
205	/bin/kill -s SIGKILL $tst_pid > /dev/null 2>&1
206
207	return $ret
208}
209
210base_test()
211{
212	setup
213	if [ $? -ne 0 ]; then
214		exit_status=1
215	else
216		"$test_function" "$@"
217		if [ $? -ne 0 ]; then
218			exit_status=1
219			cleanup
220		else
221			cleanup
222			if [ $? -ne 0 ]; then
223				exit_status=1
224			else
225				tst_resm TPASS "Cpuset vs CPU hotplug test succeeded."
226			fi
227		fi
228
229		cpu_hotplug_cleanup
230	fi
231	TST_COUNT=$(($TST_COUNT + 1))
232}
233
234# Test Case 1-2
235test_root_cpu_hotplug()
236{
237	local tmp_cpus="`cpuset_list_compute -s $cpus_all $HOTPLUG_CPU`"
238
239	test_function="root_cpu_hotplug_test"
240	while read hotplug cpus_expect task_expect
241	do
242		base_test "$hotplug" "$cpus_expect" "$task_expect"
243	done <<- EOF
244		offline	$tmp_cpus	$cpus_all
245		online	$cpus_all	$cpus_all
246	EOF
247	# while read hotplug cpus_expect task_expect
248}
249
250# Test Case 3-6
251test_general_cpu_hotplug()
252{
253	local tmp_cpus="`cpuset_list_compute -s $cpus_all $HOTPLUG_CPU`"
254
255	test_function="general_cpu_hotplug_test"
256	while read hotplug cpus cpus_expect task_expect
257	do
258		base_test "$hotplug" "$cpus" "$cpus_expect" "$task_expect"
259	done <<- EOF
260		offline		0-1	0	0
261		offline		1	EMPTY	$cpus_all
262		offline		0	0	0
263		online		0	0	0
264	EOF
265	# while read hotplug cpus cpus_expect task_expect
266}
267
268test_root_cpu_hotplug
269test_general_cpu_hotplug
270
271exit $exit_status
272