aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Young <hidave.darkstar@gmail.com>2008-07-25 04:45:58 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-25 13:53:29 -0400
commit717115e1a5856b57af0f71e1df7149108294fc10 (patch)
tree9528a992245c2fb993a0cf0bc8221dc7dea5d259
parent2711b793eb62a5873a0ba583a69252040aef176e (diff)
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>
-rw-r--r--include/asm-generic/bug.h3
-rw-r--r--include/linux/kernel.h8
-rw-r--r--include/linux/net.h3
-rw-r--r--include/linux/ratelimit.h27
-rw-r--r--include/linux/rcupreempt.h9
-rw-r--r--kernel/printk.c17
-rw-r--r--kernel/sysctl.c4
-rw-r--r--lib/ratelimit.c55
-rw-r--r--net/core/sysctl_net_core.c4
-rw-r--r--net/core/utils.c5
10 files changed, 79 insertions, 56 deletions
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index a346e744e770..a3f738cffdb6 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -97,6 +97,9 @@ extern void warn_slowpath(const char *file, const int line,
97 unlikely(__ret_warn_once); \ 97 unlikely(__ret_warn_once); \
98}) 98})
99 99
100#define WARN_ON_RATELIMIT(condition, state) \
101 WARN_ON((condition) && __ratelimit(state))
102
100#ifdef CONFIG_SMP 103#ifdef CONFIG_SMP
101# define WARN_ON_SMP(x) WARN_ON(x) 104# define WARN_ON_SMP(x) WARN_ON(x)
102#else 105#else
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 5c4b1251e110..fdbbf72ca2eb 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -15,6 +15,7 @@
15#include <linux/bitops.h> 15#include <linux/bitops.h>
16#include <linux/log2.h> 16#include <linux/log2.h>
17#include <linux/typecheck.h> 17#include <linux/typecheck.h>
18#include <linux/ratelimit.h>
18#include <asm/byteorder.h> 19#include <asm/byteorder.h>
19#include <asm/bug.h> 20#include <asm/bug.h>
20 21
@@ -189,11 +190,8 @@ asmlinkage int vprintk(const char *fmt, va_list args)
189asmlinkage int printk(const char * fmt, ...) 190asmlinkage int printk(const char * fmt, ...)
190 __attribute__ ((format (printf, 1, 2))) __cold; 191 __attribute__ ((format (printf, 1, 2))) __cold;
191 192
192extern int printk_ratelimit_jiffies; 193extern struct ratelimit_state printk_ratelimit_state;
193extern int printk_ratelimit_burst;
194extern int printk_ratelimit(void); 194extern int printk_ratelimit(void);
195extern int __ratelimit(int ratelimit_jiffies, int ratelimit_burst);
196extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst);
197extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, 195extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
198 unsigned int interval_msec); 196 unsigned int interval_msec);
199#else 197#else
@@ -204,8 +202,6 @@ static inline int printk(const char *s, ...)
204 __attribute__ ((format (printf, 1, 2))); 202 __attribute__ ((format (printf, 1, 2)));
205static inline int __cold printk(const char *s, ...) { return 0; } 203static inline int __cold printk(const char *s, ...) { return 0; }
206static inline int printk_ratelimit(void) { return 0; } 204static inline int printk_ratelimit(void) { return 0; }
207static inline int __printk_ratelimit(int ratelimit_jiffies, \
208 int ratelimit_burst) { return 0; }
209static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \ 205static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \
210 unsigned int interval_msec) \ 206 unsigned int interval_msec) \
211 { return false; } 207 { return false; }
diff --git a/include/linux/net.h b/include/linux/net.h
index 2f999fbb188d..4a9a30f2d68f 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -351,8 +351,7 @@ static const struct proto_ops name##_ops = { \
351 351
352#ifdef CONFIG_SYSCTL 352#ifdef CONFIG_SYSCTL
353#include <linux/sysctl.h> 353#include <linux/sysctl.h>
354extern int net_msg_cost; 354extern struct ratelimit_state net_ratelimit_state;
355extern int net_msg_burst;
356#endif 355#endif
357 356
358#endif /* __KERNEL__ */ 357#endif /* __KERNEL__ */
diff --git a/include/linux/ratelimit.h b/include/linux/ratelimit.h
new file mode 100644
index 000000000000..18a5b9ba9d40
--- /dev/null
+++ b/include/linux/ratelimit.h
@@ -0,0 +1,27 @@
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
8struct 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
19extern int __ratelimit(struct ratelimit_state *rs);
20
21static 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
diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h
index f04b64eca636..0967f03b0705 100644
--- a/include/linux/rcupreempt.h
+++ b/include/linux/rcupreempt.h
@@ -115,16 +115,21 @@ DECLARE_PER_CPU(struct rcu_dyntick_sched, rcu_dyntick_sched);
115 115
116static inline void rcu_enter_nohz(void) 116static inline void rcu_enter_nohz(void)
117{ 117{
118 static DEFINE_RATELIMIT_STATE(rs, 10 * HZ, 1);
119
118 smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ 120 smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */
119 __get_cpu_var(rcu_dyntick_sched).dynticks++; 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
123static inline void rcu_exit_nohz(void) 125static inline void rcu_exit_nohz(void)
124{ 126{
127 static DEFINE_RATELIMIT_STATE(rs, 10 * HZ, 1);
128
125 smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ 129 smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */
126 __get_cpu_var(rcu_dyntick_sched).dynticks++; 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#else /* CONFIG_NO_HZ */ 135#else /* CONFIG_NO_HZ */
diff --git a/kernel/printk.c b/kernel/printk.c
index 3f7a2a94583b..a7f7559c5f6c 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1308,6 +1308,8 @@ void tty_write_message(struct tty_struct *tty, char *msg)
1308} 1308}
1309 1309
1310#if defined CONFIG_PRINTK 1310#if defined CONFIG_PRINTK
1311
1312DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10);
1311/* 1313/*
1312 * printk rate limiting, lifted from the networking subsystem. 1314 * printk rate limiting, lifted from the networking subsystem.
1313 * 1315 *
@@ -1315,22 +1317,9 @@ void tty_write_message(struct tty_struct *tty, char *msg)
1315 * every printk_ratelimit_jiffies to make a denial-of-service 1317 * every printk_ratelimit_jiffies to make a denial-of-service
1316 * attack impossible. 1318 * attack impossible.
1317 */ 1319 */
1318int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
1319{
1320 return __ratelimit(ratelimit_jiffies, ratelimit_burst);
1321}
1322EXPORT_SYMBOL(__printk_ratelimit);
1323
1324/* minimum time in jiffies between messages */
1325int printk_ratelimit_jiffies = 5 * HZ;
1326
1327/* number of messages we send before ratelimiting */
1328int printk_ratelimit_burst = 10;
1329
1330int printk_ratelimit(void) 1320int printk_ratelimit(void)
1331{ 1321{
1332 return __printk_ratelimit(printk_ratelimit_jiffies, 1322 return __ratelimit(&printk_ratelimit_state);
1333 printk_ratelimit_burst);
1334} 1323}
1335EXPORT_SYMBOL(printk_ratelimit); 1324EXPORT_SYMBOL(printk_ratelimit);
1336 1325
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 1a8299d1fe59..35a50db9b6ce 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -624,7 +624,7 @@ static struct ctl_table kern_table[] = {
624 { 624 {
625 .ctl_name = KERN_PRINTK_RATELIMIT, 625 .ctl_name = KERN_PRINTK_RATELIMIT,
626 .procname = "printk_ratelimit", 626 .procname = "printk_ratelimit",
627 .data = &printk_ratelimit_jiffies, 627 .data = &printk_ratelimit_state.interval,
628 .maxlen = sizeof(int), 628 .maxlen = sizeof(int),
629 .mode = 0644, 629 .mode = 0644,
630 .proc_handler = &proc_dointvec_jiffies, 630 .proc_handler = &proc_dointvec_jiffies,
@@ -633,7 +633,7 @@ static struct ctl_table kern_table[] = {
633 { 633 {
634 .ctl_name = KERN_PRINTK_RATELIMIT_BURST, 634 .ctl_name = KERN_PRINTK_RATELIMIT_BURST,
635 .procname = "printk_ratelimit_burst", 635 .procname = "printk_ratelimit_burst",
636 .data = &printk_ratelimit_burst, 636 .data = &printk_ratelimit_state.burst,
637 .maxlen = sizeof(int), 637 .maxlen = sizeof(int),
638 .mode = 0644, 638 .mode = 0644,
639 .proc_handler = &proc_dointvec, 639 .proc_handler = &proc_dointvec,
diff --git a/lib/ratelimit.c b/lib/ratelimit.c
index 485e3040dcd4..35136671b215 100644
--- a/lib/ratelimit.c
+++ b/lib/ratelimit.c
@@ -3,6 +3,9 @@
3 * 3 *
4 * Isolated from kernel/printk.c by Dave Young <hidave.darkstar@gmail.com> 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 * This file is released under the GPLv2. 9 * This file is released under the GPLv2.
7 * 10 *
8 */ 11 */
@@ -11,41 +14,43 @@
11#include <linux/jiffies.h> 14#include <linux/jiffies.h>
12#include <linux/module.h> 15#include <linux/module.h>
13 16
17static DEFINE_SPINLOCK(ratelimit_lock);
18static unsigned long flags;
19
14/* 20/*
15 * __ratelimit - rate limiting 21 * __ratelimit - rate limiting
16 * @ratelimit_jiffies: minimum time in jiffies between two callbacks 22 * @rs: ratelimit_state data
17 * @ratelimit_burst: number of callbacks we do before ratelimiting
18 * 23 *
19 * This enforces a rate limit: not more than @ratelimit_burst callbacks 24 * This enforces a rate limit: not more than @rs->ratelimit_burst callbacks
20 * in every ratelimit_jiffies 25 * in every @rs->ratelimit_jiffies
21 */ 26 */
22int __ratelimit(int ratelimit_jiffies, int ratelimit_burst) 27int __ratelimit(struct ratelimit_state *rs)
23{ 28{
24 static DEFINE_SPINLOCK(ratelimit_lock); 29 if (!rs->interval)
25 static unsigned toks = 10 * 5 * HZ; 30 return 1;
26 static unsigned long last_msg;
27 static int missed;
28 unsigned long flags;
29 unsigned long now = jiffies;
30 31
31 spin_lock_irqsave(&ratelimit_lock, flags); 32 spin_lock_irqsave(&ratelimit_lock, flags);
32 toks += now - last_msg; 33 if (!rs->begin)
33 last_msg = now; 34 rs->begin = jiffies;
34 if (toks > (ratelimit_burst * ratelimit_jiffies))
35 toks = ratelimit_burst * ratelimit_jiffies;
36 if (toks >= ratelimit_jiffies) {
37 int lost = missed;
38 35
39 missed = 0; 36 if (time_is_before_jiffies(rs->begin + rs->interval)) {
40 toks -= ratelimit_jiffies; 37 if (rs->missed)
41 spin_unlock_irqrestore(&ratelimit_lock, flags); 38 printk(KERN_WARNING "%s: %d callbacks suppressed\n",
42 if (lost) 39 __func__, rs->missed);
43 printk(KERN_WARNING "%s: %d messages suppressed\n", 40 rs->begin = 0;
44 __func__, lost); 41 rs->printed = 0;
45 return 1; 42 rs->missed = 0;
46 } 43 }
47 missed++; 44 if (rs->burst && rs->burst > rs->printed)
45 goto print;
46
47 rs->missed++;
48 spin_unlock_irqrestore(&ratelimit_lock, flags); 48 spin_unlock_irqrestore(&ratelimit_lock, flags);
49 return 0; 49 return 0;
50
51print:
52 rs->printed++;
53 spin_unlock_irqrestore(&ratelimit_lock, flags);
54 return 1;
50} 55}
51EXPORT_SYMBOL(__ratelimit); 56EXPORT_SYMBOL(__ratelimit);
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index a570e2af22cb..f686467ff12b 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -67,7 +67,7 @@ static struct ctl_table net_core_table[] = {
67 { 67 {
68 .ctl_name = NET_CORE_MSG_COST, 68 .ctl_name = NET_CORE_MSG_COST,
69 .procname = "message_cost", 69 .procname = "message_cost",
70 .data = &net_msg_cost, 70 .data = &net_ratelimit_state.interval,
71 .maxlen = sizeof(int), 71 .maxlen = sizeof(int),
72 .mode = 0644, 72 .mode = 0644,
73 .proc_handler = &proc_dointvec_jiffies, 73 .proc_handler = &proc_dointvec_jiffies,
@@ -76,7 +76,7 @@ static struct ctl_table net_core_table[] = {
76 { 76 {
77 .ctl_name = NET_CORE_MSG_BURST, 77 .ctl_name = NET_CORE_MSG_BURST,
78 .procname = "message_burst", 78 .procname = "message_burst",
79 .data = &net_msg_burst, 79 .data = &net_ratelimit_state.burst,
80 .maxlen = sizeof(int), 80 .maxlen = sizeof(int),
81 .mode = 0644, 81 .mode = 0644,
82 .proc_handler = &proc_dointvec, 82 .proc_handler = &proc_dointvec,
diff --git a/net/core/utils.c b/net/core/utils.c
index 8031eb59054e..72e0ebe964a0 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -31,17 +31,16 @@
31#include <asm/system.h> 31#include <asm/system.h>
32#include <asm/uaccess.h> 32#include <asm/uaccess.h>
33 33
34int net_msg_cost __read_mostly = 5*HZ;
35int net_msg_burst __read_mostly = 10;
36int net_msg_warn __read_mostly = 1; 34int net_msg_warn __read_mostly = 1;
37EXPORT_SYMBOL(net_msg_warn); 35EXPORT_SYMBOL(net_msg_warn);
38 36
37DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10);
39/* 38/*
40 * All net warning printk()s should be guarded by this function. 39 * All net warning printk()s should be guarded by this function.
41 */ 40 */
42int net_ratelimit(void) 41int net_ratelimit(void)
43{ 42{
44 return __printk_ratelimit(net_msg_cost, net_msg_burst); 43 return __ratelimit(&net_ratelimit_state);
45} 44}
46EXPORT_SYMBOL(net_ratelimit); 45EXPORT_SYMBOL(net_ratelimit);
47 46