diff options
author | Borislav Petkov <bp@suse.de> | 2016-08-02 17:04:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-08-02 19:35:06 -0400 |
commit | 6b1d174b0c27b5de421eda55c2731f32b6bd9852 (patch) | |
tree | 3095928a9c579090ef8db9cb6df7125ec1c638db | |
parent | b5644a153d2701ffc335cfb9ef49967bd5b6a3c2 (diff) |
ratelimit: extend to print suppressed messages on release
Extend the ratelimiting facility to print the amount of suppressed lines
when it is being released.
This use case is aimed at short-termed, burst-like users for which we
want to output the suppressed lines stats only once, after it has been
disposed of. For an example, see /dev/kmsg usage in a follow-on patch.
Also, change the printk() line we issue on release to not use
"callbacks" as it is misleading: we're not suppressing callbacks but
printk() calls.
This has been separated from a previous patch by Linus.
Link: http://lkml.kernel.org/r/20160716061745.15795-2-bp@alien8.de
Signed-off-by: Borislav Petkov <bp@suse.de>
Cc: Dave Young <dyoung@redhat.com>
Cc: Franck Bui <fbui@suse.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/ratelimit.h | 38 | ||||
-rw-r--r-- | lib/ratelimit.c | 10 |
2 files changed, 39 insertions, 9 deletions
diff --git a/include/linux/ratelimit.h b/include/linux/ratelimit.h index 18102529254e..57c9e0622a38 100644 --- a/include/linux/ratelimit.h +++ b/include/linux/ratelimit.h | |||
@@ -2,11 +2,15 @@ | |||
2 | #define _LINUX_RATELIMIT_H | 2 | #define _LINUX_RATELIMIT_H |
3 | 3 | ||
4 | #include <linux/param.h> | 4 | #include <linux/param.h> |
5 | #include <linux/sched.h> | ||
5 | #include <linux/spinlock.h> | 6 | #include <linux/spinlock.h> |
6 | 7 | ||
7 | #define DEFAULT_RATELIMIT_INTERVAL (5 * HZ) | 8 | #define DEFAULT_RATELIMIT_INTERVAL (5 * HZ) |
8 | #define DEFAULT_RATELIMIT_BURST 10 | 9 | #define DEFAULT_RATELIMIT_BURST 10 |
9 | 10 | ||
11 | /* issue num suppressed message on exit */ | ||
12 | #define RATELIMIT_MSG_ON_RELEASE BIT(0) | ||
13 | |||
10 | struct ratelimit_state { | 14 | struct ratelimit_state { |
11 | raw_spinlock_t lock; /* protect the state */ | 15 | raw_spinlock_t lock; /* protect the state */ |
12 | 16 | ||
@@ -15,6 +19,7 @@ struct ratelimit_state { | |||
15 | int printed; | 19 | int printed; |
16 | int missed; | 20 | int missed; |
17 | unsigned long begin; | 21 | unsigned long begin; |
22 | unsigned long flags; | ||
18 | }; | 23 | }; |
19 | 24 | ||
20 | #define RATELIMIT_STATE_INIT(name, interval_init, burst_init) { \ | 25 | #define RATELIMIT_STATE_INIT(name, interval_init, burst_init) { \ |
@@ -34,12 +39,35 @@ struct ratelimit_state { | |||
34 | static inline void ratelimit_state_init(struct ratelimit_state *rs, | 39 | static inline void ratelimit_state_init(struct ratelimit_state *rs, |
35 | int interval, int burst) | 40 | int interval, int burst) |
36 | { | 41 | { |
42 | memset(rs, 0, sizeof(*rs)); | ||
43 | |||
37 | raw_spin_lock_init(&rs->lock); | 44 | raw_spin_lock_init(&rs->lock); |
38 | rs->interval = interval; | 45 | rs->interval = interval; |
39 | rs->burst = burst; | 46 | rs->burst = burst; |
40 | rs->printed = 0; | 47 | } |
41 | rs->missed = 0; | 48 | |
42 | rs->begin = 0; | 49 | static inline void ratelimit_default_init(struct ratelimit_state *rs) |
50 | { | ||
51 | return ratelimit_state_init(rs, DEFAULT_RATELIMIT_INTERVAL, | ||
52 | DEFAULT_RATELIMIT_BURST); | ||
53 | } | ||
54 | |||
55 | static inline void ratelimit_state_exit(struct ratelimit_state *rs) | ||
56 | { | ||
57 | if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) | ||
58 | return; | ||
59 | |||
60 | if (rs->missed) { | ||
61 | pr_warn("%s: %d output lines suppressed due to ratelimiting\n", | ||
62 | current->comm, rs->missed); | ||
63 | rs->missed = 0; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static inline void | ||
68 | ratelimit_set_flags(struct ratelimit_state *rs, unsigned long flags) | ||
69 | { | ||
70 | rs->flags = flags; | ||
43 | } | 71 | } |
44 | 72 | ||
45 | extern struct ratelimit_state printk_ratelimit_state; | 73 | extern struct ratelimit_state printk_ratelimit_state; |
diff --git a/lib/ratelimit.c b/lib/ratelimit.c index 2c5de86460c5..08f8043cac61 100644 --- a/lib/ratelimit.c +++ b/lib/ratelimit.c | |||
@@ -46,12 +46,14 @@ int ___ratelimit(struct ratelimit_state *rs, const char *func) | |||
46 | rs->begin = jiffies; | 46 | rs->begin = jiffies; |
47 | 47 | ||
48 | if (time_is_before_jiffies(rs->begin + rs->interval)) { | 48 | if (time_is_before_jiffies(rs->begin + rs->interval)) { |
49 | if (rs->missed) | 49 | if (rs->missed) { |
50 | printk(KERN_WARNING "%s: %d callbacks suppressed\n", | 50 | if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) { |
51 | func, rs->missed); | 51 | pr_warn("%s: %d callbacks suppressed\n", func, rs->missed); |
52 | rs->missed = 0; | ||
53 | } | ||
54 | } | ||
52 | rs->begin = jiffies; | 55 | rs->begin = jiffies; |
53 | rs->printed = 0; | 56 | rs->printed = 0; |
54 | rs->missed = 0; | ||
55 | } | 57 | } |
56 | if (rs->burst && rs->burst > rs->printed) { | 58 | if (rs->burst && rs->burst > rs->printed) { |
57 | rs->printed++; | 59 | rs->printed++; |