[PATCH v3 2/4] kunit: add assertions for lockdep inside of kunit

From: Malte Wechter

Date: Tue Oct 13 2026 - 06:33:11 EST


assert that `debug_locks` are on prior to running a kunit testcase and
assert that `debug_locks` has not been turned off while the test has run.
The assertions are gated behind `CONFIG_KUNIT_FAIL_TEST_ON_LOCKDEP=y`,
if it is not enabled, writing and running kunit test cases that trigger
a lockdep warning does _not_ fail the test if the test itself passes.
If enabled, it marks any test that triggers a lockdep warning as failed,
and forcefully skips all proceeding test cases, implying that the kernel
is now seen as unreliable since `debug_locks` are off. Failing a test
when lockdep reports a problem is useful for any unit test that takes
locks, locking bugs are caught by the test that triggered them,
instead of being silently logged and missed.

Signed-off-by: Malte Wechter <maltewechter@xxxxxxxxx>
---
lib/kunit/test.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)

diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 0e3ed457daca..1292a0799c33 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -6,6 +6,7 @@
* Author: Brendan Higgins <brendanhiggins@xxxxxxxxxx>
*/

+#include <linux/debug_locks.h>
#include <kunit/resource.h>
#include <kunit/test.h>
#include <kunit/test-bug.h>
@@ -80,6 +81,29 @@ void __printf(3, 4) __kunit_fail_current_test_impl(const char *file, int line, c
kunit_kfree(current->kunit_test, buffer);
}

+/*
+ * Fails current test if test turns off debug_locks.
+ */
+static void kunit_check_lockdep(struct kunit *test, int prev_debug_locks)
+{
+ if (IS_ENABLED(CONFIG_KUNIT_FAIL_TEST_ON_LOCKDEP) && !debug_locks && prev_debug_locks) {
+ kunit_err(test, "Test triggered a lockdep warning");
+ kunit_set_failure(test);
+ }
+}
+
+/*
+ * Skip a KUnit test if debug_locks is turned off by lockdep.
+ */
+static void kunit_skip_if_lockdep(struct kunit *test, struct kunit_suite *suite)
+{
+ if (IS_ENABLED(CONFIG_KUNIT_FAIL_TEST_ON_LOCKDEP) && !debug_locks) {
+ suite->forced_skip = true;
+ test->forced_skip = true;
+ kunit_skip(test, "force skip: debug_locks are off");
+ }
+}
+
/*
* Enable KUnit tests to run.
*/
@@ -462,6 +486,8 @@ static void kunit_run_case_internal(struct kunit *test,
{
struct timespec64 start, end;

+ kunit_skip_if_lockdep(test, suite);
+
if (suite->init) {
int ret;

@@ -512,6 +538,7 @@ static void kunit_try_run_case(void *data)
struct kunit *test = ctx->test;
struct kunit_suite *suite = ctx->suite;
struct kunit_case *test_case = ctx->test_case;
+ int debug_locks_snapshot = debug_locks;

current->kunit_test = test;

@@ -521,6 +548,8 @@ static void kunit_try_run_case(void *data)
* thread will resume control and handle any necessary clean up.
*/
kunit_run_case_internal(test, suite, test_case);
+
+ kunit_check_lockdep(test, debug_locks_snapshot);
}

static void kunit_try_run_case_cleanup(void *data)

--
2.54.0