Commit 717115e1a5856b57af0f71e1df7149108294fc10

Authored by Dave Young
Committed by Linus Torvalds
1 parent 2711b793eb

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
... ... @@ -97,6 +97,9 @@
97 97 unlikely(__ret_warn_once); \
98 98 })
99 99  
  100 +#define WARN_ON_RATELIMIT(condition, state) \
  101 + WARN_ON((condition) && __ratelimit(state))
  102 +
100 103 #ifdef CONFIG_SMP
101 104 # define WARN_ON_SMP(x) WARN_ON(x)
102 105 #else
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; }
... ... @@ -351,8 +351,7 @@
351 351  
352 352 #ifdef CONFIG_SYSCTL
353 353 #include <linux/sysctl.h>
354   -extern int net_msg_cost;
355   -extern int net_msg_burst;
  354 +extern struct ratelimit_state net_ratelimit_state;
356 355 #endif
357 356  
358 357 #endif /* __KERNEL__ */
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 */
... ... @@ -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  
... ... @@ -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,
... ... @@ -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,
... ... @@ -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