120 lines · 2.9 KB · C
RawDownload
// 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;}