-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathck_state.sh
executable file
·106 lines (81 loc) · 2.52 KB
/
ck_state.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/env bash
set -eu -o pipefail
SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
usage() {
printf "Usage: %s MOD_NAME CHECK_STATE
MOD_NAME\\t: name of kernel module
CHECK_STATE\\t: patch state to check. 0 is unpatched and 1 is patched.
eg,
%s no_fscache 0 # check unpatched state for module no_fscache
See livepatch consistency model for details:
https://www.kernel.org/doc/Documentation/livepatch/livepatch.txt
" "$SCRIPT_NAME" "$SCRIPT_NAME"
}
if [[ "$#" -ne 2 ]]; then
usage
exit 1
fi
mod_name="$1"
mod_sysfs_if=/sys/kernel/livepatch/"$mod_name"
if [[ ! -d "$mod_sysfs_if" ]]; then
printf "[Error] Module %s does not exist in sysfs interface path %s\n\n" "$mod_name" "$(dirname "$mod_sysfs_if")"
exit 2
fi
check_state="$2"
if [[ "$check_state" -ne 0 && "$check_state" -ne 1 ]]; then
printf "[Error] CHECK_STATE can only be 0 or 1.\\n\\n"
usage
exit 2
fi
if [[ $EUID -ne 0 ]]; then
printf "[Error] This script must be run as root.\\n\\n"
usage
exit 3
fi
MAX_SHOW_NUM_TASKS=5
print_blocking_tasks() {
local blocking_tasks=()
for ps in /proc/*/task/*/patch_state; do
local tid task_path patch_state
tid="$(echo "$ps" | cut -d '/' -f 5)"
task_path=/proc/"${tid}"
# the process may not exist at this time
patch_state="$(cat "$task_path"/patch_state 2>/dev/null || true)"
if [[ "${patch_state:--1}" -eq "$check_state" ]]; then
blocking_tasks+=("$tid")
fi
done
if [[ "${#blocking_tasks[@]}" -ne 0 ]]; then
local blocking_tids results lines num_results
blocking_tids="$(
IFS=,
echo "${blocking_tasks[@]}"
)"
results="$(ps -eo user,pid,tid,cmd -q "$blocking_tids" || true)"
lines=$(echo "$results" | wc -l)
num_results=$((lines - 1))
if [[ "$num_results" -gt 0 ]]; then
printf "[INFO] %d tasks are not in %s state:\\n" \
"$num_results" \
"$([[ "$check_state" -eq 1 ]] && echo unpatched || echo patched)"
# show +1 lines of results because of the header line
echo "$results" | head -$((MAX_SHOW_NUM_TASKS + 1))
if [[ "$num_results" -gt "$MAX_SHOW_NUM_TASKS" ]]; then
printf "... %d more\\n" "$((num_results - MAX_SHOW_NUM_TASKS))"
fi
echo
fi
fi
}
CHECK_FREQ_IN_SECS=2
printf "[INFO] Checking transition state for module %s (update every %ds)...\n\n" \
"$mod_name" \
"$CHECK_FREQ_IN_SECS"
while :; do
transition_state="$(cat "$mod_sysfs_if"/transition)"
if [[ "$transition_state" -eq 0 ]]; then
break
fi
print_blocking_tasks
sleep "$CHECK_FREQ_IN_SECS"
done