blob: 8b6cd56e79104e397265a0d4863172b9fea8f44a [file] [log] [blame]
Anders Roxelle3f51b82024-07-04 12:30:01 +02001#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0-only
3# Copyright (C) 2024 Linaro Ltd.
4
5# shellcheck disable=SC1091
6. ../../lib/sh-test-lib
7OUTPUT="$(pwd)/output"
8RESULT_FILE="${OUTPUT}/result.txt"
9export RESULT_FILE
10
11MODULES_LIST=""
12MODULES_SUBDIRS=""
13MODULE_MODPROBE_NUMBER="1"
Anders Roxell8aa8dbf2024-07-11 14:42:19 +020014SKIPLIST=""
Anders Roxelle3f51b82024-07-04 12:30:01 +020015SHARD_NUMBER=1
16SHARD_INDEX=1
Anders Roxell261c1ee2025-07-02 09:17:39 +020017MEMORY_TOLERANCE=512
Anders Roxelle3f51b82024-07-04 12:30:01 +020018
19usage() {
20 echo "Usage: $0 [-d <subdir of the modules directory> ]
21 [-l <space separated module list> ]
22 [-c <Number of load/unload of a module> ]
23 [-i <sharding bucket to run> ]
24 [-n <number of shard buckets to create> ]
Anders Roxell8aa8dbf2024-07-11 14:42:19 +020025 [-s <skiplist modules to skip> ]
Anders Roxell261c1ee2025-07-02 09:17:39 +020026 [-t <memory tolerance in KB for leak detection> ]
Anders Roxelle3f51b82024-07-04 12:30:01 +020027 [-h ]" 1>&2
28 exit 0
29}
30
Anders Roxell261c1ee2025-07-02 09:17:39 +020031while getopts "c:d:i:l:n:s:t:h" o; do
Anders Roxelle3f51b82024-07-04 12:30:01 +020032 case "$o" in
33 d) MODULES_SUBDIRS="${OPTARG}" ;;
34 l) MODULES_LIST="${OPTARG}" ;;
35 c) MODULE_MODPROBE_NUMBER="${OPTARG}" ;;
36 i) SHARD_INDEX="${OPTARG}" ;;
37 n) SHARD_NUMBER="${OPTARG}" ;;
Anders Roxell8aa8dbf2024-07-11 14:42:19 +020038 s) SKIPLIST="${OPTARG}" ;;
Anders Roxell261c1ee2025-07-02 09:17:39 +020039 t) MEMORY_TOLERANCE="${OPTARG}" ;;
Anders Roxelle3f51b82024-07-04 12:30:01 +020040 h|*) usage ;;
41 esac
42done
43
Anders Roxellcb19cb92025-06-06 00:25:27 +020044get_mem_usage_kb() {
45 grep -i "MemAvailable:" /proc/meminfo | awk '{ print $2 }'
46}
47
Anders Roxellb8562562025-07-02 09:06:40 +020048check_module_memory_leaks_cumulative() {
Anders Roxell9d498ad2025-07-02 09:07:09 +020049 local module=$1
50 local mem_start=$2
51 local mem_end=$3
Anders Roxellcb19cb92025-06-06 00:25:27 +020052 local diff_kb
Anders Roxell9d498ad2025-07-02 09:07:09 +020053 diff_kb=$((mem_start - mem_end))
54 echo "memcheck cumulative: start ${mem_start}, end ${mem_end}, diff ${diff_kb}"
Anders Roxell261c1ee2025-07-02 09:17:39 +020055 if [ "$diff_kb" -lt "-${MEMORY_TOLERANCE}" ]; then
Anders Roxellcb19cb92025-06-06 00:25:27 +020056 report_fail "memcheck_${module}"
57 else
58 report_pass "memcheck_${module}"
59 fi
60}
61
Anders Roxelle3f51b82024-07-04 12:30:01 +020062get_modules_list() {
63 if [ -z "${MODULES_LIST}" ]; then
Anders Roxell25fd9512025-04-28 13:50:31 +020064 if [ -n "${MODULES_SUBDIRS}" ]; then
65 subdir=$(echo "${MODULES_SUBDIRS}" | tr ' ' '|')
66 grep -E "kernel/(${subdir})" /lib/modules/"$(uname -r)"/modules.order > /tmp/find_modules.txt
67 else
68 # No subdir given, default to all modules
69 cat /lib/modules/"$(uname -r)"/modules.order > /tmp/find_modules.txt
70 fi
71
72 if [ -n "${SKIPLIST}" ]; then
73 skiplist=$(echo "${SKIPLIST}" | tr ' ' '|')
74 grep -E -v "(${skiplist})" /tmp/find_modules.txt > /tmp/modules_to_run.txt
75 else
76 cp /tmp/find_modules.txt /tmp/modules_to_run.txt
77 fi
78
Anders Roxell8aa8dbf2024-07-11 14:42:19 +020079 split --verbose --numeric-suffixes=1 -n l/"${SHARD_INDEX}"/"${SHARD_NUMBER}" /tmp/modules_to_run.txt > /tmp/shardfile
Anders Roxellbde4f2e2024-07-09 19:29:06 +020080 echo "============== Tests to run ==============="
81 cat /tmp/shardfile
82 echo "===========End Tests to run ==============="
83 if [ -s /tmp/shardfile ]; then
84 report_pass "shardfile"
85 else
86 report_fail "shardfile"
87 fi
Anders Roxelle3f51b82024-07-04 12:30:01 +020088 while IFS= read -r line
89 do
90 module_basename=$(basename "${line}")
91 module_name=${module_basename%.*}
92 MODULES_LIST="${MODULES_LIST} ${module_name}"
93 done < /tmp/shardfile
94 fi
95}
96
97report() {
98 local _modprop_flag="${1}"
99 local _module="${2}"
100 local _text="${3}"
101 local _num="${4}"
102 echo
103 echo "${_text} module: ${_module}"
104 if ! modprobe "${_module}" "${_modprop_flag}"; then
105 report_fail "${_text}_module_${_num}_${_module}"
106 else
107 report_pass "${_text}_module_${_num}_${_module}"
108 fi
109}
110
Anders Roxella7b173b2025-04-28 12:24:19 +0200111scan_dmesg_for_errors() {
112 echo "=== Scanning dmesg for errors ==="
113 dmesg -l 0,1,2,3,4,5 | grep -Ei "BUG:|WARNING:|Oops:|Call Trace:" && report_fail "dmesg_error_scan" || report_pass "dmesg_error_scan"
114}
115
Anders Roxelle6199bd2025-04-28 12:25:03 +0200116check_module_unloaded() {
117 local _module="$1"
118 if lsmod | grep "^${_module} " > /dev/null; then
119 echo "Module ${_module} still loaded after removal!"
120 report_fail "module_stuck_${_module}"
121 else
122 report_pass "module_unloaded_${_module}"
123 fi
124}
125
Anders Roxellad114aa2025-04-28 12:25:26 +0200126kmemleak_scan() {
127 if [ -e /sys/kernel/debug/kmemleak ]; then
128 echo "Triggering kmemleak scan..."
129 echo scan > /sys/kernel/debug/kmemleak
130 sleep 5
131 if grep -q . /sys/kernel/debug/kmemleak; then
132 echo "Potential memory leaks detected:"
133 cat /sys/kernel/debug/kmemleak
134 report_fail "kmemleak_detected"
135 else
136 report_pass "kmemleak_no_leaks"
137 fi
138 else
139 echo "kmemleak not available, skipping scan."
140 fi
141}
142
Anders Roxelle3f51b82024-07-04 12:30:01 +0200143run () {
144 for module in ${MODULES_LIST}; do
145 # don't insert/remove modules that is already inserted.
146 if ! lsmod | grep "^${module}"; then
147 for num in $(seq "${MODULE_MODPROBE_NUMBER}"); do
148 dmesg -C
Anders Roxellcb19cb92025-06-06 00:25:27 +0200149 mem_before=$(get_mem_usage_kb)
Anders Roxelle3f51b82024-07-04 12:30:01 +0200150 report "" "${module}" "insert" "${num}"
151 echo
152 echo "modinfo ${module}"
153 modinfo "${module}"
Anders Roxella7b173b2025-04-28 12:24:19 +0200154 scan_dmesg_for_errors
155
Anders Roxelle3f51b82024-07-04 12:30:01 +0200156 report "--remove" "${module}" "remove" "${num}"
Anders Roxella7b173b2025-04-28 12:24:19 +0200157 scan_dmesg_for_errors
Anders Roxelle6199bd2025-04-28 12:25:03 +0200158
159 check_module_unloaded "${module}"
Anders Roxellcb19cb92025-06-06 00:25:27 +0200160 mem_after=$(get_mem_usage_kb)
Anders Roxellb8562562025-07-02 09:06:40 +0200161 check_module_memory_leaks_cumulative "$mem_before" "$mem_after" "$module"
Anders Roxelle3f51b82024-07-04 12:30:01 +0200162 done
163 fi
164 done
165}
166
167# Test run.
168! check_root && error_msg "This script must be run as root"
169create_out_dir "${OUTPUT}"
170info_msg "Output directory: ${OUTPUT}"
171info_msg "About to run load/unload kernel modules ..."
172get_modules_list
173run
Anders Roxellad114aa2025-04-28 12:25:26 +0200174kmemleak_scan