xref: /linux/lib/kunit/backtrace-suppression-test.c (revision 5b33fc6492a7b7a62359157db0f92f5b6e9af690)
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 <linux@roeck-us.net>
7  */
8 
9 #include <kunit/test.h>
10 #include <linux/bug.h>
11 #include <linux/completion.h>
12 #include <linux/kthread.h>
13 
14 static 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 
30 static noinline void trigger_backtrace_warn(void)
31 {
32 	WARN(1, "This backtrace should be suppressed");
33 }
34 
35 static 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 
46 static 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 
58 static 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 
71 static noinline void trigger_backtrace_warn_on(void)
72 {
73 	WARN_ON(1);
74 }
75 
76 static 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 
89 static 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 
105 static 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 
122 static 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 
144 struct cross_kthread_data {
145 	bool was_active;
146 	struct completion done;
147 };
148 
149 static 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 
160 static 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 
178 static 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 
191 static struct kunit_suite backtrace_suppression_test_suite = {
192 	.name = "backtrace-suppression-test",
193 	.test_cases = backtrace_suppression_test_cases,
194 };
195 kunit_test_suites(&backtrace_suppression_test_suite);
196 
197 MODULE_LICENSE("GPL");
198 MODULE_DESCRIPTION("KUnit test to verify warning backtrace suppression");
199