Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Dave Young and committed by
Linus Torvalds
717115e1 2711b793

+79 -56
+3
include/asm-generic/bug.h
··· 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
+2 -6
include/linux/kernel.h
··· 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 ··· 190 189 asmlinkage int printk(const char * fmt, ...) 191 190 __attribute__ ((format (printf, 1, 2))) __cold; 192 191 193 - extern int printk_ratelimit_jiffies; 194 - extern int printk_ratelimit_burst; 192 + extern struct ratelimit_state printk_ratelimit_state; 195 193 extern int printk_ratelimit(void); 196 - extern int __ratelimit(int ratelimit_jiffies, int ratelimit_burst); 197 - extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst); 198 194 extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, 199 195 unsigned int interval_msec); 200 196 #else ··· 202 204 __attribute__ ((format (printf, 1, 2))); 203 205 static inline int __cold printk(const char *s, ...) { return 0; } 204 206 static inline int printk_ratelimit(void) { return 0; } 205 - static inline int __printk_ratelimit(int ratelimit_jiffies, \ 206 - int ratelimit_burst) { return 0; } 207 207 static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, \ 208 208 unsigned int interval_msec) \ 209 209 { return false; }
+1 -2
include/linux/net.h
··· 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__ */
+27
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
+7 -2
include/linux/rcupreempt.h
··· 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 */
+3 -14
kernel/printk.c
··· 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 * ··· 1317 1315 * every printk_ratelimit_jiffies to make a denial-of-service 1318 1316 * attack impossible. 1319 1317 */ 1320 - int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst) 1321 - { 1322 - return __ratelimit(ratelimit_jiffies, ratelimit_burst); 1323 - } 1324 - EXPORT_SYMBOL(__printk_ratelimit); 1325 - 1326 - /* minimum time in jiffies between messages */ 1327 - int printk_ratelimit_jiffies = 5 * HZ; 1328 - 1329 - /* number of messages we send before ratelimiting */ 1330 - int printk_ratelimit_burst = 10; 1331 - 1332 1318 int printk_ratelimit(void) 1333 1319 { 1334 - return __printk_ratelimit(printk_ratelimit_jiffies, 1335 - printk_ratelimit_burst); 1320 + return __ratelimit(&printk_ratelimit_state); 1336 1321 } 1337 1322 EXPORT_SYMBOL(printk_ratelimit); 1338 1323
+2 -2
kernel/sysctl.c
··· 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 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,
+30 -25
lib/ratelimit.c
··· 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 */ ··· 14 11 #include <linux/jiffies.h> 15 12 #include <linux/module.h> 16 13 14 + static DEFINE_SPINLOCK(ratelimit_lock); 15 + static unsigned long flags; 16 + 17 17 /* 18 18 * __ratelimit - rate limiting 19 - * @ratelimit_jiffies: minimum time in jiffies between two callbacks 20 - * @ratelimit_burst: number of callbacks we do before ratelimiting 19 + * @rs: ratelimit_state data 21 20 * 22 - * This enforces a rate limit: not more than @ratelimit_burst callbacks 23 - * in every ratelimit_jiffies 21 + * This enforces a rate limit: not more than @rs->ratelimit_burst callbacks 22 + * in every @rs->ratelimit_jiffies 24 23 */ 25 - int __ratelimit(int ratelimit_jiffies, int ratelimit_burst) 24 + int __ratelimit(struct ratelimit_state *rs) 26 25 { 27 - static DEFINE_SPINLOCK(ratelimit_lock); 28 - static unsigned toks = 10 * 5 * HZ; 29 - static unsigned long last_msg; 30 - static int missed; 31 - unsigned long flags; 32 - unsigned long now = jiffies; 26 + if (!rs->interval) 27 + return 1; 33 28 34 29 spin_lock_irqsave(&ratelimit_lock, flags); 35 - toks += now - last_msg; 36 - last_msg = now; 37 - if (toks > (ratelimit_burst * ratelimit_jiffies)) 38 - toks = ratelimit_burst * ratelimit_jiffies; 39 - if (toks >= ratelimit_jiffies) { 40 - int lost = missed; 30 + if (!rs->begin) 31 + rs->begin = jiffies; 41 32 42 - missed = 0; 43 - toks -= ratelimit_jiffies; 44 - spin_unlock_irqrestore(&ratelimit_lock, flags); 45 - if (lost) 46 - printk(KERN_WARNING "%s: %d messages suppressed\n", 47 - __func__, lost); 48 - return 1; 33 + if (time_is_before_jiffies(rs->begin + rs->interval)) { 34 + if (rs->missed) 35 + printk(KERN_WARNING "%s: %d callbacks suppressed\n", 36 + __func__, rs->missed); 37 + rs->begin = 0; 38 + rs->printed = 0; 39 + rs->missed = 0; 49 40 } 50 - missed++; 41 + if (rs->burst && rs->burst > rs->printed) 42 + goto print; 43 + 44 + rs->missed++; 51 45 spin_unlock_irqrestore(&ratelimit_lock, flags); 52 46 return 0; 47 + 48 + print: 49 + rs->printed++; 50 + spin_unlock_irqrestore(&ratelimit_lock, flags); 51 + return 1; 53 52 } 54 53 EXPORT_SYMBOL(__ratelimit);
+2 -2
net/core/sysctl_net_core.c
··· 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 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,
+2 -3
net/core/utils.c
··· 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