Assert that the kernel is not tainted with `TAINT_WARN` prior to running a KUnit test case, and assert that it has not become tainted with `TAINT_WARN` while the test has run. If this is not enabled, writing and running KUnit test cases that trigger a `WARN()` does not fail the test if the test itself passes. If enabled, it marks any test that triggers a warning as failed, and forcefully skips all proceeding test cases, since the taint cannot be cleared and the kernel is now seen as unreliable. The assertions are gated behind `CONFIG_KUNIT_FAIL_TEST_ON_WARN=y`
Signed-off-by: Malte Wechter <[email protected]> --- lib/kunit/test.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 1292a0799c33..6d6f1e947db5 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -81,6 +81,30 @@ 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 TAINT_WARN has been set (changed) after the test has run. + */ +static void kunit_check_taint_warn(struct kunit *test, unsigned long tainted_before) +{ + if (IS_ENABLED(CONFIG_KUNIT_FAIL_TEST_ON_WARN) && + test_taint(TAINT_WARN) && !tainted_before) { + kunit_err(test, "Test triggered a kernel WARN"); + kunit_set_failure(test); + } +} + +/* + * Skip a KUnit test if the kernel is tainted with TAINT_WARN. + */ +static void kunit_skip_if_taint_warn(struct kunit *test, struct kunit_suite *suite) +{ + if (IS_ENABLED(CONFIG_KUNIT_FAIL_TEST_ON_WARN) && test_taint(TAINT_WARN)) { + suite->forced_skip = true; + test->forced_skip = true; + kunit_skip(test, "force skip: kernel is tainted with TAINT_WARN"); + } +} + /* * Fails current test if test turns off debug_locks. */ @@ -487,6 +511,7 @@ static void kunit_run_case_internal(struct kunit *test, struct timespec64 start, end; kunit_skip_if_lockdep(test, suite); + kunit_skip_if_taint_warn(test, suite); if (suite->init) { int ret; @@ -539,6 +564,7 @@ static void kunit_try_run_case(void *data) struct kunit_suite *suite = ctx->suite; struct kunit_case *test_case = ctx->test_case; int debug_locks_snapshot = debug_locks; + unsigned long tainted_warn_snapshot = test_taint(TAINT_WARN); current->kunit_test = test; @@ -549,6 +575,7 @@ static void kunit_try_run_case(void *data) */ kunit_run_case_internal(test, suite, test_case); + kunit_check_taint_warn(test, tainted_warn_snapshot); kunit_check_lockdep(test, debug_locks_snapshot); } -- 2.54.0

