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