diff options
Diffstat (limited to 'lib/kunit')
| -rw-r--r-- | lib/kunit/Makefile | 3 | ||||
| -rw-r--r-- | lib/kunit/bug.c | 120 | ||||
| -rw-r--r-- | lib/kunit/hooks-impl.h | 2 |
3 files changed, 124 insertions, 1 deletions
diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile index 656f1fa35abc..4592f9d0aa8d 100644 --- a/lib/kunit/Makefile +++ b/lib/kunit/Makefile @@ -10,7 +10,8 @@ kunit-objs += test.o \ executor.o \ attributes.o \ device.o \ - platform.o + platform.o \ + bug.o ifeq ($(CONFIG_KUNIT_DEBUGFS),y) kunit-objs += debugfs.o diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c new file mode 100644 index 000000000000..8579235c9ca6 --- /dev/null +++ b/lib/kunit/bug.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit helpers for backtrace suppression + * + * Copyright (C) 2025 Alessandro Carminati <acarmina@redhat.com> + * Copyright (C) 2024 Guenter Roeck <linux@roeck-us.net> + */ + +#include <kunit/resource.h> +#include <linux/export.h> +#include <linux/rculist.h> +#include <linux/sched.h> +#include <linux/sched/task.h> +#include <linux/spinlock.h> + +#include "hooks-impl.h" + +struct kunit_suppressed_warning { + struct list_head node; + struct task_struct *task; + struct kunit *test; + atomic_t counter; +}; + +static LIST_HEAD(suppressed_warnings); +static DEFINE_SPINLOCK(suppressed_warnings_lock); + +static void kunit_suppress_warning_remove(struct kunit_suppressed_warning *w) +{ + unsigned long flags; + + spin_lock_irqsave(&suppressed_warnings_lock, flags); + list_del_rcu(&w->node); + spin_unlock_irqrestore(&suppressed_warnings_lock, flags); + put_task_struct(w->task); +} + +KUNIT_DEFINE_ACTION_WRAPPER(kunit_suppress_warning_cleanup, + kunit_suppress_warning_remove, + struct kunit_suppressed_warning *); + +bool kunit_has_active_suppress_warning(void) +{ + return __kunit_is_suppressed_warning_impl(false); +} +EXPORT_SYMBOL_GPL(kunit_has_active_suppress_warning); + +struct kunit_suppressed_warning * +kunit_start_suppress_warning(struct kunit *test) +{ + struct kunit_suppressed_warning *w; + unsigned long flags; + int ret; + + if (kunit_has_active_suppress_warning()) { + KUNIT_FAIL(test, "Another suppression block is already active"); + return NULL; + } + + w = kunit_kzalloc(test, sizeof(*w), GFP_KERNEL); + if (!w) { + KUNIT_FAIL(test, "Failed to allocate suppression handle."); + return NULL; + } + + w->task = get_task_struct(current); + w->test = test; + + spin_lock_irqsave(&suppressed_warnings_lock, flags); + list_add_rcu(&w->node, &suppressed_warnings); + spin_unlock_irqrestore(&suppressed_warnings_lock, flags); + + ret = kunit_add_action_or_reset(test, + kunit_suppress_warning_cleanup, w); + if (ret) { + KUNIT_FAIL(test, "Failed to add suppression cleanup action."); + return NULL; + } + + return w; +} +EXPORT_SYMBOL_GPL(kunit_start_suppress_warning); + +void kunit_end_suppress_warning(struct kunit *test, + struct kunit_suppressed_warning *w) +{ + if (!w) + return; + kunit_release_action(test, kunit_suppress_warning_cleanup, w); +} +EXPORT_SYMBOL_GPL(kunit_end_suppress_warning); + +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp) +{ + if (*wp) + kunit_end_suppress_warning((*wp)->test, *wp); +} +EXPORT_SYMBOL_GPL(__kunit_suppress_auto_cleanup); + +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w) +{ + return w ? atomic_read(&w->counter) : 0; +} +EXPORT_SYMBOL_GPL(kunit_suppressed_warning_count); + +bool __kunit_is_suppressed_warning_impl(bool count) +{ + struct kunit_suppressed_warning *w; + + guard(rcu)(); + list_for_each_entry_rcu(w, &suppressed_warnings, node) { + if (w->task == current) { + if (count) + atomic_inc(&w->counter); + return true; + } + } + + return false; +} diff --git a/lib/kunit/hooks-impl.h b/lib/kunit/hooks-impl.h index 4e71b2d0143b..d8720f261692 100644 --- a/lib/kunit/hooks-impl.h +++ b/lib/kunit/hooks-impl.h @@ -19,6 +19,7 @@ void __printf(3, 4) __kunit_fail_current_test_impl(const char *file, int line, const char *fmt, ...); void *__kunit_get_static_stub_address_impl(struct kunit *test, void *real_fn_addr); +bool __kunit_is_suppressed_warning_impl(bool count); /* Code to set all of the function pointers. */ static inline void kunit_install_hooks(void) @@ -26,6 +27,7 @@ static inline void kunit_install_hooks(void) /* Install the KUnit hook functions. */ kunit_hooks.fail_current_test = __kunit_fail_current_test_impl; kunit_hooks.get_static_stub_address = __kunit_get_static_stub_address_impl; + kunit_hooks.is_suppressed_warning = __kunit_is_suppressed_warning_impl; } #endif /* _KUNIT_HOOKS_IMPL_H */ |
