Commit b1fca27d authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

kernel debug: support resetting WARN*_ONCE

I like _ONCE warnings because it's guaranteed that they don't flood the
log.

During testing I find it useful to reset the state of the once warnings,
so that I can rerun tests and see if they trigger again, or can
guarantee that a test run always hits the same warnings.

This patch adds a debugfs interface to reset all the _ONCE warnings so
that they appear again:

  echo 1 > /sys/kernel/debug/clear_warn_once

This is implemented by putting all the warning booleans into a special
section, and clearing it.

[akpm@linux-foundation.org: coding-style fixes]
Link: http://lkml.kernel.org/r/20171017221455.6740-1-andi@firstfloor.orgSigned-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Tested-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fb6cc4ac
WARN_ONCE / WARN_ON_ONCE only print a warning once.
echo 1 > /sys/kernel/debug/clear_warn_once
clears the state and allows the warnings to print once again.
This can be useful after test suite runs to reproduce problems.
...@@ -130,7 +130,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint, ...@@ -130,7 +130,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
#ifndef WARN_ON_ONCE #ifndef WARN_ON_ONCE
#define WARN_ON_ONCE(condition) ({ \ #define WARN_ON_ONCE(condition) ({ \
static bool __section(.data.unlikely) __warned; \ static bool __section(.data.once) __warned; \
int __ret_warn_once = !!(condition); \ int __ret_warn_once = !!(condition); \
\ \
if (unlikely(__ret_warn_once && !__warned)) { \ if (unlikely(__ret_warn_once && !__warned)) { \
...@@ -142,7 +142,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint, ...@@ -142,7 +142,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
#endif #endif
#define WARN_ONCE(condition, format...) ({ \ #define WARN_ONCE(condition, format...) ({ \
static bool __section(.data.unlikely) __warned; \ static bool __section(.data.once) __warned; \
int __ret_warn_once = !!(condition); \ int __ret_warn_once = !!(condition); \
\ \
if (unlikely(__ret_warn_once && !__warned)) { \ if (unlikely(__ret_warn_once && !__warned)) { \
...@@ -153,7 +153,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint, ...@@ -153,7 +153,7 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
}) })
#define WARN_TAINT_ONCE(condition, taint, format...) ({ \ #define WARN_TAINT_ONCE(condition, taint, format...) ({ \
static bool __section(.data.unlikely) __warned; \ static bool __section(.data.once) __warned; \
int __ret_warn_once = !!(condition); \ int __ret_warn_once = !!(condition); \
\ \
if (unlikely(__ret_warn_once && !__warned)) { \ if (unlikely(__ret_warn_once && !__warned)) { \
......
...@@ -44,6 +44,7 @@ extern char __entry_text_start[], __entry_text_end[]; ...@@ -44,6 +44,7 @@ extern char __entry_text_start[], __entry_text_end[];
extern char __start_rodata[], __end_rodata[]; extern char __start_rodata[], __end_rodata[];
extern char __irqentry_text_start[], __irqentry_text_end[]; extern char __irqentry_text_start[], __irqentry_text_end[];
extern char __softirqentry_text_start[], __softirqentry_text_end[]; extern char __softirqentry_text_start[], __softirqentry_text_end[];
extern char __start_once[], __end_once[];
/* Start and end of .ctors section - used for constructor calls. */ /* Start and end of .ctors section - used for constructor calls. */
extern char __ctors_start[], __ctors_end[]; extern char __ctors_start[], __ctors_end[];
......
...@@ -223,6 +223,9 @@ ...@@ -223,6 +223,9 @@
MEM_KEEP(init.data) \ MEM_KEEP(init.data) \
MEM_KEEP(exit.data) \ MEM_KEEP(exit.data) \
*(.data.unlikely) \ *(.data.unlikely) \
VMLINUX_SYMBOL(__start_once) = .; \
*(.data.once) \
VMLINUX_SYMBOL(__end_once) = .; \
STRUCT_ALIGN(); \ STRUCT_ALIGN(); \
*(__tracepoints) \ *(__tracepoints) \
/* implement dynamic printk debug */ \ /* implement dynamic printk debug */ \
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/debugfs.h>
#include <asm/sections.h>
#define PANIC_TIMER_STEP 100 #define PANIC_TIMER_STEP 100
#define PANIC_BLINK_SPD 18 #define PANIC_BLINK_SPD 18
...@@ -587,6 +589,32 @@ void warn_slowpath_null(const char *file, int line) ...@@ -587,6 +589,32 @@ void warn_slowpath_null(const char *file, int line)
EXPORT_SYMBOL(warn_slowpath_null); EXPORT_SYMBOL(warn_slowpath_null);
#endif #endif
#ifdef CONFIG_BUG
/* Support resetting WARN*_ONCE state */
static int clear_warn_once_set(void *data, u64 val)
{
memset(__start_once, 0, __end_once - __start_once);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(clear_warn_once_fops,
NULL,
clear_warn_once_set,
"%lld\n");
static __init int register_warn_debugfs(void)
{
/* Don't care about failure */
debugfs_create_file("clear_warn_once", 0644, NULL,
NULL, &clear_warn_once_fops);
return 0;
}
device_initcall(register_warn_debugfs);
#endif
#ifdef CONFIG_CC_STACKPROTECTOR #ifdef CONFIG_CC_STACKPROTECTOR
/* /*
......
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