Skip to content

Commit 42eb3a5

Browse files
committed
Merge tag 'linux_kselftest-kunit-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull kunit updates from Shuah Khan: "Fixes to tool and kunit core and new features to both to support JUnit XML (primitive) and backtrace suppression API: - Core support for suppressing warning backtraces - Parse and print the reason tests are skipped - Add (primitive) support for outputting JUnit XML - Don't write to stdout when it should be disabled - Add backtrace suppression self-tests - Suppress intentional warning backtraces in scaling unit tests - Add documentation for warning backtrace suppression API - Fix spelling mistakes in comments and messages - gen_compile_commands: Ignore libgcc.a - qemu_configs: Add or1k / openrisc configuration" * tag 'linux_kselftest-kunit-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: kunit:tool: Don't write to stdout when it should be disabled kunit: tool: Add (primitive) support for outputting JUnit XML kunit: tool: Parse and print the reason tests are skipped kunit: Add documentation for warning backtrace suppression API drm: Suppress intentional warning backtraces in scaling unit tests kunit: Add backtrace suppression self-tests bug/kunit: Core support for suppressing warning backtraces kunit: Fix spelling mistakes in comments and messages kunit: qemu_configs: Add or1k / openrisc configuration gen_compile_commands: Ignore libgcc.a
2 parents b1cbabe + 29afed1 commit 42eb3a5

18 files changed

Lines changed: 730 additions & 27 deletions

File tree

Documentation/dev-tools/kunit/run_wrapper.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ command line arguments:
324324
- ``--json``: If set, stores the test results in a JSON format and prints to `stdout` or
325325
saves to a file if a filename is specified.
326326

327+
- ``--junit``: If set, stores the test results in JUnit XML format and prints to `stdout` or
328+
saves to a file if a filename is specified.
329+
327330
- ``--filter``: Specifies filters on test attributes, for example, ``speed!=slow``.
328331
Multiple filters can be used by wrapping input in quotes and separating filters
329332
by commas. Example: ``--filter "speed>slow, module=example"``.

Documentation/dev-tools/kunit/usage.rst

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,50 @@ Alternatively, one can take full control over the error message by using
157157
if (some_setup_function())
158158
KUNIT_FAIL(test, "Failed to setup thing for testing");
159159
160+
Suppressing warning backtraces
161+
------------------------------
162+
163+
Some unit tests trigger warning backtraces either intentionally or as a side
164+
effect. Such backtraces are normally undesirable since they distract from
165+
the actual test and may result in the impression that there is a problem.
166+
167+
Backtraces can be suppressed with **task-scoped suppression**: while
168+
suppression is active on the current task, the backtrace and stack dump from
169+
``WARN*()``, ``WARN_ON*()``, and related macros on that task are suppressed.
170+
Two API forms are available.
171+
172+
- Scoped suppression is the simplest form. Wrap the code that triggers
173+
warnings in a ``kunit_warning_suppress()`` block:
174+
175+
.. code-block:: c
176+
177+
static void some_test(struct kunit *test)
178+
{
179+
kunit_warning_suppress(test) {
180+
trigger_backtrace();
181+
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
182+
}
183+
}
184+
185+
.. note::
186+
The warning count must be checked inside the block; the suppression handle
187+
is not accessible after the block exits.
188+
189+
- Direct functions return an explicit handle pointer. Use them when the handle
190+
needs to be retained or passed across helper functions:
191+
192+
.. code-block:: c
193+
194+
static void some_test(struct kunit *test)
195+
{
196+
struct kunit_suppressed_warning *w;
197+
198+
w = kunit_start_suppress_warning(test);
199+
trigger_backtrace();
200+
kunit_end_suppress_warning(test, w);
201+
202+
KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(w), 1);
203+
}
160204
161205
Test Suites
162206
~~~~~~~~~~~
@@ -1211,4 +1255,4 @@ For example:
12111255
dev_managed_string = devm_kstrdup(fake_device, "Hello, World!");
12121256
12131257
// Everything is cleaned up automatically when the test ends.
1214-
}
1258+
}

drivers/gpu/drm/tests/drm_rect_test.c

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <drm/drm_rect.h>
1111
#include <drm/drm_mode.h>
1212

13+
#include <linux/limits.h>
1314
#include <linux/string_helpers.h>
1415
#include <linux/errno.h>
1516

@@ -407,21 +408,54 @@ KUNIT_ARRAY_PARAM(drm_rect_scale, drm_rect_scale_cases, drm_rect_scale_case_desc
407408
static void drm_test_rect_calc_hscale(struct kunit *test)
408409
{
409410
const struct drm_rect_scale_case *params = test->param_value;
410-
int scaling_factor;
411+
int expected_warnings = params->expected_scaling_factor == -EINVAL;
412+
int scaling_factor = INT_MIN;
411413

412-
scaling_factor = drm_rect_calc_hscale(&params->src, &params->dst,
413-
params->min_range, params->max_range);
414+
/*
415+
* Without CONFIG_BUG, WARN_ON() is a no-op and the suppressed warning
416+
* count stays zero, failing the assertion.
417+
*/
418+
if (expected_warnings && !IS_ENABLED(CONFIG_BUG))
419+
kunit_skip(test, "requires CONFIG_BUG");
420+
421+
/*
422+
* drm_rect_calc_hscale() generates a warning backtrace whenever bad
423+
* parameters are passed to it. This affects unit tests with -EINVAL
424+
* error code in expected_scaling_factor.
425+
*/
426+
kunit_warning_suppress(test) {
427+
scaling_factor = drm_rect_calc_hscale(&params->src, &params->dst,
428+
params->min_range,
429+
params->max_range);
430+
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected_warnings);
431+
}
414432

415433
KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
416434
}
417435

418436
static void drm_test_rect_calc_vscale(struct kunit *test)
419437
{
420438
const struct drm_rect_scale_case *params = test->param_value;
421-
int scaling_factor;
439+
int expected_warnings = params->expected_scaling_factor == -EINVAL;
440+
int scaling_factor = INT_MIN;
422441

423-
scaling_factor = drm_rect_calc_vscale(&params->src, &params->dst,
424-
params->min_range, params->max_range);
442+
/*
443+
* Without CONFIG_BUG, WARN_ON() is a no-op and the suppressed warning
444+
* count stays zero, failing the assertion.
445+
*/
446+
if (expected_warnings && !IS_ENABLED(CONFIG_BUG))
447+
kunit_skip(test, "requires CONFIG_BUG");
448+
449+
/*
450+
* drm_rect_calc_vscale() generates a warning backtrace whenever bad
451+
* parameters are passed to it. This affects unit tests with -EINVAL
452+
* error code in expected_scaling_factor.
453+
*/
454+
kunit_warning_suppress(test) {
455+
scaling_factor = drm_rect_calc_vscale(&params->src, &params->dst,
456+
params->min_range, params->max_range);
457+
KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected_warnings);
458+
}
425459

426460
KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
427461
}

include/kunit/test-bug.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define _KUNIT_TEST_BUG_H
1111

1212
#include <linux/stddef.h> /* for NULL */
13+
#include <linux/types.h> /* for bool */
1314

1415
#if IS_ENABLED(CONFIG_KUNIT)
1516

@@ -23,6 +24,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running);
2324
extern struct kunit_hooks_table {
2425
__printf(3, 4) void (*fail_current_test)(const char*, int, const char*, ...);
2526
void *(*get_static_stub_address)(struct kunit *test, void *real_fn_addr);
27+
bool (*is_suppressed_warning)(bool count);
2628
} kunit_hooks;
2729

2830
/**
@@ -60,9 +62,33 @@ static inline struct kunit *kunit_get_current_test(void)
6062
} \
6163
} while (0)
6264

65+
/**
66+
* kunit_is_suppressed_warning() - Check if warnings are being suppressed
67+
* by the current KUnit test.
68+
* @count: if true, increment the suppression counter on match.
69+
*
70+
* Returns true if the current task has active warning suppression.
71+
* Uses the kunit_running static branch for zero overhead when no tests run.
72+
*
73+
* A single WARN*() may traverse multiple call sites in the warning path
74+
* (e.g., __warn_printk() and __report_bug()). Pass @count = true at the
75+
* primary suppression point to count each warning exactly once, and
76+
* @count = false at secondary points to suppress output without
77+
* inflating the count.
78+
*/
79+
static inline bool kunit_is_suppressed_warning(bool count)
80+
{
81+
if (!static_branch_unlikely(&kunit_running))
82+
return false;
83+
84+
return kunit_hooks.is_suppressed_warning &&
85+
kunit_hooks.is_suppressed_warning(count);
86+
}
87+
6388
#else
6489

6590
static inline struct kunit *kunit_get_current_test(void) { return NULL; }
91+
static inline bool kunit_is_suppressed_warning(bool count) { return false; }
6692

6793
#define kunit_fail_current_test(fmt, ...) do {} while (0)
6894

include/kunit/test.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,4 +1796,102 @@ do { \
17961796
// include resource.h themselves if they need it.
17971797
#include <kunit/resource.h>
17981798

1799+
/*
1800+
* Warning backtrace suppression API.
1801+
*
1802+
* Suppresses WARN*() backtraces on the current task while active. Two forms
1803+
* are provided:
1804+
*
1805+
* - Scoped: kunit_warning_suppress(test) { ... }
1806+
* Suppression is active for the duration of the block. On normal exit,
1807+
* the for-loop increment deactivates suppression. On early exit (break,
1808+
* return, goto), the __cleanup attribute fires. On kthread_exit() (e.g.,
1809+
* a failed KUnit assertion), kunit_add_action() cleans up at test
1810+
* teardown. The suppression handle is only accessible inside the block,
1811+
* so warning counts must be checked before the block exits.
1812+
*
1813+
* - Direct: kunit_start_suppress_warning() / kunit_end_suppress_warning()
1814+
* The underlying functions, returning an explicit handle pointer. Use
1815+
* when the handle needs to be retained (e.g., for post-suppression
1816+
* count checks) or passed across helper functions.
1817+
*/
1818+
struct kunit_suppressed_warning;
1819+
1820+
struct kunit_suppressed_warning *
1821+
kunit_start_suppress_warning(struct kunit *test);
1822+
void kunit_end_suppress_warning(struct kunit *test,
1823+
struct kunit_suppressed_warning *w);
1824+
int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w);
1825+
void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp);
1826+
bool kunit_has_active_suppress_warning(void);
1827+
1828+
/**
1829+
* kunit_warning_suppress() - Suppress WARN*() backtraces for the duration
1830+
* of a block.
1831+
* @test: The test context object.
1832+
*
1833+
* Scoped form of the suppression API. Suppression starts when the block is
1834+
* entered and ends automatically when the block exits through any path. See
1835+
* the section comment above for the cleanup guarantees on each exit path.
1836+
* Fails the test if suppression is already active; nesting is not supported.
1837+
*
1838+
* The warning count can be checked inside the block via
1839+
* KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(). The handle is not accessible
1840+
* after the block exits.
1841+
*
1842+
* Example::
1843+
*
1844+
* kunit_warning_suppress(test) {
1845+
* trigger_warning();
1846+
* KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
1847+
* }
1848+
*/
1849+
#define kunit_warning_suppress(test) \
1850+
for (struct kunit_suppressed_warning *__kunit_suppress \
1851+
__cleanup(__kunit_suppress_auto_cleanup) = \
1852+
kunit_start_suppress_warning(test); \
1853+
__kunit_suppress; \
1854+
kunit_end_suppress_warning(test, __kunit_suppress), \
1855+
__kunit_suppress = NULL)
1856+
1857+
/**
1858+
* KUNIT_SUPPRESSED_WARNING_COUNT() - Returns the suppressed warning count.
1859+
*
1860+
* Returns the number of WARN*() calls suppressed since the current
1861+
* suppression block started, or 0 if the handle is NULL. Usable inside a
1862+
* kunit_warning_suppress() block.
1863+
*/
1864+
#define KUNIT_SUPPRESSED_WARNING_COUNT() \
1865+
kunit_suppressed_warning_count(__kunit_suppress)
1866+
1867+
/**
1868+
* KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT() - Sets an expectation that the
1869+
* suppressed warning count equals
1870+
* @expected.
1871+
* @test: The test context object.
1872+
* @expected: an expression that evaluates to the expected warning count.
1873+
*
1874+
* Sets an expectation that the number of suppressed WARN*() calls equals
1875+
* @expected. This is semantically equivalent to
1876+
* KUNIT_EXPECT_EQ(@test, KUNIT_SUPPRESSED_WARNING_COUNT(), @expected).
1877+
* See KUNIT_EXPECT_EQ() for more information.
1878+
*/
1879+
#define KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected) \
1880+
KUNIT_EXPECT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
1881+
1882+
/**
1883+
* KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT() - Sets an assertion that the
1884+
* suppressed warning count equals
1885+
* @expected.
1886+
* @test: The test context object.
1887+
* @expected: an expression that evaluates to the expected warning count.
1888+
*
1889+
* Sets an assertion that the number of suppressed WARN*() calls equals
1890+
* @expected. This is the same as KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(),
1891+
* except it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the
1892+
* assertion is not met.
1893+
*/
1894+
#define KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT(test, expected) \
1895+
KUNIT_ASSERT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
1896+
17991897
#endif /* _KUNIT_TEST_H */

kernel/panic.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <linux/sys_info.h>
4040
#include <trace/events/error_report.h>
4141
#include <asm/sections.h>
42+
#include <kunit/test-bug.h>
4243

4344
#define PANIC_TIMER_STEP 100
4445
#define PANIC_BLINK_SPD 18
@@ -1124,6 +1125,11 @@ void warn_slowpath_fmt(const char *file, int line, unsigned taint,
11241125
bool rcu = warn_rcu_enter();
11251126
struct warn_args args;
11261127

1128+
if (kunit_is_suppressed_warning(true)) {
1129+
warn_rcu_exit(rcu);
1130+
return;
1131+
}
1132+
11271133
pr_warn(CUT_HERE);
11281134

11291135
if (!fmt) {
@@ -1146,6 +1152,11 @@ void __warn_printk(const char *fmt, ...)
11461152
bool rcu = warn_rcu_enter();
11471153
va_list args;
11481154

1155+
if (kunit_is_suppressed_warning(false)) {
1156+
warn_rcu_exit(rcu);
1157+
return;
1158+
}
1159+
11491160
pr_warn(CUT_HERE);
11501161

11511162
va_start(args, fmt);

lib/bug.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <linux/rculist.h>
4949
#include <linux/ftrace.h>
5050
#include <linux/context_tracking.h>
51+
#include <kunit/test-bug.h>
5152

5253
extern struct bug_entry __start___bug_table[], __stop___bug_table[];
5354

@@ -209,8 +210,6 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
209210
return BUG_TRAP_TYPE_NONE;
210211
}
211212

212-
disable_trace_on_warning();
213-
214213
bug_get_file_line(bug, &file, &line);
215214
fmt = bug_get_format(bug);
216215

@@ -220,6 +219,17 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
220219
no_cut = bug->flags & BUGFLAG_NO_CUT_HERE;
221220
has_args = bug->flags & BUGFLAG_ARGS;
222221

222+
#ifdef CONFIG_KUNIT
223+
/*
224+
* Before the once logic so suppressed warnings do not consume
225+
* the single-fire budget of WARN_ON_ONCE().
226+
*/
227+
if (warning && kunit_is_suppressed_warning(true))
228+
return BUG_TRAP_TYPE_WARN;
229+
#endif
230+
231+
disable_trace_on_warning();
232+
223233
if (warning && once) {
224234
if (done)
225235
return BUG_TRAP_TYPE_WARN;

lib/kunit/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ kunit-objs += test.o \
1010
executor.o \
1111
attributes.o \
1212
device.o \
13-
platform.o
13+
platform.o \
14+
bug.o
1415

1516
ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
1617
kunit-objs += debugfs.o
@@ -21,6 +22,7 @@ obj-$(if $(CONFIG_KUNIT),y) += hooks.o
2122

2223
obj-$(CONFIG_KUNIT_TEST) += kunit-test.o
2324
obj-$(CONFIG_KUNIT_TEST) += platform-test.o
25+
obj-$(CONFIG_KUNIT_TEST) += backtrace-suppression-test.o
2426

2527
# string-stream-test compiles built-in only.
2628
ifeq ($(CONFIG_KUNIT_TEST),y)

0 commit comments

Comments
 (0)