Commit 717115e1a5856b57af0f71e1df7149108294fc10
Committed by
Linus Torvalds
1 parent
2711b793eb
Exists in
master
and in
4 other branches
printk ratelimiting rewrite
All ratelimit user use same jiffies and burst params, so some messages (callbacks) will be lost. For example: a call printk_ratelimit(5 * HZ, 1) b call printk_ratelimit(5 * HZ, 1) before the 5*HZ timeout of a, then b will will be supressed. - rewrite __ratelimit, and use a ratelimit_state as parameter. Thanks for hints from andrew. - Add WARN_ON_RATELIMIT, update rcupreempt.h - remove __printk_ratelimit - use __ratelimit in net_ratelimit Signed-off-by: Dave Young <hidave.darkstar@gmail.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: "Paul E. McKenney" <paulmck@us.ibm.com> Cc: Dave Young <hidave.darkstar@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 10 changed files with 79 additions and 56 deletions Side-by-side Diff
include/asm-generic/bug.h
include/linux/kernel.h
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | #include <linux/bitops.h> |
16 | 16 | #include <linux/log2.h> |
17 | 17 | #include <linux/typecheck.h> |
18 | +#include <linux/ratelimit.h> | |
18 | 19 | #include <asm/byteorder.h> |
19 | 20 | #include <asm/bug.h> |
20 | 21 | |
21 | 22 | |
... | ... | @@ -189,11 +190,8 @@ |
189 | 190 | asmlinkage int printk(const char * fmt, ...) |
190 | 191 | __attribute__ ((format (printf, 1, 2))) __cold; |
191 | 192 | |
192 | -extern int printk_ratelimit_jiffies; | |
193 | -extern int printk_ratelimit_burst; | |
193 | +extern struct ratelimit_state printk_ratelimit_state; | |
194 | 194 | extern int printk_ratelimit(void); |
195 | -extern int __ratelimit(int ratelimit_jiffies, int ratelimit_burst); | |
196 | -extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst); | |
197 | 195 | extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, |
198 | 196 | unsigned int interval_msec); |
199 | 197 | #else |
... | ... | @@ -204,8 +202,6 @@ |
204 | 202 | __attribute__ ((format (printf, 1, 2))); |
205 | 203 | static inline int __cold printk(const char *s, ...) { return 0; } |
206 | 204 | static inline int printk_ratelimit(void) { return 0; } |
207 | -static inline int __printk_ratelimit(int ratelimit_jiffies, \ | |
208 | - int ratelimit_burst) { return 0; } | |
209 | 205 | static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \ |
210 | 206 | unsigned int interval_msec) \ |
211 | 207 | { return false; } |
include/linux/net.h
include/linux/ratelimit.h
1 | +#ifndef _LINUX_RATELIMIT_H | |
2 | +#define _LINUX_RATELIMIT_H | |
3 | +#include <linux/param.h> | |
4 | + | |
5 | +#define DEFAULT_RATELIMIT_INTERVAL (5 * HZ) | |
6 | +#define DEFAULT_RATELIMIT_BURST 10 | |
7 | + | |
8 | +struct ratelimit_state { | |
9 | + int interval; | |
10 | + int burst; | |
11 | + int printed; | |
12 | + int missed; | |
13 | + unsigned long begin; | |
14 | +}; | |
15 | + | |
16 | +#define DEFINE_RATELIMIT_STATE(name, interval, burst) \ | |
17 | + struct ratelimit_state name = {interval, burst,} | |
18 | + | |
19 | +extern int __ratelimit(struct ratelimit_state *rs); | |
20 | + | |
21 | +static inline int ratelimit(void) | |
22 | +{ | |
23 | + static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, | |
24 | + DEFAULT_RATELIMIT_BURST); | |
25 | + return __ratelimit(&rs); | |
26 | +} | |
27 | +#endif |
include/linux/rcupreempt.h
... | ... | @@ -115,16 +115,21 @@ |
115 | 115 | |
116 | 116 | static inline void rcu_enter_nohz(void) |
117 | 117 | { |
118 | + static DEFINE_RATELIMIT_STATE(rs, 10 * HZ, 1); | |
119 | + | |
118 | 120 | smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ |
119 | 121 | __get_cpu_var(rcu_dyntick_sched).dynticks++; |
120 | - WARN_ON(__get_cpu_var(rcu_dyntick_sched).dynticks & 0x1); | |
122 | + WARN_ON_RATELIMIT(__get_cpu_var(rcu_dyntick_sched).dynticks & 0x1, &rs); | |
121 | 123 | } |
122 | 124 | |
123 | 125 | static inline void rcu_exit_nohz(void) |
124 | 126 | { |
127 | + static DEFINE_RATELIMIT_STATE(rs, 10 * HZ, 1); | |
128 | + | |
125 | 129 | smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ |
126 | 130 | __get_cpu_var(rcu_dyntick_sched).dynticks++; |
127 | - WARN_ON(!(__get_cpu_var(rcu_dyntick_sched).dynticks & 0x1)); | |
131 | + WARN_ON_RATELIMIT(!(__get_cpu_var(rcu_dyntick_sched).dynticks & 0x1), | |
132 | + &rs); | |
128 | 133 | } |
129 | 134 | |
130 | 135 | #else /* CONFIG_NO_HZ */ |
kernel/printk.c
... | ... | @@ -1308,6 +1308,8 @@ |
1308 | 1308 | } |
1309 | 1309 | |
1310 | 1310 | #if defined CONFIG_PRINTK |
1311 | + | |
1312 | +DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); | |
1311 | 1313 | /* |
1312 | 1314 | * printk rate limiting, lifted from the networking subsystem. |
1313 | 1315 | * |
1314 | 1316 | |
... | ... | @@ -1315,22 +1317,9 @@ |
1315 | 1317 | * every printk_ratelimit_jiffies to make a denial-of-service |
1316 | 1318 | * attack impossible. |
1317 | 1319 | */ |
1318 | -int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst) | |
1319 | -{ | |
1320 | - return __ratelimit(ratelimit_jiffies, ratelimit_burst); | |
1321 | -} | |
1322 | -EXPORT_SYMBOL(__printk_ratelimit); | |
1323 | - | |
1324 | -/* minimum time in jiffies between messages */ | |
1325 | -int printk_ratelimit_jiffies = 5 * HZ; | |
1326 | - | |
1327 | -/* number of messages we send before ratelimiting */ | |
1328 | -int printk_ratelimit_burst = 10; | |
1329 | - | |
1330 | 1320 | int printk_ratelimit(void) |
1331 | 1321 | { |
1332 | - return __printk_ratelimit(printk_ratelimit_jiffies, | |
1333 | - printk_ratelimit_burst); | |
1322 | + return __ratelimit(&printk_ratelimit_state); | |
1334 | 1323 | } |
1335 | 1324 | EXPORT_SYMBOL(printk_ratelimit); |
1336 | 1325 |
kernel/sysctl.c
... | ... | @@ -624,7 +624,7 @@ |
624 | 624 | { |
625 | 625 | .ctl_name = KERN_PRINTK_RATELIMIT, |
626 | 626 | .procname = "printk_ratelimit", |
627 | - .data = &printk_ratelimit_jiffies, | |
627 | + .data = &printk_ratelimit_state.interval, | |
628 | 628 | .maxlen = sizeof(int), |
629 | 629 | .mode = 0644, |
630 | 630 | .proc_handler = &proc_dointvec_jiffies, |
... | ... | @@ -633,7 +633,7 @@ |
633 | 633 | { |
634 | 634 | .ctl_name = KERN_PRINTK_RATELIMIT_BURST, |
635 | 635 | .procname = "printk_ratelimit_burst", |
636 | - .data = &printk_ratelimit_burst, | |
636 | + .data = &printk_ratelimit_state.burst, | |
637 | 637 | .maxlen = sizeof(int), |
638 | 638 | .mode = 0644, |
639 | 639 | .proc_handler = &proc_dointvec, |
lib/ratelimit.c
... | ... | @@ -3,6 +3,9 @@ |
3 | 3 | * |
4 | 4 | * Isolated from kernel/printk.c by Dave Young <hidave.darkstar@gmail.com> |
5 | 5 | * |
6 | + * 2008-05-01 rewrite the function and use a ratelimit_state data struct as | |
7 | + * parameter. Now every user can use their own standalone ratelimit_state. | |
8 | + * | |
6 | 9 | * This file is released under the GPLv2. |
7 | 10 | * |
8 | 11 | */ |
9 | 12 | |
10 | 13 | |
11 | 14 | |
12 | 15 | |
13 | 16 | |
14 | 17 | |
15 | 18 | |
16 | 19 | |
... | ... | @@ -11,42 +14,44 @@ |
11 | 14 | #include <linux/jiffies.h> |
12 | 15 | #include <linux/module.h> |
13 | 16 | |
17 | +static DEFINE_SPINLOCK(ratelimit_lock); | |
18 | +static unsigned long flags; | |
19 | + | |
14 | 20 | /* |
15 | 21 | * __ratelimit - rate limiting |
16 | - * @ratelimit_jiffies: minimum time in jiffies between two callbacks | |
17 | - * @ratelimit_burst: number of callbacks we do before ratelimiting | |
22 | + * @rs: ratelimit_state data | |
18 | 23 | * |
19 | - * This enforces a rate limit: not more than @ratelimit_burst callbacks | |
20 | - * in every ratelimit_jiffies | |
24 | + * This enforces a rate limit: not more than @rs->ratelimit_burst callbacks | |
25 | + * in every @rs->ratelimit_jiffies | |
21 | 26 | */ |
22 | -int __ratelimit(int ratelimit_jiffies, int ratelimit_burst) | |
27 | +int __ratelimit(struct ratelimit_state *rs) | |
23 | 28 | { |
24 | - static DEFINE_SPINLOCK(ratelimit_lock); | |
25 | - static unsigned toks = 10 * 5 * HZ; | |
26 | - static unsigned long last_msg; | |
27 | - static int missed; | |
28 | - unsigned long flags; | |
29 | - unsigned long now = jiffies; | |
29 | + if (!rs->interval) | |
30 | + return 1; | |
30 | 31 | |
31 | 32 | spin_lock_irqsave(&ratelimit_lock, flags); |
32 | - toks += now - last_msg; | |
33 | - last_msg = now; | |
34 | - if (toks > (ratelimit_burst * ratelimit_jiffies)) | |
35 | - toks = ratelimit_burst * ratelimit_jiffies; | |
36 | - if (toks >= ratelimit_jiffies) { | |
37 | - int lost = missed; | |
33 | + if (!rs->begin) | |
34 | + rs->begin = jiffies; | |
38 | 35 | |
39 | - missed = 0; | |
40 | - toks -= ratelimit_jiffies; | |
41 | - spin_unlock_irqrestore(&ratelimit_lock, flags); | |
42 | - if (lost) | |
43 | - printk(KERN_WARNING "%s: %d messages suppressed\n", | |
44 | - __func__, lost); | |
45 | - return 1; | |
36 | + if (time_is_before_jiffies(rs->begin + rs->interval)) { | |
37 | + if (rs->missed) | |
38 | + printk(KERN_WARNING "%s: %d callbacks suppressed\n", | |
39 | + __func__, rs->missed); | |
40 | + rs->begin = 0; | |
41 | + rs->printed = 0; | |
42 | + rs->missed = 0; | |
46 | 43 | } |
47 | - missed++; | |
44 | + if (rs->burst && rs->burst > rs->printed) | |
45 | + goto print; | |
46 | + | |
47 | + rs->missed++; | |
48 | 48 | spin_unlock_irqrestore(&ratelimit_lock, flags); |
49 | 49 | return 0; |
50 | + | |
51 | +print: | |
52 | + rs->printed++; | |
53 | + spin_unlock_irqrestore(&ratelimit_lock, flags); | |
54 | + return 1; | |
50 | 55 | } |
51 | 56 | EXPORT_SYMBOL(__ratelimit); |
net/core/sysctl_net_core.c
... | ... | @@ -67,7 +67,7 @@ |
67 | 67 | { |
68 | 68 | .ctl_name = NET_CORE_MSG_COST, |
69 | 69 | .procname = "message_cost", |
70 | - .data = &net_msg_cost, | |
70 | + .data = &net_ratelimit_state.interval, | |
71 | 71 | .maxlen = sizeof(int), |
72 | 72 | .mode = 0644, |
73 | 73 | .proc_handler = &proc_dointvec_jiffies, |
... | ... | @@ -76,7 +76,7 @@ |
76 | 76 | { |
77 | 77 | .ctl_name = NET_CORE_MSG_BURST, |
78 | 78 | .procname = "message_burst", |
79 | - .data = &net_msg_burst, | |
79 | + .data = &net_ratelimit_state.burst, | |
80 | 80 | .maxlen = sizeof(int), |
81 | 81 | .mode = 0644, |
82 | 82 | .proc_handler = &proc_dointvec, |
net/core/utils.c
... | ... | @@ -31,17 +31,16 @@ |
31 | 31 | #include <asm/system.h> |
32 | 32 | #include <asm/uaccess.h> |
33 | 33 | |
34 | -int net_msg_cost __read_mostly = 5*HZ; | |
35 | -int net_msg_burst __read_mostly = 10; | |
36 | 34 | int net_msg_warn __read_mostly = 1; |
37 | 35 | EXPORT_SYMBOL(net_msg_warn); |
38 | 36 | |
37 | +DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10); | |
39 | 38 | /* |
40 | 39 | * All net warning printk()s should be guarded by this function. |
41 | 40 | */ |
42 | 41 | int net_ratelimit(void) |
43 | 42 | { |
44 | - return __printk_ratelimit(net_msg_cost, net_msg_burst); | |
43 | + return __ratelimit(&net_ratelimit_state); | |
45 | 44 | } |
46 | 45 | EXPORT_SYMBOL(net_ratelimit); |
47 | 46 |