1#!/bin/bash
2
3SYSFS=
4
5prerequisite()
6{
7	msg="skip all tests:"
8
9	if [ $UID != 0 ]; then
10		echo $msg must be run as root >&2
11		exit 0
12	fi
13
14	taskset -p 01 $$
15
16	SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
17
18	if [ ! -d "$SYSFS" ]; then
19		echo $msg sysfs is not mounted >&2
20		exit 0
21	fi
22
23	if ! ls $SYSFS/devices/system/cpu/cpu* > /dev/null 2>&1; then
24		echo $msg cpu hotplug is not supported >&2
25		exit 0
26	fi
27
28	echo "CPU online/offline summary:"
29	online_cpus=`cat $SYSFS/devices/system/cpu/online`
30	online_max=${online_cpus##*-}
31	echo -e "\t Cpus in online state: $online_cpus"
32
33	offline_cpus=`cat $SYSFS/devices/system/cpu/offline`
34	if [[ "a$offline_cpus" = "a" ]]; then
35		offline_cpus=0
36	else
37		offline_max=${offline_cpus##*-}
38	fi
39	echo -e "\t Cpus in offline state: $offline_cpus"
40}
41
42#
43# list all hot-pluggable CPUs
44#
45hotpluggable_cpus()
46{
47	local state=${1:-.\*}
48
49	for cpu in $SYSFS/devices/system/cpu/cpu*; do
50		if [ -f $cpu/online ] && grep -q $state $cpu/online; then
51			echo ${cpu##/*/cpu}
52		fi
53	done
54}
55
56hotplaggable_offline_cpus()
57{
58	hotpluggable_cpus 0
59}
60
61hotpluggable_online_cpus()
62{
63	hotpluggable_cpus 1
64}
65
66cpu_is_online()
67{
68	grep -q 1 $SYSFS/devices/system/cpu/cpu$1/online
69}
70
71cpu_is_offline()
72{
73	grep -q 0 $SYSFS/devices/system/cpu/cpu$1/online
74}
75
76online_cpu()
77{
78	echo 1 > $SYSFS/devices/system/cpu/cpu$1/online
79}
80
81offline_cpu()
82{
83	echo 0 > $SYSFS/devices/system/cpu/cpu$1/online
84}
85
86online_cpu_expect_success()
87{
88	local cpu=$1
89
90	if ! online_cpu $cpu; then
91		echo $FUNCNAME $cpu: unexpected fail >&2
92		exit 1
93	elif ! cpu_is_online $cpu; then
94		echo $FUNCNAME $cpu: unexpected offline >&2
95		exit 1
96	fi
97}
98
99online_cpu_expect_fail()
100{
101	local cpu=$1
102
103	if online_cpu $cpu 2> /dev/null; then
104		echo $FUNCNAME $cpu: unexpected success >&2
105		exit 1
106	elif ! cpu_is_offline $cpu; then
107		echo $FUNCNAME $cpu: unexpected online >&2
108		exit 1
109	fi
110}
111
112offline_cpu_expect_success()
113{
114	local cpu=$1
115
116	if ! offline_cpu $cpu; then
117		echo $FUNCNAME $cpu: unexpected fail >&2
118		exit 1
119	elif ! cpu_is_offline $cpu; then
120		echo $FUNCNAME $cpu: unexpected offline >&2
121		exit 1
122	fi
123}
124
125offline_cpu_expect_fail()
126{
127	local cpu=$1
128
129	if offline_cpu $cpu 2> /dev/null; then
130		echo $FUNCNAME $cpu: unexpected success >&2
131		exit 1
132	elif ! cpu_is_online $cpu; then
133		echo $FUNCNAME $cpu: unexpected offline >&2
134		exit 1
135	fi
136}
137
138error=-12
139allcpus=0
140priority=0
141online_cpus=0
142online_max=0
143offline_cpus=0
144offline_max=0
145
146while getopts e:ahp: opt; do
147	case $opt in
148	e)
149		error=$OPTARG
150		;;
151	a)
152		allcpus=1
153		;;
154	h)
155		echo "Usage $0 [ -a ] [ -e errno ] [ -p notifier-priority ]"
156		echo -e "\t default offline one cpu"
157		echo -e "\t run with -a option to offline all cpus"
158		exit
159		;;
160	p)
161		priority=$OPTARG
162		;;
163	esac
164done
165
166if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
167	echo "error code must be -4095 <= errno < 0" >&2
168	exit 1
169fi
170
171prerequisite
172
173#
174# Safe test (default) - offline and online one cpu
175#
176if [ $allcpus -eq 0 ]; then
177	echo "Limited scope test: one hotplug cpu"
178	echo -e "\t (leaves cpu in the original state):"
179	echo -e "\t online to offline to online: cpu $online_max"
180	offline_cpu_expect_success $online_max
181	online_cpu_expect_success $online_max
182
183	if [[ $offline_cpus -gt 0 ]]; then
184		echo -e "\t offline to online to offline: cpu $offline_max"
185		online_cpu_expect_success $offline_max
186		offline_cpu_expect_success $offline_max
187	fi
188	exit 0
189else
190	echo "Full scope test: all hotplug cpus"
191	echo -e "\t online all offline cpus"
192	echo -e "\t offline all online cpus"
193	echo -e "\t online all offline cpus"
194fi
195
196#
197# Online all hot-pluggable CPUs
198#
199for cpu in `hotplaggable_offline_cpus`; do
200	online_cpu_expect_success $cpu
201done
202
203#
204# Offline all hot-pluggable CPUs
205#
206for cpu in `hotpluggable_online_cpus`; do
207	offline_cpu_expect_success $cpu
208done
209
210#
211# Online all hot-pluggable CPUs again
212#
213for cpu in `hotplaggable_offline_cpus`; do
214	online_cpu_expect_success $cpu
215done
216
217#
218# Test with cpu notifier error injection
219#
220
221DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
222NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/cpu
223
224prerequisite_extra()
225{
226	msg="skip extra tests:"
227
228	/sbin/modprobe -q -r cpu-notifier-error-inject
229	/sbin/modprobe -q cpu-notifier-error-inject priority=$priority
230
231	if [ ! -d "$DEBUGFS" ]; then
232		echo $msg debugfs is not mounted >&2
233		exit 0
234	fi
235
236	if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
237		echo $msg cpu-notifier-error-inject module is not available >&2
238		exit 0
239	fi
240}
241
242prerequisite_extra
243
244#
245# Offline all hot-pluggable CPUs
246#
247echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
248for cpu in `hotpluggable_online_cpus`; do
249	offline_cpu_expect_success $cpu
250done
251
252#
253# Test CPU hot-add error handling (offline => online)
254#
255echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
256for cpu in `hotplaggable_offline_cpus`; do
257	online_cpu_expect_fail $cpu
258done
259
260#
261# Online all hot-pluggable CPUs
262#
263echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
264for cpu in `hotplaggable_offline_cpus`; do
265	online_cpu_expect_success $cpu
266done
267
268#
269# Test CPU hot-remove error handling (online => offline)
270#
271echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
272for cpu in `hotpluggable_online_cpus`; do
273	offline_cpu_expect_fail $cpu
274done
275
276echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
277/sbin/modprobe -q -r cpu-notifier-error-inject
278