From nobody Tue Apr 7 01:22:32 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E097A39F164 for ; Tue, 17 Mar 2026 09:25:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773739514; cv=none; b=s7X42Zvwg7PbkXzDFO0JOZhSjL2Fau/082FjO5HIg/Fgvn0mle4SVuPsr1uRPhyhOX+QbzK70r431qw2b3I7N1ZrVe8X3A+GN3cq981aNSYToTdZkuGc/2hdW0TgvOFwaDo4ptVdm+luC87agBkl/7d12vZdtPGO9NwKEzLiqnY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773739514; c=relaxed/simple; bh=CmX/LqdIOJS1Ct1RBcik9DLTDYba7/p3qMd9LakEEKk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HwaMqFlRyEDln2sQSbVK0QxBEissMXWcZ10F+aDbjMTqp6ffQ/ceGZQWs9NLgBXEoKUeNHI8/SgG63TvUsR5AnVmovDz1exDTIZLykNdY1CvEd4iPGAASrPTkPaElwfXowBRe10iLIdI6hkmnhZRe495Xn7rjiMcxb5dlhninlc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=IXAPmh3H; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="IXAPmh3H" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1773739512; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vl38m1bfQraLOcvKSMlDF9R7LfHO8MoiUxQ5e03K4cE=; b=IXAPmh3HI89EnKL0HO5TwqSBXFEv2aflAn9HJMKoLBiNM9vAHV6y3+gfWy2J6viyzjpqp1 0WnmiMcVwQN8BGM52n4L+meW4cil10hI2VwsEIJxiVRPoj7l9rySQrReGx/4l9fxp5W7Pb zUoQh0BAax/DFxvKLOPFtqpU1l9yqOE= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-575-UMz29TRVM6qwxuPwb0y7-A-1; Tue, 17 Mar 2026 05:25:07 -0400 X-MC-Unique: UMz29TRVM6qwxuPwb0y7-A-1 X-Mimecast-MFC-AGG-ID: UMz29TRVM6qwxuPwb0y7-A_1773739504 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id ED05018002DD; Tue, 17 Mar 2026 09:25:03 +0000 (UTC) Received: from [192.168.1.153] (unknown [10.45.224.69]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 95F621800576; Tue, 17 Mar 2026 09:24:56 +0000 (UTC) From: Albert Esteve Date: Tue, 17 Mar 2026 10:24:41 +0100 Subject: [PATCH v6 1/5] bug/kunit: Core support for suppressing warning backtraces Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260317-kunit_add_support-v6-1-dd22aeb3fe5d@redhat.com> References: <20260317-kunit_add_support-v6-0-dd22aeb3fe5d@redhat.com> In-Reply-To: <20260317-kunit_add_support-v6-0-dd22aeb3fe5d@redhat.com> To: Arnd Bergmann , Brendan Higgins , David Gow , Rae Moar , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Jonathan Corbet , Shuah Khan Cc: linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, dri-devel@lists.freedesktop.org, workflows@vger.kernel.org, linux-doc@vger.kernel.org, Alessandro Carminati , Guenter Roeck , Kees Cook , Albert Esteve X-Developer-Signature: v=1; a=ed25519-sha256; t=1773739485; l=10954; i=aesteve@redhat.com; s=20260303; h=from:subject:message-id; bh=9HDzKd2Q+voitfuDwnjvb0TVH3+Mu4gPG+q0/QE7BAQ=; b=upqDoz1QY8TvBDSLFwGn2/f4tjZfHSWNQJI8mG6XunJuXaMDpwmkOShrxyt1Qx8LKUAREE/xV 7+94VvRYSS4D3cBQZaa+Poe5o1PhH9yy2A2PN4ZRqFwMDRK0vc6j6Vs X-Developer-Key: i=aesteve@redhat.com; a=ed25519; pk=YSFz6sOHd2L45+Fr8DIvHTi6lSIjhLZ5T+rkxspJt1s= X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 From: Alessandro Carminati Some unit tests intentionally trigger warning backtraces by passing bad parameters to kernel API functions. Such unit tests typically check the return value from such calls, not the existence of the warning backtrace. Such intentionally generated warning backtraces are neither desirable nor useful for a number of reasons: - They can result in overlooked real problems. - A warning that suddenly starts to show up in unit tests needs to be investigated and has to be marked to be ignored, for example by adjusting filter scripts. Such filters are ad hoc because there is no real standard format for warnings. On top of that, such filter scripts would require constant maintenance. Solve the problem by providing a means to identify and suppress specific warning backtraces while executing test code. Support suppressing multiple backtraces while at the same time limiting changes to generic code to the absolute minimum. Implementation details: Check suppression directly in the `WARN()` Macros. This avoids the need for function symbol resolution or ELF section modification. Use unlikely() with KUNIT_IS_SUPPRESSED_WARNING() in the Macros so the common case (no suppression) stays on the hot path, improving performance and keeping the critical path smaller. A helper function, `__kunit_is_suppressed_warning()`, is used to determine whether suppression applies. It is marked as `noinstr`, since some `WARN*()` sites reside in non-instrumentable sections. As it uses `strcmp`, which is not `noinstr`-safe, its use is wrapped within `__kunit_check_suppress()` and surounded by instrumentation_begin()/end() calls. The list of supressed warnings includes RCU protection. The implementation is deliberately simple and avoids architecture-specific optimizations to preserve portability. Signed-off-by: Guenter Roeck Signed-off-by: Alessandro Carminati Reviewed-by: Kees Cook Signed-off-by: Albert Esteve --- include/asm-generic/bug.h | 44 ++++++++++++++++++++++------------ include/kunit/bug.h | 61 +++++++++++++++++++++++++++++++++++++++++++= ++++ include/kunit/test.h | 1 + lib/kunit/Kconfig | 9 +++++++ lib/kunit/Makefile | 6 +++-- lib/kunit/bug.c | 59 +++++++++++++++++++++++++++++++++++++++++++= ++ 6 files changed, 163 insertions(+), 17 deletions(-) diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h index 09e8eccee8ed9..7c766fde49a90 100644 --- a/include/asm-generic/bug.h +++ b/include/asm-generic/bug.h @@ -27,6 +27,7 @@ #endif /* WARN_CONDITION_STR */ =20 #ifndef __ASSEMBLY__ +#include #include #include =20 @@ -71,9 +72,13 @@ struct bug_entry { */ #ifndef HAVE_ARCH_BUG #define BUG() do { \ - printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ - barrier_before_unreachable(); \ - panic("BUG!"); \ + if (!unlikely(KUNIT_IS_SUPPRESSED_WARNING(__func__))) { \ + printk("BUG: failure at %s:%d/%s()!\n", __FILE__, \ + __LINE__, __func__); \ + barrier_before_unreachable(); \ + panic("BUG!"); \ + } \ + __builtin_unreachable(); \ } while (0) #endif =20 @@ -129,18 +134,23 @@ extern __printf(1, 2) void __warn_printk(const char *= fmt, ...); =20 #if defined(__WARN_FLAGS) && !defined(__WARN_printf) #define __WARN_printf(taint, arg...) do { \ - instrumentation_begin(); \ - __warn_printk(arg); \ - __WARN_FLAGS("", BUGFLAG_NO_CUT_HERE | BUGFLAG_TAINT(taint));\ - instrumentation_end(); \ + if (!unlikely(KUNIT_IS_SUPPRESSED_WARNING(__func__))) { \ + instrumentation_begin(); \ + __warn_printk(arg); \ + __WARN_FLAGS("", BUGFLAG_NO_CUT_HERE | \ + BUGFLAG_TAINT(taint)); \ + instrumentation_end(); \ + } \ } while (0) #endif =20 #ifndef __WARN_printf -#define __WARN_printf(taint, arg...) do { \ - instrumentation_begin(); \ - warn_slowpath_fmt(__FILE__, __LINE__, taint, arg); \ - instrumentation_end(); \ +#define __WARN_printf(taint, arg...) do { \ + if (!unlikely(KUNIT_IS_SUPPRESSED_WARNING(__func__))) { \ + instrumentation_begin(); \ + warn_slowpath_fmt(__FILE__, __LINE__, taint, arg); \ + instrumentation_end(); \ + } \ } while (0) #endif =20 @@ -153,7 +163,8 @@ extern __printf(1, 2) void __warn_printk(const char *fm= t, ...); #ifndef WARN_ON #define WARN_ON(condition) ({ \ int __ret_warn_on =3D !!(condition); \ - if (unlikely(__ret_warn_on)) \ + if (unlikely(__ret_warn_on) && \ + !unlikely(KUNIT_IS_SUPPRESSED_WARNING(__func__))) \ __WARN(); \ unlikely(__ret_warn_on); \ }) @@ -170,7 +181,8 @@ extern __printf(1, 2) void __warn_printk(const char *fm= t, ...); =20 #define WARN_TAINT(condition, taint, format...) ({ \ int __ret_warn_on =3D !!(condition); \ - if (unlikely(__ret_warn_on)) \ + if (unlikely(__ret_warn_on) && \ + !unlikely(KUNIT_IS_SUPPRESSED_WARNING(__func__))) \ __WARN_printf(taint, format); \ unlikely(__ret_warn_on); \ }) @@ -191,8 +203,10 @@ extern __printf(1, 2) void __warn_printk(const char *f= mt, ...); #else /* !CONFIG_BUG */ #ifndef HAVE_ARCH_BUG #define BUG() do { \ - do {} while (1); \ - unreachable(); \ + if (!unlikely(KUNIT_IS_SUPPRESSED_WARNING(__func__))) { \ + do {} while (1); \ + } \ + unreachable(); \ } while (0) #endif =20 diff --git a/include/kunit/bug.h b/include/kunit/bug.h new file mode 100644 index 0000000000000..9a5cd226c2139 --- /dev/null +++ b/include/kunit/bug.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * KUnit helpers for backtrace suppression + * + * Copyright (C) 2025 Alessandro Carminati + * Copyright (C) 2024 Guenter Roeck + */ + +#ifndef _KUNIT_BUG_H +#define _KUNIT_BUG_H + +#ifndef __ASSEMBLY__ + +#include + +#ifdef CONFIG_KUNIT_SUPPRESS_BACKTRACE + +#include +#include + +struct __suppressed_warning { + struct list_head node; + const char *function; + int counter; +}; + +void __kunit_start_suppress_warning(struct __suppressed_warning *warning); +void __kunit_end_suppress_warning(struct __suppressed_warning *warning); +bool __kunit_is_suppressed_warning(const char *function); + +#define KUNIT_DEFINE_SUPPRESSED_WARNING(func) \ + struct __suppressed_warning __kunit_suppress_##func =3D \ + { .function =3D __stringify(func), .counter =3D 0 } + +#define KUNIT_START_SUPPRESSED_WARNING(func) \ + __kunit_start_suppress_warning(&__kunit_suppress_##func) + +#define KUNIT_END_SUPPRESSED_WARNING(func) \ + __kunit_end_suppress_warning(&__kunit_suppress_##func) + +#define KUNIT_IS_SUPPRESSED_WARNING(func) \ + __kunit_is_suppressed_warning(func) + +#define KUNIT_SUPPRESSED_WARNING_COUNT(func) \ + (__kunit_suppress_##func.counter) + +#define KUNIT_SUPPRESSED_WARNING_COUNT_RESET(func) \ + __kunit_suppress_##func.counter =3D 0 + +#else /* CONFIG_KUNIT_SUPPRESS_BACKTRACE */ + +#define KUNIT_DEFINE_SUPPRESSED_WARNING(func) +#define KUNIT_START_SUPPRESSED_WARNING(func) +#define KUNIT_END_SUPPRESSED_WARNING(func) +#define KUNIT_IS_SUPPRESSED_WARNING(func) ((void)(func), false) +#define KUNIT_SUPPRESSED_WARNING_COUNT(func) ((void)(func), 0) +#define KUNIT_SUPPRESSED_WARNING_COUNT_RESET(func) + +#endif /* CONFIG_KUNIT_SUPPRESS_BACKTRACE */ +#endif /* __ASSEMBLY__ */ +#endif /* _KUNIT_BUG_H */ diff --git a/include/kunit/test.h b/include/kunit/test.h index 9cd1594ab697d..4ec07b3fa0204 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -10,6 +10,7 @@ #define _KUNIT_TEST_H =20 #include +#include #include =20 #include diff --git a/lib/kunit/Kconfig b/lib/kunit/Kconfig index 498cc51e493dc..57527418fcf09 100644 --- a/lib/kunit/Kconfig +++ b/lib/kunit/Kconfig @@ -15,6 +15,15 @@ menuconfig KUNIT =20 if KUNIT =20 +config KUNIT_SUPPRESS_BACKTRACE + bool "KUnit - Enable backtrace suppression" + default y + help + Enable backtrace suppression for KUnit. If enabled, backtraces + generated intentionally by KUnit tests are suppressed. Disable + to reduce kernel image size if image size is more important than + suppression of backtraces generated by KUnit tests. + config KUNIT_DEBUGFS bool "KUnit - Enable /sys/kernel/debug/kunit debugfs representation" if != KUNIT_ALL_TESTS default KUNIT_ALL_TESTS diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile index 656f1fa35abcc..fe177ff3ebdef 100644 --- a/lib/kunit/Makefile +++ b/lib/kunit/Makefile @@ -16,8 +16,10 @@ ifeq ($(CONFIG_KUNIT_DEBUGFS),y) kunit-objs +=3D debugfs.o endif =20 -# KUnit 'hooks' are built-in even when KUnit is built as a module. -obj-$(if $(CONFIG_KUNIT),y) +=3D hooks.o +# KUnit 'hooks' and bug handling are built-in even when KUnit is built +# as a module. +obj-$(if $(CONFIG_KUNIT),y) +=3D hooks.o \ + bug.o =20 obj-$(CONFIG_KUNIT_TEST) +=3D kunit-test.o obj-$(CONFIG_KUNIT_TEST) +=3D platform-test.o diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c new file mode 100644 index 0000000000000..53c98e225a895 --- /dev/null +++ b/lib/kunit/bug.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit helpers for backtrace suppression + * + * Copyright (C) 2025 Alessandro Carminati + * Copyright (C) 2024 Guenter Roeck + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_KUNIT_SUPPRESS_BACKTRACE + +static LIST_HEAD(suppressed_warnings); + +void __kunit_start_suppress_warning(struct __suppressed_warning *warning) +{ + list_add_rcu(&warning->node, &suppressed_warnings); +} +EXPORT_SYMBOL_GPL(__kunit_start_suppress_warning); + +void __kunit_end_suppress_warning(struct __suppressed_warning *warning) +{ + list_del_rcu(&warning->node); + synchronize_rcu(); /* Wait for readers to finish */ +} +EXPORT_SYMBOL_GPL(__kunit_end_suppress_warning); + +static bool __kunit_check_suppress(const char *function) +{ + struct __suppressed_warning *warning; + + if (!function) + return false; + + list_for_each_entry(warning, &suppressed_warnings, node) { + if (!strcmp(function, warning->function)) { + warning->counter++; + return true; + } + } + return false; +} + +noinstr bool __kunit_is_suppressed_warning(const char *function) +{ + bool ret; + + instrumentation_begin(); + ret =3D __kunit_check_suppress(function); + instrumentation_end(); + return ret; +} +EXPORT_SYMBOL_GPL(__kunit_is_suppressed_warning); + +#endif /* CONFIG_KUNIT_SUPPRESS_BACKTRACE */ --=20 2.52.0