diff options
Diffstat (limited to 'lib/ratelimit.c')
| -rw-r--r-- | lib/ratelimit.c | 55 |
1 files changed, 30 insertions, 25 deletions
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 | ||
| 17 | static DEFINE_SPINLOCK(ratelimit_lock); | ||
| 18 | static 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 | */ |
| 22 | int __ratelimit(int ratelimit_jiffies, int ratelimit_burst) | 27 | int __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 | |||
| 51 | print: | ||
| 52 | rs->printed++; | ||
| 53 | spin_unlock_irqrestore(&ratelimit_lock, flags); | ||
| 54 | return 1; | ||
| 50 | } | 55 | } |
| 51 | EXPORT_SYMBOL(__ratelimit); | 56 | EXPORT_SYMBOL(__ratelimit); |
