Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3# Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com>
4
5# Shell functions for the rest of the scripts.
6
7MAX_RETRIES=600
8RETRY_INTERVAL=".1" # seconds
9
10# log(msg) - write message to kernel log
11# msg - insightful words
12function log() {
13 echo "$1" > /dev/kmsg
14}
15
16# die(msg) - game over, man
17# msg - dying words
18function die() {
19 log "ERROR: $1"
20 echo "ERROR: $1" >&2
21 exit 1
22}
23
24# set_dynamic_debug() - setup kernel dynamic debug
25# TODO - push and pop this config?
26function set_dynamic_debug() {
27 cat << EOF > /sys/kernel/debug/dynamic_debug/control
28file kernel/livepatch/* +p
29func klp_try_switch_task -p
30EOF
31}
32
33# loop_until(cmd) - loop a command until it is successful or $MAX_RETRIES,
34# sleep $RETRY_INTERVAL between attempts
35# cmd - command and its arguments to run
36function loop_until() {
37 local cmd="$*"
38 local i=0
39 while true; do
40 eval "$cmd" && return 0
41 [[ $((i++)) -eq $MAX_RETRIES ]] && return 1
42 sleep $RETRY_INTERVAL
43 done
44}
45
46function is_livepatch_mod() {
47 local mod="$1"
48
49 if [[ $(modinfo "$mod" | awk '/^livepatch:/{print $NF}') == "Y" ]]; then
50 return 0
51 fi
52
53 return 1
54}
55
56function __load_mod() {
57 local mod="$1"; shift
58
59 local msg="% modprobe $mod $*"
60 log "${msg%% }"
61 ret=$(modprobe "$mod" "$@" 2>&1)
62 if [[ "$ret" != "" ]]; then
63 die "$ret"
64 fi
65
66 # Wait for module in sysfs ...
67 loop_until '[[ -e "/sys/module/$mod" ]]' ||
68 die "failed to load module $mod"
69}
70
71
72# load_mod(modname, params) - load a kernel module
73# modname - module name to load
74# params - module parameters to pass to modprobe
75function load_mod() {
76 local mod="$1"; shift
77
78 is_livepatch_mod "$mod" &&
79 die "use load_lp() to load the livepatch module $mod"
80
81 __load_mod "$mod" "$@"
82}
83
84# load_lp_nowait(modname, params) - load a kernel module with a livepatch
85# but do not wait on until the transition finishes
86# modname - module name to load
87# params - module parameters to pass to modprobe
88function load_lp_nowait() {
89 local mod="$1"; shift
90
91 is_livepatch_mod "$mod" ||
92 die "module $mod is not a livepatch"
93
94 __load_mod "$mod" "$@"
95
96 # Wait for livepatch in sysfs ...
97 loop_until '[[ -e "/sys/kernel/livepatch/$mod" ]]' ||
98 die "failed to load module $mod (sysfs)"
99}
100
101# load_lp(modname, params) - load a kernel module with a livepatch
102# modname - module name to load
103# params - module parameters to pass to modprobe
104function load_lp() {
105 local mod="$1"; shift
106
107 load_lp_nowait "$mod" "$@"
108
109 # Wait until the transition finishes ...
110 loop_until 'grep -q '^0$' /sys/kernel/livepatch/$mod/transition' ||
111 die "failed to complete transition"
112}
113
114# load_failing_mod(modname, params) - load a kernel module, expect to fail
115# modname - module name to load
116# params - module parameters to pass to modprobe
117function load_failing_mod() {
118 local mod="$1"; shift
119
120 local msg="% modprobe $mod $*"
121 log "${msg%% }"
122 ret=$(modprobe "$mod" "$@" 2>&1)
123 if [[ "$ret" == "" ]]; then
124 die "$mod unexpectedly loaded"
125 fi
126 log "$ret"
127}
128
129# unload_mod(modname) - unload a kernel module
130# modname - module name to unload
131function unload_mod() {
132 local mod="$1"
133
134 # Wait for module reference count to clear ...
135 loop_until '[[ $(cat "/sys/module/$mod/refcnt") == "0" ]]' ||
136 die "failed to unload module $mod (refcnt)"
137
138 log "% rmmod $mod"
139 ret=$(rmmod "$mod" 2>&1)
140 if [[ "$ret" != "" ]]; then
141 die "$ret"
142 fi
143
144 # Wait for module in sysfs ...
145 loop_until '[[ ! -e "/sys/module/$mod" ]]' ||
146 die "failed to unload module $mod (/sys/module)"
147}
148
149# unload_lp(modname) - unload a kernel module with a livepatch
150# modname - module name to unload
151function unload_lp() {
152 unload_mod "$1"
153}
154
155# disable_lp(modname) - disable a livepatch
156# modname - module name to unload
157function disable_lp() {
158 local mod="$1"
159
160 log "% echo 0 > /sys/kernel/livepatch/$mod/enabled"
161 echo 0 > /sys/kernel/livepatch/"$mod"/enabled
162
163 # Wait until the transition finishes and the livepatch gets
164 # removed from sysfs...
165 loop_until '[[ ! -e "/sys/kernel/livepatch/$mod" ]]' ||
166 die "failed to disable livepatch $mod"
167}
168
169# set_pre_patch_ret(modname, pre_patch_ret)
170# modname - module name to set
171# pre_patch_ret - new pre_patch_ret value
172function set_pre_patch_ret {
173 local mod="$1"; shift
174 local ret="$1"
175
176 log "% echo $ret > /sys/module/$mod/parameters/pre_patch_ret"
177 echo "$ret" > /sys/module/"$mod"/parameters/pre_patch_ret
178
179 # Wait for sysfs value to hold ...
180 loop_until '[[ $(cat "/sys/module/$mod/parameters/pre_patch_ret") == "$ret" ]]' ||
181 die "failed to set pre_patch_ret parameter for $mod module"
182}
183
184# check_result() - verify dmesg output
185# TODO - better filter, out of order msgs, etc?
186function check_result {
187 local expect="$*"
188 local result
189
190 result=$(dmesg | grep -v 'tainting' | grep -e 'livepatch:' -e 'test_klp' | sed 's/^\[[ 0-9.]*\] //')
191
192 if [[ "$expect" == "$result" ]] ; then
193 echo "ok"
194 else
195 echo -e "not ok\n\n$(diff -upr --label expected --label result <(echo "$expect") <(echo "$result"))\n"
196 die "livepatch kselftest(s) failed"
197 fi
198}