Linux-libre 5.4.47-gnu
[librecmc/linux-libre.git] / tools / testing / selftests / memory-hotplug / mem-on-off-test.sh
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3
4 SYSFS=
5
6 # Kselftest framework requirement - SKIP code is 4.
7 ksft_skip=4
8
9 prerequisite()
10 {
11         msg="skip all tests:"
12
13         if [ $UID != 0 ]; then
14                 echo $msg must be run as root >&2
15                 exit $ksft_skip
16         fi
17
18         SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'`
19
20         if [ ! -d "$SYSFS" ]; then
21                 echo $msg sysfs is not mounted >&2
22                 exit $ksft_skip
23         fi
24
25         if ! ls $SYSFS/devices/system/memory/memory* > /dev/null 2>&1; then
26                 echo $msg memory hotplug is not supported >&2
27                 exit $ksft_skip
28         fi
29
30         if ! grep -q 1 $SYSFS/devices/system/memory/memory*/removable; then
31                 echo $msg no hot-pluggable memory >&2
32                 exit $ksft_skip
33         fi
34 }
35
36 #
37 # list all hot-pluggable memory
38 #
39 hotpluggable_memory()
40 {
41         local state=${1:-.\*}
42
43         for memory in $SYSFS/devices/system/memory/memory*; do
44                 if grep -q 1 $memory/removable &&
45                    grep -q $state $memory/state; then
46                         echo ${memory##/*/memory}
47                 fi
48         done
49 }
50
51 hotpluggable_offline_memory()
52 {
53         hotpluggable_memory offline
54 }
55
56 hotpluggable_online_memory()
57 {
58         hotpluggable_memory online
59 }
60
61 memory_is_online()
62 {
63         grep -q online $SYSFS/devices/system/memory/memory$1/state
64 }
65
66 memory_is_offline()
67 {
68         grep -q offline $SYSFS/devices/system/memory/memory$1/state
69 }
70
71 online_memory()
72 {
73         echo online > $SYSFS/devices/system/memory/memory$1/state
74 }
75
76 offline_memory()
77 {
78         echo offline > $SYSFS/devices/system/memory/memory$1/state
79 }
80
81 online_memory_expect_success()
82 {
83         local memory=$1
84
85         if ! online_memory $memory; then
86                 echo $FUNCNAME $memory: unexpected fail >&2
87                 return 1
88         elif ! memory_is_online $memory; then
89                 echo $FUNCNAME $memory: unexpected offline >&2
90                 return 1
91         fi
92         return 0
93 }
94
95 online_memory_expect_fail()
96 {
97         local memory=$1
98
99         if online_memory $memory 2> /dev/null; then
100                 echo $FUNCNAME $memory: unexpected success >&2
101                 return 1
102         elif ! memory_is_offline $memory; then
103                 echo $FUNCNAME $memory: unexpected online >&2
104                 return 1
105         fi
106         return 0
107 }
108
109 offline_memory_expect_success()
110 {
111         local memory=$1
112
113         if ! offline_memory $memory; then
114                 echo $FUNCNAME $memory: unexpected fail >&2
115                 return 1
116         elif ! memory_is_offline $memory; then
117                 echo $FUNCNAME $memory: unexpected offline >&2
118                 return 1
119         fi
120         return 0
121 }
122
123 offline_memory_expect_fail()
124 {
125         local memory=$1
126
127         if offline_memory $memory 2> /dev/null; then
128                 echo $FUNCNAME $memory: unexpected success >&2
129                 return 1
130         elif ! memory_is_online $memory; then
131                 echo $FUNCNAME $memory: unexpected offline >&2
132                 return 1
133         fi
134         return 0
135 }
136
137 error=-12
138 priority=0
139 # Run with default of ratio=2 for Kselftest run
140 ratio=2
141 retval=0
142
143 while getopts e:hp:r: opt; do
144         case $opt in
145         e)
146                 error=$OPTARG
147                 ;;
148         h)
149                 echo "Usage $0 [ -e errno ] [ -p notifier-priority ] [ -r percent-of-memory-to-offline ]"
150                 exit
151                 ;;
152         p)
153                 priority=$OPTARG
154                 ;;
155         r)
156                 ratio=$OPTARG
157                 if [ "$ratio" -gt 100 ] || [ "$ratio" -lt 0 ]; then
158                         echo "The percentage should be an integer within 0~100 range"
159                         exit 1
160                 fi
161                 ;;
162         esac
163 done
164
165 if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
166         echo "error code must be -4095 <= errno < 0" >&2
167         exit 1
168 fi
169
170 prerequisite
171
172 echo "Test scope: $ratio% hotplug memory"
173
174 #
175 # Online all hot-pluggable memory
176 #
177 hotpluggable_num=`hotpluggable_offline_memory | wc -l`
178 echo -e "\t online all hot-pluggable memory in offline state:"
179 if [ "$hotpluggable_num" -gt 0 ]; then
180         for memory in `hotpluggable_offline_memory`; do
181                 echo "offline->online memory$memory"
182                 if ! online_memory_expect_success $memory; then
183                         retval=1
184                 fi
185         done
186 else
187         echo -e "\t\t SKIPPED - no hot-pluggable memory in offline state"
188 fi
189
190 #
191 # Offline $ratio percent of hot-pluggable memory
192 #
193 hotpluggable_num=`hotpluggable_online_memory | wc -l`
194 target=`echo "a=$hotpluggable_num*$ratio; if ( a%100 ) a/100+1 else a/100" | bc`
195 echo -e "\t offline $ratio% hot-pluggable memory in online state"
196 echo -e "\t trying to offline $target out of $hotpluggable_num memory block(s):"
197 for memory in `hotpluggable_online_memory`; do
198         if [ "$target" -gt 0 ]; then
199                 echo "online->offline memory$memory"
200                 if offline_memory_expect_success $memory; then
201                         target=$(($target - 1))
202                 fi
203         fi
204 done
205 if [ "$target" -gt 0 ]; then
206         retval=1
207         echo -e "\t\t FAILED - unable to offline some memory blocks, device busy?"
208 fi
209
210 #
211 # Online all hot-pluggable memory again
212 #
213 hotpluggable_num=`hotpluggable_offline_memory | wc -l`
214 echo -e "\t online all hot-pluggable memory in offline state:"
215 if [ "$hotpluggable_num" -gt 0 ]; then
216         for memory in `hotpluggable_offline_memory`; do
217                 echo "offline->online memory$memory"
218                 if ! online_memory_expect_success $memory; then
219                         retval=1
220                 fi
221         done
222 else
223         echo -e "\t\t SKIPPED - no hot-pluggable memory in offline state"
224 fi
225
226 #
227 # Test with memory notifier error injection
228 #
229
230 DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
231 NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/memory
232
233 prerequisite_extra()
234 {
235         msg="skip extra tests:"
236
237         /sbin/modprobe -q -r memory-notifier-error-inject
238         /sbin/modprobe -q memory-notifier-error-inject priority=$priority
239
240         if [ ! -d "$DEBUGFS" ]; then
241                 echo $msg debugfs is not mounted >&2
242                 exit $retval
243         fi
244
245         if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
246                 echo $msg memory-notifier-error-inject module is not available >&2
247                 exit $retval
248         fi
249 }
250
251 echo -e "\t Test with memory notifier error injection"
252 prerequisite_extra
253
254 #
255 # Offline $ratio percent of hot-pluggable memory
256 #
257 echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
258 for memory in `hotpluggable_online_memory`; do
259         if [ $((RANDOM % 100)) -lt $ratio ]; then
260                 offline_memory_expect_success $memory
261         fi
262 done
263
264 #
265 # Test memory hot-add error handling (offline => online)
266 #
267 echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
268 for memory in `hotpluggable_offline_memory`; do
269         online_memory_expect_fail $memory
270 done
271
272 #
273 # Online all hot-pluggable memory
274 #
275 echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_ONLINE/error
276 for memory in `hotpluggable_offline_memory`; do
277         online_memory_expect_success $memory
278 done
279
280 #
281 # Test memory hot-remove error handling (online => offline)
282 #
283 echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
284 for memory in `hotpluggable_online_memory`; do
285         offline_memory_expect_fail $memory
286 done
287
288 echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/MEM_GOING_OFFLINE/error
289 /sbin/modprobe -q -r memory-notifier-error-inject
290
291 exit $retval