]> Git Repo - linux.git/blob - tools/testing/selftests/livepatch/functions.sh
scsi: zfcp: Trace when request remove fails after qdio send fails
[linux.git] / tools / testing / selftests / livepatch / functions.sh
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (C) 2018 Joe Lawrence <[email protected]>
4
5 # Shell functions for the rest of the scripts.
6
7 MAX_RETRIES=600
8 RETRY_INTERVAL=".1"     # seconds
9 KLP_SYSFS_DIR="/sys/kernel/livepatch"
10
11 # Kselftest framework requirement - SKIP code is 4
12 ksft_skip=4
13
14 # log(msg) - write message to kernel log
15 #       msg - insightful words
16 function log() {
17         echo "$1" > /dev/kmsg
18 }
19
20 # skip(msg) - testing can't proceed
21 #       msg - explanation
22 function skip() {
23         log "SKIP: $1"
24         echo "SKIP: $1" >&2
25         exit $ksft_skip
26 }
27
28 # root test
29 function is_root() {
30         uid=$(id -u)
31         if [ $uid -ne 0 ]; then
32                 echo "skip all tests: must be run as root" >&2
33                 exit $ksft_skip
34         fi
35 }
36
37 # die(msg) - game over, man
38 #       msg - dying words
39 function die() {
40         log "ERROR: $1"
41         echo "ERROR: $1" >&2
42         exit 1
43 }
44
45 # save existing dmesg so we can detect new content
46 function save_dmesg() {
47         SAVED_DMESG=$(mktemp --tmpdir -t klp-dmesg-XXXXXX)
48         dmesg > "$SAVED_DMESG"
49 }
50
51 # cleanup temporary dmesg file from save_dmesg()
52 function cleanup_dmesg_file() {
53         rm -f "$SAVED_DMESG"
54 }
55
56 function push_config() {
57         DYNAMIC_DEBUG=$(grep '^kernel/livepatch' /sys/kernel/debug/dynamic_debug/control | \
58                         awk -F'[: ]' '{print "file " $1 " line " $2 " " $4}')
59         FTRACE_ENABLED=$(sysctl --values kernel.ftrace_enabled)
60 }
61
62 function pop_config() {
63         if [[ -n "$DYNAMIC_DEBUG" ]]; then
64                 echo -n "$DYNAMIC_DEBUG" > /sys/kernel/debug/dynamic_debug/control
65         fi
66         if [[ -n "$FTRACE_ENABLED" ]]; then
67                 sysctl kernel.ftrace_enabled="$FTRACE_ENABLED" &> /dev/null
68         fi
69 }
70
71 function set_dynamic_debug() {
72         cat <<-EOF > /sys/kernel/debug/dynamic_debug/control
73                 file kernel/livepatch/* +p
74                 func klp_try_switch_task -p
75                 EOF
76 }
77
78 function set_ftrace_enabled() {
79         local can_fail=0
80         if [[ "$1" == "--fail" ]] ; then
81                 can_fail=1
82                 shift
83         fi
84
85         local err=$(sysctl -q kernel.ftrace_enabled="$1" 2>&1)
86         local result=$(sysctl --values kernel.ftrace_enabled)
87
88         if [[ "$result" != "$1" ]] ; then
89                 if [[ $can_fail -eq 1 ]] ; then
90                         echo "livepatch: $err" | sed 's#/proc/sys/kernel/#kernel.#' > /dev/kmsg
91                         return
92                 fi
93
94                 skip "failed to set kernel.ftrace_enabled = $1"
95         fi
96
97         echo "livepatch: kernel.ftrace_enabled = $result" > /dev/kmsg
98 }
99
100 function cleanup() {
101         pop_config
102         cleanup_dmesg_file
103 }
104
105 # setup_config - save the current config and set a script exit trap that
106 #                restores the original config.  Setup the dynamic debug
107 #                for verbose livepatching output and turn on
108 #                the ftrace_enabled sysctl.
109 function setup_config() {
110         is_root
111         push_config
112         set_dynamic_debug
113         set_ftrace_enabled 1
114         trap cleanup EXIT INT TERM HUP
115 }
116
117 # loop_until(cmd) - loop a command until it is successful or $MAX_RETRIES,
118 #                   sleep $RETRY_INTERVAL between attempts
119 #       cmd - command and its arguments to run
120 function loop_until() {
121         local cmd="$*"
122         local i=0
123         while true; do
124                 eval "$cmd" && return 0
125                 [[ $((i++)) -eq $MAX_RETRIES ]] && return 1
126                 sleep $RETRY_INTERVAL
127         done
128 }
129
130 function assert_mod() {
131         local mod="$1"
132
133         modprobe --dry-run "$mod" &>/dev/null
134 }
135
136 function is_livepatch_mod() {
137         local mod="$1"
138
139         if [[ $(modinfo "$mod" | awk '/^livepatch:/{print $NF}') == "Y" ]]; then
140                 return 0
141         fi
142
143         return 1
144 }
145
146 function __load_mod() {
147         local mod="$1"; shift
148
149         local msg="% modprobe $mod $*"
150         log "${msg%% }"
151         ret=$(modprobe "$mod" "$@" 2>&1)
152         if [[ "$ret" != "" ]]; then
153                 die "$ret"
154         fi
155
156         # Wait for module in sysfs ...
157         loop_until '[[ -e "/sys/module/$mod" ]]' ||
158                 die "failed to load module $mod"
159 }
160
161
162 # load_mod(modname, params) - load a kernel module
163 #       modname - module name to load
164 #       params  - module parameters to pass to modprobe
165 function load_mod() {
166         local mod="$1"; shift
167
168         assert_mod "$mod" ||
169                 skip "unable to load module ${mod}, verify CONFIG_TEST_LIVEPATCH=m and run self-tests as root"
170
171         is_livepatch_mod "$mod" &&
172                 die "use load_lp() to load the livepatch module $mod"
173
174         __load_mod "$mod" "$@"
175 }
176
177 # load_lp_nowait(modname, params) - load a kernel module with a livepatch
178 #                       but do not wait on until the transition finishes
179 #       modname - module name to load
180 #       params  - module parameters to pass to modprobe
181 function load_lp_nowait() {
182         local mod="$1"; shift
183
184         assert_mod "$mod" ||
185                 skip "unable to load module ${mod}, verify CONFIG_TEST_LIVEPATCH=m and run self-tests as root"
186
187         is_livepatch_mod "$mod" ||
188                 die "module $mod is not a livepatch"
189
190         __load_mod "$mod" "$@"
191
192         # Wait for livepatch in sysfs ...
193         loop_until '[[ -e "/sys/kernel/livepatch/$mod" ]]' ||
194                 die "failed to load module $mod (sysfs)"
195 }
196
197 # load_lp(modname, params) - load a kernel module with a livepatch
198 #       modname - module name to load
199 #       params  - module parameters to pass to modprobe
200 function load_lp() {
201         local mod="$1"; shift
202
203         load_lp_nowait "$mod" "$@"
204
205         # Wait until the transition finishes ...
206         loop_until 'grep -q '^0$' /sys/kernel/livepatch/$mod/transition' ||
207                 die "failed to complete transition"
208 }
209
210 # load_failing_mod(modname, params) - load a kernel module, expect to fail
211 #       modname - module name to load
212 #       params  - module parameters to pass to modprobe
213 function load_failing_mod() {
214         local mod="$1"; shift
215
216         local msg="% modprobe $mod $*"
217         log "${msg%% }"
218         ret=$(modprobe "$mod" "$@" 2>&1)
219         if [[ "$ret" == "" ]]; then
220                 die "$mod unexpectedly loaded"
221         fi
222         log "$ret"
223 }
224
225 # unload_mod(modname) - unload a kernel module
226 #       modname - module name to unload
227 function unload_mod() {
228         local mod="$1"
229
230         # Wait for module reference count to clear ...
231         loop_until '[[ $(cat "/sys/module/$mod/refcnt") == "0" ]]' ||
232                 die "failed to unload module $mod (refcnt)"
233
234         log "% rmmod $mod"
235         ret=$(rmmod "$mod" 2>&1)
236         if [[ "$ret" != "" ]]; then
237                 die "$ret"
238         fi
239
240         # Wait for module in sysfs ...
241         loop_until '[[ ! -e "/sys/module/$mod" ]]' ||
242                 die "failed to unload module $mod (/sys/module)"
243 }
244
245 # unload_lp(modname) - unload a kernel module with a livepatch
246 #       modname - module name to unload
247 function unload_lp() {
248         unload_mod "$1"
249 }
250
251 # disable_lp(modname) - disable a livepatch
252 #       modname - module name to unload
253 function disable_lp() {
254         local mod="$1"
255
256         log "% echo 0 > /sys/kernel/livepatch/$mod/enabled"
257         echo 0 > /sys/kernel/livepatch/"$mod"/enabled
258
259         # Wait until the transition finishes and the livepatch gets
260         # removed from sysfs...
261         loop_until '[[ ! -e "/sys/kernel/livepatch/$mod" ]]' ||
262                 die "failed to disable livepatch $mod"
263 }
264
265 # set_pre_patch_ret(modname, pre_patch_ret)
266 #       modname - module name to set
267 #       pre_patch_ret - new pre_patch_ret value
268 function set_pre_patch_ret {
269         local mod="$1"; shift
270         local ret="$1"
271
272         log "% echo $ret > /sys/module/$mod/parameters/pre_patch_ret"
273         echo "$ret" > /sys/module/"$mod"/parameters/pre_patch_ret
274
275         # Wait for sysfs value to hold ...
276         loop_until '[[ $(cat "/sys/module/$mod/parameters/pre_patch_ret") == "$ret" ]]' ||
277                 die "failed to set pre_patch_ret parameter for $mod module"
278 }
279
280 function start_test {
281         local test="$1"
282
283         save_dmesg
284         echo -n "TEST: $test ... "
285         log "===== TEST: $test ====="
286 }
287
288 # check_result() - verify dmesg output
289 #       TODO - better filter, out of order msgs, etc?
290 function check_result {
291         local expect="$*"
292         local result
293
294         # Note: when comparing dmesg output, the kernel log timestamps
295         # help differentiate repeated testing runs.  Remove them with a
296         # post-comparison sed filter.
297
298         result=$(dmesg | comm --nocheck-order -13 "$SAVED_DMESG" - | \
299                  grep -e 'livepatch:' -e 'test_klp' | \
300                  grep -v '\(tainting\|taints\) kernel' | \
301                  sed 's/^\[[ 0-9.]*\] //')
302
303         if [[ "$expect" == "$result" ]] ; then
304                 echo "ok"
305         else
306                 echo -e "not ok\n\n$(diff -upr --label expected --label result <(echo "$expect") <(echo "$result"))\n"
307                 die "livepatch kselftest(s) failed"
308         fi
309
310         cleanup_dmesg_file
311 }
312
313 # check_sysfs_rights(modname, rel_path, expected_rights) - check sysfs
314 # path permissions
315 #       modname - livepatch module creating the sysfs interface
316 #       rel_path - relative path of the sysfs interface
317 #       expected_rights - expected access rights
318 function check_sysfs_rights() {
319         local mod="$1"; shift
320         local rel_path="$1"; shift
321         local expected_rights="$1"; shift
322
323         local path="$KLP_SYSFS_DIR/$mod/$rel_path"
324         local rights=$(/bin/stat --format '%A' "$path")
325         if test "$rights" != "$expected_rights" ; then
326                 die "Unexpected access rights of $path: $expected_rights vs. $rights"
327         fi
328 }
329
330 # check_sysfs_value(modname, rel_path, expected_value) - check sysfs value
331 #       modname - livepatch module creating the sysfs interface
332 #       rel_path - relative path of the sysfs interface
333 #       expected_value - expected value read from the file
334 function check_sysfs_value() {
335         local mod="$1"; shift
336         local rel_path="$1"; shift
337         local expected_value="$1"; shift
338
339         local path="$KLP_SYSFS_DIR/$mod/$rel_path"
340         local value=`cat $path`
341         if test "$value" != "$expected_value" ; then
342                 die "Unexpected value in $path: $expected_value vs. $value"
343         fi
344 }
This page took 0.054898 seconds and 4 git commands to generate.