xref: /linux/lib/ratelimit.c (revision 9a64e8e0ace51b309fdcff4b4754b3649250382a)
15f97a5a8SDave Young /*
25f97a5a8SDave Young  * ratelimit.c - Do something with rate limit.
35f97a5a8SDave Young  *
45f97a5a8SDave Young  * Isolated from kernel/printk.c by Dave Young <hidave.darkstar@gmail.com>
55f97a5a8SDave Young  *
6717115e1SDave Young  * 2008-05-01 rewrite the function and use a ratelimit_state data struct as
7717115e1SDave Young  * parameter. Now every user can use their own standalone ratelimit_state.
8717115e1SDave Young  *
95f97a5a8SDave Young  * This file is released under the GPLv2.
105f97a5a8SDave Young  */
115f97a5a8SDave Young 
123fff4c42SIngo Molnar #include <linux/ratelimit.h>
135f97a5a8SDave Young #include <linux/jiffies.h>
14*8bc3bcc9SPaul Gortmaker #include <linux/export.h>
155f97a5a8SDave Young 
165f97a5a8SDave Young /*
175f97a5a8SDave Young  * __ratelimit - rate limiting
18717115e1SDave Young  * @rs: ratelimit_state data
192a7268abSYong Zhang  * @func: name of calling function
205f97a5a8SDave Young  *
212a7268abSYong Zhang  * This enforces a rate limit: not more than @rs->burst callbacks
222a7268abSYong Zhang  * in every @rs->interval
232a7268abSYong Zhang  *
242a7268abSYong Zhang  * RETURNS:
252a7268abSYong Zhang  * 0 means callbacks will be suppressed.
262a7268abSYong Zhang  * 1 means go ahead and do it.
275f97a5a8SDave Young  */
285c828713SChristian Borntraeger int ___ratelimit(struct ratelimit_state *rs, const char *func)
295f97a5a8SDave Young {
304d9c377cSAlexey Dobriyan 	unsigned long flags;
31979f693dSIngo Molnar 	int ret;
324d9c377cSAlexey Dobriyan 
33717115e1SDave Young 	if (!rs->interval)
34717115e1SDave Young 		return 1;
355f97a5a8SDave Young 
36edaac8e3SIngo Molnar 	/*
37edaac8e3SIngo Molnar 	 * If we contend on this state's lock then almost
38edaac8e3SIngo Molnar 	 * by definition we are too busy to print a message,
39edaac8e3SIngo Molnar 	 * in addition to the one that will be printed by
40edaac8e3SIngo Molnar 	 * the entity that is holding the lock already:
41edaac8e3SIngo Molnar 	 */
4207354eb1SThomas Gleixner 	if (!raw_spin_trylock_irqsave(&rs->lock, flags))
4357119c34SYong Zhang 		return 0;
44edaac8e3SIngo Molnar 
45717115e1SDave Young 	if (!rs->begin)
46717115e1SDave Young 		rs->begin = jiffies;
475f97a5a8SDave Young 
48717115e1SDave Young 	if (time_is_before_jiffies(rs->begin + rs->interval)) {
49717115e1SDave Young 		if (rs->missed)
50717115e1SDave Young 			printk(KERN_WARNING "%s: %d callbacks suppressed\n",
515c828713SChristian Borntraeger 				func, rs->missed);
52717115e1SDave Young 		rs->begin   = 0;
53717115e1SDave Young 		rs->printed = 0;
54717115e1SDave Young 		rs->missed  = 0;
555f97a5a8SDave Young 	}
56979f693dSIngo Molnar 	if (rs->burst && rs->burst > rs->printed) {
57717115e1SDave Young 		rs->printed++;
58979f693dSIngo Molnar 		ret = 1;
59979f693dSIngo Molnar 	} else {
60979f693dSIngo Molnar 		rs->missed++;
61979f693dSIngo Molnar 		ret = 0;
62979f693dSIngo Molnar 	}
6307354eb1SThomas Gleixner 	raw_spin_unlock_irqrestore(&rs->lock, flags);
64979f693dSIngo Molnar 
65979f693dSIngo Molnar 	return ret;
665f97a5a8SDave Young }
675c828713SChristian Borntraeger EXPORT_SYMBOL(___ratelimit);
68