projects/linux·blob assoc-array-fixes · refs

120 lines · 2.9 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * KUnit helpers for backtrace suppression
4 *
5 * Copyright (C) 2025 Alessandro Carminati <[email protected]>
6 * Copyright (C) 2024 Guenter Roeck <[email protected]>
7 */
8
9#include <kunit/resource.h>
10#include <linux/export.h>
11#include <linux/rculist.h>
12#include <linux/sched.h>
13#include <linux/sched/task.h>
14#include <linux/spinlock.h>
15
16#include "hooks-impl.h"
17
18struct kunit_suppressed_warning {
19 struct list_head node;
20 struct task_struct *task;
21 struct kunit *test;
22 atomic_t counter;
23};
24
25static LIST_HEAD(suppressed_warnings);
26static DEFINE_SPINLOCK(suppressed_warnings_lock);
27
28static void kunit_suppress_warning_remove(struct kunit_suppressed_warning *w)
29{
30 unsigned long flags;
31
32 spin_lock_irqsave(&suppressed_warnings_lock, flags);
33 list_del_rcu(&w->node);
34 spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
35 put_task_struct(w->task);
36}
37
38KUNIT_DEFINE_ACTION_WRAPPER(kunit_suppress_warning_cleanup,
39 kunit_suppress_warning_remove,
40 struct kunit_suppressed_warning *);
41
42bool kunit_has_active_suppress_warning(void)
43{
44 return __kunit_is_suppressed_warning_impl(false);
45}
46EXPORT_SYMBOL_GPL(kunit_has_active_suppress_warning);
47
48struct kunit_suppressed_warning *
49kunit_start_suppress_warning(struct kunit *test)
50{
51 struct kunit_suppressed_warning *w;
52 unsigned long flags;
53 int ret;
54
55 if (kunit_has_active_suppress_warning()) {
56 KUNIT_FAIL(test, "Another suppression block is already active");
57 return NULL;
58 }
59
60 w = kunit_kzalloc(test, sizeof(*w), GFP_KERNEL);
61 if (!w) {
62 KUNIT_FAIL(test, "Failed to allocate suppression handle.");
63 return NULL;
64 }
65
66 w->task = get_task_struct(current);
67 w->test = test;
68
69 spin_lock_irqsave(&suppressed_warnings_lock, flags);
70 list_add_rcu(&w->node, &suppressed_warnings);
71 spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
72
73 ret = kunit_add_action_or_reset(test,
74 kunit_suppress_warning_cleanup, w);
75 if (ret) {
76 KUNIT_FAIL(test, "Failed to add suppression cleanup action.");
77 return NULL;
78 }
79
80 return w;
81}
82EXPORT_SYMBOL_GPL(kunit_start_suppress_warning);
83
84void kunit_end_suppress_warning(struct kunit *test,
85 struct kunit_suppressed_warning *w)
86{
87 if (!w)
88 return;
89 kunit_release_action(test, kunit_suppress_warning_cleanup, w);
90}
91EXPORT_SYMBOL_GPL(kunit_end_suppress_warning);
92
93void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp)
94{
95 if (*wp)
96 kunit_end_suppress_warning((*wp)->test, *wp);
97}
98EXPORT_SYMBOL_GPL(__kunit_suppress_auto_cleanup);
99
100int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w)
101{
102 return w ? atomic_read(&w->counter) : 0;
103}
104EXPORT_SYMBOL_GPL(kunit_suppressed_warning_count);
105
106bool __kunit_is_suppressed_warning_impl(bool count)
107{
108 struct kunit_suppressed_warning *w;
109
110 guard(rcu)();
111 list_for_each_entry_rcu(w, &suppressed_warnings, node) {
112 if (w->task == current) {
113 if (count)
114 atomic_inc(&w->counter);
115 return true;
116 }
117 }
118
119 return false;
120}