Running blktests can also help uncover kernel memory leaks when the kernel is built with CONFIG_DEBUG_KMEMLEAK. However, until now the blktests framework had no way to automatically detect or report such leaks. Users typically had to manually setup kmemleak and trigger scans after running tests[1][2]. This change integrates kmemleak support directly into the blktests framework. Before running each test, the framework checks for the presence of /sys/kernel/debug/kmemleak to determine whether kmemleak is enabled for the running kernel. If available, before running a test, any existing kmemleak reports are cleared to avoid false positives from previous tests. After the test completes, the framework explicitly triggers a kmemleak scan. If memory leaks are detected, they are written to a per-test file at, "results/.../.../.kmemleak" and the corresponding test is marked as FAIL. Users can then inspect the .kmemleak file to analyze the reported leaks. With this enhancement, blktests can automatically detect kernel memory leaks (if kerel is configured with CONFIG_DEBUG_KMEMLEAK support) on a per-test basis, removing the need for manual kmemleak setup and scans. This should make it easier and faster to identify memory leaks introduced by individual tests. [1] https://lore.kernel.org/all/CAHj4cs8oJFvz=daCvjHM5dYCNQH4UXwSySPPU4v-WHce_kZXZA@mail.gmail.com/ [2] https://lore.kernel.org/all/CAHj4cs9wv3SdPo+N01Fw2SHBYDs9tj2M_e1-GdQOkRy=DsBB1w@mail.gmail.com/ Signed-off-by: Nilay Shroff --- check | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/check b/check index 6d77d8e..3a6e837 100755 --- a/check +++ b/check @@ -183,6 +183,36 @@ _check_dmesg() { fi } +_setup_kmemleak() { + local f="/sys/kernel/debug/kmemleak" + + if [[ ! -e $f || ! -r $f ]]; then + return 0 + fi + + echo clear > "$f" +} + +_check_kmemleak() { + local kmemleak + local f="/sys/kernel/debug/kmemleak" + + if [[ ! -e $f || ! -r $f ]]; then + return 0 + fi + + echo scan > "$f" + sleep 1 + kmemleak=$(cat "$f") + + if [[ -z $kmemleak ]]; then + return 0 + fi + + printf '%s\n' "$kmemleak" > "${seqres}.kmemleak" + return 1 +} + _read_last_test_run() { local seqres="${RESULTS_DIR}/${TEST_NAME}" @@ -377,6 +407,8 @@ _call_test() { if [[ -v SKIP_REASONS ]]; then TEST_RUN["status"]="not run" else + _setup_kmemleak + if [[ -w /dev/kmsg ]]; then local dmesg_marker="run blktests $TEST_NAME at ${TEST_RUN["date"]}" echo "$dmesg_marker" >> /dev/kmsg @@ -414,6 +446,9 @@ _call_test() { elif ! _check_dmesg "$dmesg_marker"; then TEST_RUN["status"]=fail TEST_RUN["reason"]=dmesg + elif ! _check_kmemleak; then + TEST_RUN["status"]=fail + TEST_RUN["reason"]=kmemleak else TEST_RUN["status"]=pass fi @@ -451,6 +486,18 @@ _call_test() { print \" \" \$0 }" "${seqres}.dmesg" ;; + kmemleak) + echo " kmemleak detected:" + awk " + { + if (NR > 10) { + print \" ...\" + print \" (See '${seqres}.kmemleak' for the entire message)\" + exit + } + print \" \" \$0 + }" "${seqres}.kmemleak" + ;; esac return 1 else -- 2.52.0