mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	debug: Add _ONCE() logic to report_bug()
Josh suggested moving the _ONCE logic inside the trap handler, using a bit in the bug_entry::flags field, avoiding the need for the extra variable. Sadly this only works for WARN_ON_ONCE(), since the others have printk() statements prior to triggering the trap. Still, this saves a fair amount of text and some data: text data filename 10682460 4530992 defconfig-build/vmlinux.orig 10665111 4530096 defconfig-build/vmlinux.patched Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andy Lutomirski <luto@kernel.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
		
							parent
							
								
									70579a86e3
								
							
						
					
					
						commit
						19d436268d
					
				
					 10 changed files with 52 additions and 25 deletions
				
			
		| 
						 | 
				
			
			@ -55,7 +55,7 @@ _BUGVERBOSE_LOCATION(__FILE__, __LINE__)		\
 | 
			
		|||
	unreachable();				\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define __WARN_TAINT(taint) _BUG_FLAGS(BUGFLAG_TAINT(taint))
 | 
			
		||||
#define __WARN_FLAGS(flags) _BUG_FLAGS(BUGFLAG_WARNING|(flags))
 | 
			
		||||
 | 
			
		||||
#endif /* ! CONFIG_GENERIC_BUG */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,7 +46,7 @@
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
 | 
			
		||||
#define __WARN_TAINT(taint)						\
 | 
			
		||||
#define __WARN_FLAGS(flags)						\
 | 
			
		||||
	do {								\
 | 
			
		||||
		asm volatile("\n"					\
 | 
			
		||||
			     "1:\t" PARISC_BUG_BREAK_ASM "\n"		\
 | 
			
		||||
| 
						 | 
				
			
			@ -56,11 +56,11 @@
 | 
			
		|||
			     "\t.org 2b+%c3\n"				\
 | 
			
		||||
			     "\t.popsection"				\
 | 
			
		||||
			     : : "i" (__FILE__), "i" (__LINE__),	\
 | 
			
		||||
			     "i" (BUGFLAG_TAINT(taint)), 		\
 | 
			
		||||
			     "i" (BUGFLAG_WARNING|(flags)),		\
 | 
			
		||||
			     "i" (sizeof(struct bug_entry)) );		\
 | 
			
		||||
	} while(0)
 | 
			
		||||
#else
 | 
			
		||||
#define __WARN_TAINT(taint)						\
 | 
			
		||||
#define __WARN_FLAGS(flags)						\
 | 
			
		||||
	do {								\
 | 
			
		||||
		asm volatile("\n"					\
 | 
			
		||||
			     "1:\t" PARISC_BUG_BREAK_ASM "\n"		\
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +69,7 @@
 | 
			
		|||
			     "\t.short %c0\n"				\
 | 
			
		||||
			     "\t.org 2b+%c1\n"				\
 | 
			
		||||
			     "\t.popsection"				\
 | 
			
		||||
			     : : "i" (BUGFLAG_TAINT(taint)),		\
 | 
			
		||||
			     : : "i" (BUGFLAG_WARNING|(flags)),		\
 | 
			
		||||
			     "i" (sizeof(struct bug_entry)) );		\
 | 
			
		||||
	} while(0)
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,12 +85,12 @@
 | 
			
		|||
	}							\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define __WARN_TAINT(taint) do {				\
 | 
			
		||||
#define __WARN_FLAGS(flags) do {				\
 | 
			
		||||
	__asm__ __volatile__(					\
 | 
			
		||||
		"1:	twi 31,0,0\n"				\
 | 
			
		||||
		_EMIT_BUG_ENTRY					\
 | 
			
		||||
		: : "i" (__FILE__), "i" (__LINE__),		\
 | 
			
		||||
		  "i" (BUGFLAG_TAINT(taint)),			\
 | 
			
		||||
		  "i" (BUGFLAG_WARNING|(flags)),		\
 | 
			
		||||
		  "i" (sizeof(struct bug_entry)));		\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,8 +46,8 @@
 | 
			
		|||
	unreachable();					\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define __WARN_TAINT(taint) do {			\
 | 
			
		||||
	__EMIT_BUG(BUGFLAG_TAINT(taint));		\
 | 
			
		||||
#define __WARN_FLAGS(flags) do {			\
 | 
			
		||||
	__EMIT_BUG(BUGFLAG_WARNING|(flags));		\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define WARN_ON(x) ({					\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ do {							\
 | 
			
		|||
		   "i" (sizeof(struct bug_entry)));	\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define __WARN_TAINT(taint)				\
 | 
			
		||||
#define __WARN_FLAGS(flags)				\
 | 
			
		||||
do {							\
 | 
			
		||||
	__asm__ __volatile__ (				\
 | 
			
		||||
		"1:\t.short %O0\n"			\
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +59,7 @@ do {							\
 | 
			
		|||
		 : "n" (TRAPA_BUG_OPCODE),		\
 | 
			
		||||
		   "i" (__FILE__),			\
 | 
			
		||||
		   "i" (__LINE__),			\
 | 
			
		||||
		   "i" (BUGFLAG_TAINT(taint)),		\
 | 
			
		||||
		   "i" (BUGFLAG_WARNING|(flags)),	\
 | 
			
		||||
		   "i" (sizeof(struct bug_entry)));	\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,7 @@ do {								\
 | 
			
		|||
	unreachable();						\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define __WARN_TAINT(taint)	_BUG_FLAGS(ASM_UD0, BUGFLAG_TAINT(taint))
 | 
			
		||||
#define __WARN_FLAGS(flags)	_BUG_FLAGS(ASM_UD0, BUGFLAG_WARNING|(flags))
 | 
			
		||||
 | 
			
		||||
#include <asm-generic/bug.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,8 @@
 | 
			
		|||
 | 
			
		||||
#ifdef CONFIG_GENERIC_BUG
 | 
			
		||||
#define BUGFLAG_WARNING		(1 << 0)
 | 
			
		||||
#define BUGFLAG_ONCE		(1 << 1)
 | 
			
		||||
#define BUGFLAG_DONE		(1 << 2)
 | 
			
		||||
#define BUGFLAG_TAINT(taint)	(BUGFLAG_WARNING | ((taint) << 8))
 | 
			
		||||
#define BUG_GET_TAINT(bug)	((bug)->flags >> 8)
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -55,6 +57,18 @@ struct bug_entry {
 | 
			
		|||
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __WARN_FLAGS
 | 
			
		||||
#define __WARN_TAINT(taint)		__WARN_FLAGS(BUGFLAG_TAINT(taint))
 | 
			
		||||
#define __WARN_ONCE_TAINT(taint)	__WARN_FLAGS(BUGFLAG_ONCE|BUGFLAG_TAINT(taint))
 | 
			
		||||
 | 
			
		||||
#define WARN_ON_ONCE(condition) ({				\
 | 
			
		||||
	int __ret_warn_on = !!(condition);			\
 | 
			
		||||
	if (unlikely(__ret_warn_on))				\
 | 
			
		||||
		__WARN_ONCE_TAINT(TAINT_WARN);			\
 | 
			
		||||
	unlikely(__ret_warn_on);				\
 | 
			
		||||
})
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report
 | 
			
		||||
 * significant issues that need prompt attention if they should ever
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +111,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef WARN
 | 
			
		||||
#define WARN(condition, format...) ({						\
 | 
			
		||||
#define WARN(condition, format...) ({					\
 | 
			
		||||
	int __ret_warn_on = !!(condition);				\
 | 
			
		||||
	if (unlikely(__ret_warn_on))					\
 | 
			
		||||
		__WARN_printf(format);					\
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +126,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
 | 
			
		|||
	unlikely(__ret_warn_on);					\
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
#ifndef WARN_ON_ONCE
 | 
			
		||||
#define WARN_ON_ONCE(condition)	({				\
 | 
			
		||||
	static bool __section(.data.unlikely) __warned;		\
 | 
			
		||||
	int __ret_warn_once = !!(condition);			\
 | 
			
		||||
| 
						 | 
				
			
			@ -122,6 +137,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
 | 
			
		|||
	}							\
 | 
			
		||||
	unlikely(__ret_warn_once);				\
 | 
			
		||||
})
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define WARN_ONCE(condition, format...)	({			\
 | 
			
		||||
	static bool __section(.data.unlikely) __warned;		\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -286,8 +286,6 @@
 | 
			
		|||
		*(.rodata1)						\
 | 
			
		||||
	}								\
 | 
			
		||||
									\
 | 
			
		||||
	BUG_TABLE							\
 | 
			
		||||
									\
 | 
			
		||||
	/* PCI quirks */						\
 | 
			
		||||
	.pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {	\
 | 
			
		||||
		VMLINUX_SYMBOL(__start_pci_fixups_early) = .;		\
 | 
			
		||||
| 
						 | 
				
			
			@ -855,7 +853,8 @@
 | 
			
		|||
		READ_MOSTLY_DATA(cacheline)				\
 | 
			
		||||
		DATA_DATA						\
 | 
			
		||||
		CONSTRUCTORS						\
 | 
			
		||||
	}
 | 
			
		||||
	}								\
 | 
			
		||||
	BUG_TABLE
 | 
			
		||||
 | 
			
		||||
#define INIT_TEXT_SECTION(inittext_align)				\
 | 
			
		||||
	. = ALIGN(inittext_align);					\
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,7 +105,7 @@ static inline int is_warning_bug(const struct bug_entry *bug)
 | 
			
		|||
	return bug->flags & BUGFLAG_WARNING;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const struct bug_entry *find_bug(unsigned long bugaddr);
 | 
			
		||||
struct bug_entry *find_bug(unsigned long bugaddr);
 | 
			
		||||
 | 
			
		||||
enum bug_trap_type report_bug(unsigned long bug_addr, struct pt_regs *regs);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										28
									
								
								lib/bug.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								lib/bug.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -47,7 +47,7 @@
 | 
			
		|||
#include <linux/sched.h>
 | 
			
		||||
#include <linux/rculist.h>
 | 
			
		||||
 | 
			
		||||
extern const struct bug_entry __start___bug_table[], __stop___bug_table[];
 | 
			
		||||
extern struct bug_entry __start___bug_table[], __stop___bug_table[];
 | 
			
		||||
 | 
			
		||||
static inline unsigned long bug_addr(const struct bug_entry *bug)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -62,10 +62,10 @@ static inline unsigned long bug_addr(const struct bug_entry *bug)
 | 
			
		|||
/* Updates are protected by module mutex */
 | 
			
		||||
static LIST_HEAD(module_bug_list);
 | 
			
		||||
 | 
			
		||||
static const struct bug_entry *module_find_bug(unsigned long bugaddr)
 | 
			
		||||
static struct bug_entry *module_find_bug(unsigned long bugaddr)
 | 
			
		||||
{
 | 
			
		||||
	struct module *mod;
 | 
			
		||||
	const struct bug_entry *bug = NULL;
 | 
			
		||||
	struct bug_entry *bug = NULL;
 | 
			
		||||
 | 
			
		||||
	rcu_read_lock_sched();
 | 
			
		||||
	list_for_each_entry_rcu(mod, &module_bug_list, bug_list) {
 | 
			
		||||
| 
						 | 
				
			
			@ -122,15 +122,15 @@ void module_bug_cleanup(struct module *mod)
 | 
			
		|||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
static inline const struct bug_entry *module_find_bug(unsigned long bugaddr)
 | 
			
		||||
static inline struct bug_entry *module_find_bug(unsigned long bugaddr)
 | 
			
		||||
{
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
const struct bug_entry *find_bug(unsigned long bugaddr)
 | 
			
		||||
struct bug_entry *find_bug(unsigned long bugaddr)
 | 
			
		||||
{
 | 
			
		||||
	const struct bug_entry *bug;
 | 
			
		||||
	struct bug_entry *bug;
 | 
			
		||||
 | 
			
		||||
	for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
 | 
			
		||||
		if (bugaddr == bug_addr(bug))
 | 
			
		||||
| 
						 | 
				
			
			@ -141,9 +141,9 @@ const struct bug_entry *find_bug(unsigned long bugaddr)
 | 
			
		|||
 | 
			
		||||
enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
 | 
			
		||||
{
 | 
			
		||||
	const struct bug_entry *bug;
 | 
			
		||||
	struct bug_entry *bug;
 | 
			
		||||
	const char *file;
 | 
			
		||||
	unsigned line, warning;
 | 
			
		||||
	unsigned line, warning, once, done;
 | 
			
		||||
 | 
			
		||||
	if (!is_valid_bugaddr(bugaddr))
 | 
			
		||||
		return BUG_TRAP_TYPE_NONE;
 | 
			
		||||
| 
						 | 
				
			
			@ -164,6 +164,18 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
 | 
			
		|||
		line = bug->line;
 | 
			
		||||
#endif
 | 
			
		||||
		warning = (bug->flags & BUGFLAG_WARNING) != 0;
 | 
			
		||||
		once = (bug->flags & BUGFLAG_ONCE) != 0;
 | 
			
		||||
		done = (bug->flags & BUGFLAG_DONE) != 0;
 | 
			
		||||
 | 
			
		||||
		if (warning && once) {
 | 
			
		||||
			if (done)
 | 
			
		||||
				return BUG_TRAP_TYPE_WARN;
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * Since this is the only store, concurrency is not an issue.
 | 
			
		||||
			 */
 | 
			
		||||
			bug->flags |= BUGFLAG_DONE;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (warning) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue