Commit 19d43626 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

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: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: default avatarPeter 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: default avatarIngo Molnar <mingo@kernel.org>
parent 70579a86
...@@ -55,7 +55,7 @@ _BUGVERBOSE_LOCATION(__FILE__, __LINE__) \ ...@@ -55,7 +55,7 @@ _BUGVERBOSE_LOCATION(__FILE__, __LINE__) \
unreachable(); \ unreachable(); \
} while (0) } while (0)
#define __WARN_TAINT(taint) _BUG_FLAGS(BUGFLAG_TAINT(taint)) #define __WARN_FLAGS(flags) _BUG_FLAGS(BUGFLAG_WARNING|(flags))
#endif /* ! CONFIG_GENERIC_BUG */ #endif /* ! CONFIG_GENERIC_BUG */
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
#endif #endif
#ifdef CONFIG_DEBUG_BUGVERBOSE #ifdef CONFIG_DEBUG_BUGVERBOSE
#define __WARN_TAINT(taint) \ #define __WARN_FLAGS(flags) \
do { \ do { \
asm volatile("\n" \ asm volatile("\n" \
"1:\t" PARISC_BUG_BREAK_ASM "\n" \ "1:\t" PARISC_BUG_BREAK_ASM "\n" \
...@@ -56,11 +56,11 @@ ...@@ -56,11 +56,11 @@
"\t.org 2b+%c3\n" \ "\t.org 2b+%c3\n" \
"\t.popsection" \ "\t.popsection" \
: : "i" (__FILE__), "i" (__LINE__), \ : : "i" (__FILE__), "i" (__LINE__), \
"i" (BUGFLAG_TAINT(taint)), \ "i" (BUGFLAG_WARNING|(flags)), \
"i" (sizeof(struct bug_entry)) ); \ "i" (sizeof(struct bug_entry)) ); \
} while(0) } while(0)
#else #else
#define __WARN_TAINT(taint) \ #define __WARN_FLAGS(flags) \
do { \ do { \
asm volatile("\n" \ asm volatile("\n" \
"1:\t" PARISC_BUG_BREAK_ASM "\n" \ "1:\t" PARISC_BUG_BREAK_ASM "\n" \
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
"\t.short %c0\n" \ "\t.short %c0\n" \
"\t.org 2b+%c1\n" \ "\t.org 2b+%c1\n" \
"\t.popsection" \ "\t.popsection" \
: : "i" (BUGFLAG_TAINT(taint)), \ : : "i" (BUGFLAG_WARNING|(flags)), \
"i" (sizeof(struct bug_entry)) ); \ "i" (sizeof(struct bug_entry)) ); \
} while(0) } while(0)
#endif #endif
......
...@@ -85,12 +85,12 @@ ...@@ -85,12 +85,12 @@
} \ } \
} while (0) } while (0)
#define __WARN_TAINT(taint) do { \ #define __WARN_FLAGS(flags) do { \
__asm__ __volatile__( \ __asm__ __volatile__( \
"1: twi 31,0,0\n" \ "1: twi 31,0,0\n" \
_EMIT_BUG_ENTRY \ _EMIT_BUG_ENTRY \
: : "i" (__FILE__), "i" (__LINE__), \ : : "i" (__FILE__), "i" (__LINE__), \
"i" (BUGFLAG_TAINT(taint)), \ "i" (BUGFLAG_WARNING|(flags)), \
"i" (sizeof(struct bug_entry))); \ "i" (sizeof(struct bug_entry))); \
} while (0) } while (0)
......
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
unreachable(); \ unreachable(); \
} while (0) } while (0)
#define __WARN_TAINT(taint) do { \ #define __WARN_FLAGS(flags) do { \
__EMIT_BUG(BUGFLAG_TAINT(taint)); \ __EMIT_BUG(BUGFLAG_WARNING|(flags)); \
} while (0) } while (0)
#define WARN_ON(x) ({ \ #define WARN_ON(x) ({ \
......
...@@ -50,7 +50,7 @@ do { \ ...@@ -50,7 +50,7 @@ do { \
"i" (sizeof(struct bug_entry))); \ "i" (sizeof(struct bug_entry))); \
} while (0) } while (0)
#define __WARN_TAINT(taint) \ #define __WARN_FLAGS(flags) \
do { \ do { \
__asm__ __volatile__ ( \ __asm__ __volatile__ ( \
"1:\t.short %O0\n" \ "1:\t.short %O0\n" \
...@@ -59,7 +59,7 @@ do { \ ...@@ -59,7 +59,7 @@ do { \
: "n" (TRAPA_BUG_OPCODE), \ : "n" (TRAPA_BUG_OPCODE), \
"i" (__FILE__), \ "i" (__FILE__), \
"i" (__LINE__), \ "i" (__LINE__), \
"i" (BUGFLAG_TAINT(taint)), \ "i" (BUGFLAG_WARNING|(flags)), \
"i" (sizeof(struct bug_entry))); \ "i" (sizeof(struct bug_entry))); \
} while (0) } while (0)
......
...@@ -76,7 +76,7 @@ do { \ ...@@ -76,7 +76,7 @@ do { \
unreachable(); \ unreachable(); \
} while (0) } 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> #include <asm-generic/bug.h>
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifdef CONFIG_GENERIC_BUG #ifdef CONFIG_GENERIC_BUG
#define BUGFLAG_WARNING (1 << 0) #define BUGFLAG_WARNING (1 << 0)
#define BUGFLAG_ONCE (1 << 1)
#define BUGFLAG_DONE (1 << 2)
#define BUGFLAG_TAINT(taint) (BUGFLAG_WARNING | ((taint) << 8)) #define BUGFLAG_TAINT(taint) (BUGFLAG_WARNING | ((taint) << 8))
#define BUG_GET_TAINT(bug) ((bug)->flags >> 8) #define BUG_GET_TAINT(bug) ((bug)->flags >> 8)
#endif #endif
...@@ -55,6 +57,18 @@ struct bug_entry { ...@@ -55,6 +57,18 @@ struct bug_entry {
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0) #define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
#endif #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 * WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report
* significant issues that need prompt attention if they should ever * 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, ...@@ -97,7 +111,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
#endif #endif
#ifndef WARN #ifndef WARN
#define WARN(condition, format...) ({ \ #define WARN(condition, format...) ({ \
int __ret_warn_on = !!(condition); \ int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \ if (unlikely(__ret_warn_on)) \
__WARN_printf(format); \ __WARN_printf(format); \
...@@ -112,6 +126,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint, ...@@ -112,6 +126,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
unlikely(__ret_warn_on); \ unlikely(__ret_warn_on); \
}) })
#ifndef WARN_ON_ONCE
#define WARN_ON_ONCE(condition) ({ \ #define WARN_ON_ONCE(condition) ({ \
static bool __section(.data.unlikely) __warned; \ static bool __section(.data.unlikely) __warned; \
int __ret_warn_once = !!(condition); \ int __ret_warn_once = !!(condition); \
...@@ -122,6 +137,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint, ...@@ -122,6 +137,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
} \ } \
unlikely(__ret_warn_once); \ unlikely(__ret_warn_once); \
}) })
#endif
#define WARN_ONCE(condition, format...) ({ \ #define WARN_ONCE(condition, format...) ({ \
static bool __section(.data.unlikely) __warned; \ static bool __section(.data.unlikely) __warned; \
......
...@@ -286,8 +286,6 @@ ...@@ -286,8 +286,6 @@
*(.rodata1) \ *(.rodata1) \
} \ } \
\ \
BUG_TABLE \
\
/* PCI quirks */ \ /* PCI quirks */ \
.pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \
...@@ -855,7 +853,8 @@ ...@@ -855,7 +853,8 @@
READ_MOSTLY_DATA(cacheline) \ READ_MOSTLY_DATA(cacheline) \
DATA_DATA \ DATA_DATA \
CONSTRUCTORS \ CONSTRUCTORS \
} } \
BUG_TABLE
#define INIT_TEXT_SECTION(inittext_align) \ #define INIT_TEXT_SECTION(inittext_align) \
. = ALIGN(inittext_align); \ . = ALIGN(inittext_align); \
......
...@@ -105,7 +105,7 @@ static inline int is_warning_bug(const struct bug_entry *bug) ...@@ -105,7 +105,7 @@ static inline int is_warning_bug(const struct bug_entry *bug)
return bug->flags & BUGFLAG_WARNING; 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); enum bug_trap_type report_bug(unsigned long bug_addr, struct pt_regs *regs);
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/rculist.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) 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) ...@@ -62,10 +62,10 @@ static inline unsigned long bug_addr(const struct bug_entry *bug)
/* Updates are protected by module mutex */ /* Updates are protected by module mutex */
static LIST_HEAD(module_bug_list); 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; struct module *mod;
const struct bug_entry *bug = NULL; struct bug_entry *bug = NULL;
rcu_read_lock_sched(); rcu_read_lock_sched();
list_for_each_entry_rcu(mod, &module_bug_list, bug_list) { list_for_each_entry_rcu(mod, &module_bug_list, bug_list) {
...@@ -122,15 +122,15 @@ void module_bug_cleanup(struct module *mod) ...@@ -122,15 +122,15 @@ void module_bug_cleanup(struct module *mod)
#else #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; return NULL;
} }
#endif #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) for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
if (bugaddr == bug_addr(bug)) if (bugaddr == bug_addr(bug))
...@@ -141,9 +141,9 @@ const struct bug_entry *find_bug(unsigned long bugaddr) ...@@ -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) 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; const char *file;
unsigned line, warning; unsigned line, warning, once, done;
if (!is_valid_bugaddr(bugaddr)) if (!is_valid_bugaddr(bugaddr))
return BUG_TRAP_TYPE_NONE; return BUG_TRAP_TYPE_NONE;
...@@ -164,6 +164,18 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) ...@@ -164,6 +164,18 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
line = bug->line; line = bug->line;
#endif #endif
warning = (bug->flags & BUGFLAG_WARNING) != 0; 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) { if (warning) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment