projects/linux·blob master · refs

198 lines · 5.3 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * KUnit test for suppressing warning tracebacks.
4 *
5 * Copyright (C) 2024, Guenter Roeck
6 * Author: Guenter Roeck <[email protected]>
7 */
8
9#include <kunit/test.h>
10#include <linux/bug.h>
11#include <linux/completion.h>
12#include <linux/kthread.h>
13
14static void backtrace_suppression_test_warn_direct(struct kunit *test)
15{
16 if (!IS_ENABLED(CONFIG_BUG))
17 kunit_skip(test, "requires CONFIG_BUG");
18
19 kunit_warning_suppress(test) {
20 WARN(1, "This backtrace should be suppressed");
21 /*
22 * Count must be checked inside the scope; the handle
23 * is not accessible after the block exits.
24 */
25 KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
26 }
27 KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
28}
29
30static noinline void trigger_backtrace_warn(void)
31{
32 WARN(1, "This backtrace should be suppressed");
33}
34
35static void backtrace_suppression_test_warn_indirect(struct kunit *test)
36{
37 if (!IS_ENABLED(CONFIG_BUG))
38 kunit_skip(test, "requires CONFIG_BUG");
39
40 kunit_warning_suppress(test) {
41 trigger_backtrace_warn();
42 KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
43 }
44}
45
46static void backtrace_suppression_test_warn_multi(struct kunit *test)
47{
48 if (!IS_ENABLED(CONFIG_BUG))
49 kunit_skip(test, "requires CONFIG_BUG");
50
51 kunit_warning_suppress(test) {
52 WARN(1, "This backtrace should be suppressed");
53 trigger_backtrace_warn();
54 KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
55 }
56}
57
58static void backtrace_suppression_test_warn_on_direct(struct kunit *test)
59{
60 if (!IS_ENABLED(CONFIG_BUG))
61 kunit_skip(test, "requires CONFIG_BUG");
62 if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE) && !IS_ENABLED(CONFIG_KALLSYMS))
63 kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE or CONFIG_KALLSYMS");
64
65 kunit_warning_suppress(test) {
66 WARN_ON(1);
67 KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
68 }
69}
70
71static noinline void trigger_backtrace_warn_on(void)
72{
73 WARN_ON(1);
74}
75
76static void backtrace_suppression_test_warn_on_indirect(struct kunit *test)
77{
78 if (!IS_ENABLED(CONFIG_BUG))
79 kunit_skip(test, "requires CONFIG_BUG");
80 if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE))
81 kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE");
82
83 kunit_warning_suppress(test) {
84 trigger_backtrace_warn_on();
85 KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
86 }
87}
88
89static void backtrace_suppression_test_count(struct kunit *test)
90{
91 if (!IS_ENABLED(CONFIG_BUG))
92 kunit_skip(test, "requires CONFIG_BUG");
93
94 kunit_warning_suppress(test) {
95 KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 0);
96
97 WARN(1, "suppressed");
98 KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
99
100 WARN(1, "suppressed again");
101 KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
102 }
103}
104
105static void backtrace_suppression_test_active_state(struct kunit *test)
106{
107 KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
108
109 kunit_warning_suppress(test) {
110 KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
111 }
112
113 KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
114
115 kunit_warning_suppress(test) {
116 KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
117 }
118
119 KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
120}
121
122static void backtrace_suppression_test_multi_scope(struct kunit *test)
123{
124 struct kunit_suppressed_warning *sw1, *sw2;
125
126 if (!IS_ENABLED(CONFIG_BUG))
127 kunit_skip(test, "requires CONFIG_BUG");
128 if (!IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE))
129 kunit_skip(test, "requires CONFIG_DEBUG_BUGVERBOSE");
130
131 sw1 = kunit_start_suppress_warning(test);
132 trigger_backtrace_warn_on();
133 WARN(1, "suppressed by sw1");
134 kunit_end_suppress_warning(test, sw1);
135
136 sw2 = kunit_start_suppress_warning(test);
137 WARN(1, "suppressed by sw2");
138 kunit_end_suppress_warning(test, sw2);
139
140 KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw1), 2);
141 KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw2), 1);
142}
143
144struct cross_kthread_data {
145 bool was_active;
146 struct completion done;
147};
148
149static int cross_kthread_fn(void *data)
150{
151 struct cross_kthread_data *d = data;
152
153 d->was_active = kunit_has_active_suppress_warning();
154 complete(&d->done);
155 while (!kthread_should_stop())
156 schedule();
157 return 0;
158}
159
160static void backtrace_suppression_test_cross_kthread(struct kunit *test)
161{
162 struct cross_kthread_data data;
163 struct task_struct *task;
164
165 data.was_active = false;
166 init_completion(&data.done);
167
168 kunit_warning_suppress(test) {
169 task = kthread_run(cross_kthread_fn, &data, "kunit-cross-test");
170 KUNIT_ASSERT_FALSE(test, IS_ERR(task));
171 wait_for_completion(&data.done);
172 kthread_stop(task);
173 }
174
175 KUNIT_EXPECT_FALSE(test, data.was_active);
176}
177
178static struct kunit_case backtrace_suppression_test_cases[] = {
179 KUNIT_CASE(backtrace_suppression_test_warn_direct),
180 KUNIT_CASE(backtrace_suppression_test_warn_indirect),
181 KUNIT_CASE(backtrace_suppression_test_warn_multi),
182 KUNIT_CASE(backtrace_suppression_test_warn_on_direct),
183 KUNIT_CASE(backtrace_suppression_test_warn_on_indirect),
184 KUNIT_CASE(backtrace_suppression_test_count),
185 KUNIT_CASE(backtrace_suppression_test_active_state),
186 KUNIT_CASE(backtrace_suppression_test_multi_scope),
187 KUNIT_CASE(backtrace_suppression_test_cross_kthread),
188 {}
189};
190
191static struct kunit_suite backtrace_suppression_test_suite = {
192 .name = "backtrace-suppression-test",
193 .test_cases = backtrace_suppression_test_cases,
194};
195kunit_test_suites(&backtrace_suppression_test_suite);
196
197MODULE_LICENSE("GPL");
198MODULE_DESCRIPTION("KUnit test to verify warning backtrace suppression");