KUnit will fail tests upon observing a lockdep failure. Because lockdep turns itself off after its first failure, only fail the first test and warn users to not expect any future failures from lockdep. Similar to lib/locking-selftest [1], we check if the status of debug_locks has changed after the execution of a test case. However, we do not reset lockdep afterwards. Like the locking selftests, we also fix possible preemption count corruption from lock bugs. Depends on kunit: support failure from dynamic analysis tools [2] [1] https://elixir.bootlin.com/linux/v5.7.12/source/lib/locking-selftest.c#L1137 [2] https://lore.kernel.org/linux-kselftest/20200806174326.3577537-1-urielguajardojr@xxxxxxxxx/ Signed-off-by: Uriel Guajardo <urielguajardo@xxxxxxxxxx> --- v2 Changes: - Removed lockdep_reset - Added warning to users about lockdep shutting off --- lib/kunit/test.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/kunit/test.c b/lib/kunit/test.c index d8189d827368..7e477482457b 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -11,6 +11,7 @@ #include <linux/kref.h> #include <linux/sched/debug.h> #include <linux/sched.h> +#include <linux/debug_locks.h> #include "debugfs.h" #include "string-stream.h" @@ -22,6 +23,26 @@ void kunit_fail_current_test(void) kunit_set_failure(current->kunit_test); } +static void kunit_check_locking_bugs(struct kunit *test, + unsigned long saved_preempt_count, + bool saved_debug_locks) +{ + preempt_count_set(saved_preempt_count); +#ifdef CONFIG_TRACE_IRQFLAGS + if (softirq_count()) + current->softirqs_enabled = 0; + else + current->softirqs_enabled = 1; +#endif +#if IS_ENABLED(CONFIG_LOCKDEP) + if (saved_debug_locks && !debug_locks) { + kunit_set_failure(test); + kunit_warn(test, "Dynamic analysis tool failure from LOCKDEP."); + kunit_warn(test, "Further tests will have LOCKDEP disabled."); + } +#endif +} + static void kunit_print_tap_version(void) { static bool kunit_has_printed_tap_version; @@ -290,6 +311,9 @@ static void kunit_try_run_case(void *data) struct kunit_suite *suite = ctx->suite; struct kunit_case *test_case = ctx->test_case; + unsigned long saved_preempt_count = preempt_count(); + bool saved_debug_locks = debug_locks; + current->kunit_test = test; /* @@ -298,7 +322,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); - /* This line may never be reached. */ + /* These lines may never be reached. */ + kunit_check_locking_bugs(test, saved_preempt_count, saved_debug_locks); kunit_run_case_cleanup(test, suite); } -- 2.28.0.236.gb10cc79966-goog