mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 01:08:13 -04:00
kunit: Add backtrace suppression self-tests
Add unit tests to verify that warning backtrace suppression works. Tests cover both API forms: - Scoped: kunit_warning_suppress() with in-block count verification and post-block inactivity check. - Direct functions: kunit_start/end_suppress_warning() with sequential independent suppression blocks and per-block counts. Furthermore, tests verify incremental warning counting, that kunit_has_active_suppress_warning() transitions correctly around suppression boundaries, and that suppression active in the test kthread does not leak to a separate kthread. If backtrace suppression does _not_ work, the unit tests will likely trigger unsuppressed backtraces, which should actually help to get the affected architectures / platforms fixed. Link: https://lore.kernel.org/r/20260514-kunit_add_support-v11-2-b36a530a6d8f@redhat.com Tested-by: Linux Kernel Functional Testing <lkft@linaro.org> Acked-by: Dan Carpenter <dan.carpenter@linaro.org> Reviewed-by: Kees Cook <keescook@chromium.org> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Alessandro Carminati <acarmina@redhat.com> Reviewed-by: David Gow <david@davidgow.net> Signed-off-by: Albert Esteve <aesteve@redhat.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
This commit is contained in:
committed by
Shuah Khan
parent
85347718ab
commit
bbc960d009
@@ -22,6 +22,7 @@ obj-$(if $(CONFIG_KUNIT),y) += hooks.o
|
||||
|
||||
obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
|
||||
obj-$(CONFIG_KUNIT_TEST) += platform-test.o
|
||||
obj-$(CONFIG_KUNIT_TEST) += backtrace-suppression-test.o
|
||||
|
||||
# string-stream-test compiles built-in only.
|
||||
ifeq ($(CONFIG_KUNIT_TEST),y)
|
||||
|
||||
198
lib/kunit/backtrace-suppression-test.c
Normal file
198
lib/kunit/backtrace-suppression-test.c
Normal file
@@ -0,0 +1,198 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* KUnit test for suppressing warning tracebacks.
|
||||
*
|
||||
* Copyright (C) 2024, Guenter Roeck
|
||||
* Author: Guenter Roeck <linux@roeck-us.net>
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
static void backtrace_suppression_test_warn_direct(struct kunit *test)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BUG))
|
||||
kunit_skip(test, "requires CONFIG_BUG");
|
||||
|
||||
kunit_warning_suppress(test) {
|
||||
WARN(1, "This backtrace should be suppressed");
|
||||
/*
|
||||
* Count must be checked inside the scope; the handle
|
||||
* is not accessible after the block exits.
|
||||
*/
|
||||
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
|
||||
}
|
||||
KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
|
||||
}
|
||||
|
||||
static noinline void trigger_backtrace_warn(void)
|
||||
{
|
||||
WARN(1, "This backtrace should be suppressed");
|
||||
}
|
||||
|
||||
static void backtrace_suppression_test_warn_indirect(struct kunit *test)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BUG))
|
||||
kunit_skip(test, "requires CONFIG_BUG");
|
||||
|
||||
kunit_warning_suppress(test) {
|
||||
trigger_backtrace_warn();
|
||||
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void backtrace_suppression_test_warn_multi(struct kunit *test)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BUG))
|
||||
kunit_skip(test, "requires CONFIG_BUG");
|
||||
|
||||
kunit_warning_suppress(test) {
|
||||
WARN(1, "This backtrace should be suppressed");
|
||||
trigger_backtrace_warn();
|
||||
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void backtrace_suppression_test_warn_on_direct(struct kunit *test)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BUG))
|
||||
kunit_skip(test, "requires CONFIG_BUG");
|
||||
if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE) && !IS_ENABLED(CONFIG_KALLSYMS))
|
||||
kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE or CONFIG_KALLSYMS");
|
||||
|
||||
kunit_warning_suppress(test) {
|
||||
WARN_ON(1);
|
||||
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static noinline void trigger_backtrace_warn_on(void)
|
||||
{
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static void backtrace_suppression_test_warn_on_indirect(struct kunit *test)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BUG))
|
||||
kunit_skip(test, "requires CONFIG_BUG");
|
||||
if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE))
|
||||
kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE");
|
||||
|
||||
kunit_warning_suppress(test) {
|
||||
trigger_backtrace_warn_on();
|
||||
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void backtrace_suppression_test_count(struct kunit *test)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BUG))
|
||||
kunit_skip(test, "requires CONFIG_BUG");
|
||||
|
||||
kunit_warning_suppress(test) {
|
||||
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 0);
|
||||
|
||||
WARN(1, "suppressed");
|
||||
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
|
||||
|
||||
WARN(1, "suppressed again");
|
||||
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void backtrace_suppression_test_active_state(struct kunit *test)
|
||||
{
|
||||
KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
|
||||
|
||||
kunit_warning_suppress(test) {
|
||||
KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
|
||||
}
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
|
||||
|
||||
kunit_warning_suppress(test) {
|
||||
KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
|
||||
}
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
|
||||
}
|
||||
|
||||
static void backtrace_suppression_test_multi_scope(struct kunit *test)
|
||||
{
|
||||
struct kunit_suppressed_warning *sw1, *sw2;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BUG))
|
||||
kunit_skip(test, "requires CONFIG_BUG");
|
||||
if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE))
|
||||
kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE");
|
||||
|
||||
sw1 = kunit_start_suppress_warning(test);
|
||||
trigger_backtrace_warn_on();
|
||||
WARN(1, "suppressed by sw1");
|
||||
kunit_end_suppress_warning(test, sw1);
|
||||
|
||||
sw2 = kunit_start_suppress_warning(test);
|
||||
WARN(1, "suppressed by sw2");
|
||||
kunit_end_suppress_warning(test, sw2);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw1), 2);
|
||||
KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw2), 1);
|
||||
}
|
||||
|
||||
struct cross_kthread_data {
|
||||
bool was_active;
|
||||
struct completion done;
|
||||
};
|
||||
|
||||
static int cross_kthread_fn(void *data)
|
||||
{
|
||||
struct cross_kthread_data *d = data;
|
||||
|
||||
d->was_active = kunit_has_active_suppress_warning();
|
||||
complete(&d->done);
|
||||
while (!kthread_should_stop())
|
||||
schedule();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void backtrace_suppression_test_cross_kthread(struct kunit *test)
|
||||
{
|
||||
struct cross_kthread_data data;
|
||||
struct task_struct *task;
|
||||
|
||||
data.was_active = false;
|
||||
init_completion(&data.done);
|
||||
|
||||
kunit_warning_suppress(test) {
|
||||
task = kthread_run(cross_kthread_fn, &data, "kunit-cross-test");
|
||||
KUNIT_ASSERT_FALSE(test, IS_ERR(task));
|
||||
wait_for_completion(&data.done);
|
||||
kthread_stop(task);
|
||||
}
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, data.was_active);
|
||||
}
|
||||
|
||||
static struct kunit_case backtrace_suppression_test_cases[] = {
|
||||
KUNIT_CASE(backtrace_suppression_test_warn_direct),
|
||||
KUNIT_CASE(backtrace_suppression_test_warn_indirect),
|
||||
KUNIT_CASE(backtrace_suppression_test_warn_multi),
|
||||
KUNIT_CASE(backtrace_suppression_test_warn_on_direct),
|
||||
KUNIT_CASE(backtrace_suppression_test_warn_on_indirect),
|
||||
KUNIT_CASE(backtrace_suppression_test_count),
|
||||
KUNIT_CASE(backtrace_suppression_test_active_state),
|
||||
KUNIT_CASE(backtrace_suppression_test_multi_scope),
|
||||
KUNIT_CASE(backtrace_suppression_test_cross_kthread),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite backtrace_suppression_test_suite = {
|
||||
.name = "backtrace-suppression-test",
|
||||
.test_cases = backtrace_suppression_test_cases,
|
||||
};
|
||||
kunit_test_suites(&backtrace_suppression_test_suite);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("KUnit test to verify warning backtrace suppression");
|
||||
Reference in New Issue
Block a user