xref: /openbmc/linux/lib/ratelimit.c (revision 0db9ce82)
155716d26SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25f97a5a8SDave Young /*
35f97a5a8SDave Young  * ratelimit.c - Do something with rate limit.
45f97a5a8SDave Young  *
55f97a5a8SDave Young  * Isolated from kernel/printk.c by Dave Young <hidave.darkstar@gmail.com>
65f97a5a8SDave Young  *
7717115e1SDave Young  * 2008-05-01 rewrite the function and use a ratelimit_state data struct as
8717115e1SDave Young  * parameter. Now every user can use their own standalone ratelimit_state.
95f97a5a8SDave Young  */
105f97a5a8SDave Young 
113fff4c42SIngo Molnar #include <linux/ratelimit.h>
125f97a5a8SDave Young #include <linux/jiffies.h>
138bc3bcc9SPaul Gortmaker #include <linux/export.h>
145f97a5a8SDave Young 
155f97a5a8SDave Young /*
165f97a5a8SDave Young  * __ratelimit - rate limiting
17717115e1SDave Young  * @rs: ratelimit_state data
182a7268abSYong Zhang  * @func: name of calling function
195f97a5a8SDave Young  *
202a7268abSYong Zhang  * This enforces a rate limit: not more than @rs->burst callbacks
212a7268abSYong Zhang  * in every @rs->interval
222a7268abSYong Zhang  *
232a7268abSYong Zhang  * RETURNS:
242a7268abSYong Zhang  * 0 means callbacks will be suppressed.
252a7268abSYong Zhang  * 1 means go ahead and do it.
265f97a5a8SDave Young  */
___ratelimit(struct ratelimit_state * rs,const char * func)275c828713SChristian Borntraeger int ___ratelimit(struct ratelimit_state *rs, const char *func)
285f97a5a8SDave Young {
290db9ce82SKuniyuki Iwashima 	/* Paired with WRITE_ONCE() in .proc_handler().
300db9ce82SKuniyuki Iwashima 	 * Changing two values seperately could be inconsistent
310db9ce82SKuniyuki Iwashima 	 * and some message could be lost.  (See: net_ratelimit_state).
320db9ce82SKuniyuki Iwashima 	 */
330db9ce82SKuniyuki Iwashima 	int interval = READ_ONCE(rs->interval);
340db9ce82SKuniyuki Iwashima 	int burst = READ_ONCE(rs->burst);
354d9c377cSAlexey Dobriyan 	unsigned long flags;
36979f693dSIngo Molnar 	int ret;
374d9c377cSAlexey Dobriyan 
380db9ce82SKuniyuki Iwashima 	if (!interval)
39717115e1SDave Young 		return 1;
405f97a5a8SDave Young 
41edaac8e3SIngo Molnar 	/*
42edaac8e3SIngo Molnar 	 * If we contend on this state's lock then almost
43edaac8e3SIngo Molnar 	 * by definition we are too busy to print a message,
44edaac8e3SIngo Molnar 	 * in addition to the one that will be printed by
45edaac8e3SIngo Molnar 	 * the entity that is holding the lock already:
46edaac8e3SIngo Molnar 	 */
4707354eb1SThomas Gleixner 	if (!raw_spin_trylock_irqsave(&rs->lock, flags))
4857119c34SYong Zhang 		return 0;
49edaac8e3SIngo Molnar 
50717115e1SDave Young 	if (!rs->begin)
51717115e1SDave Young 		rs->begin = jiffies;
525f97a5a8SDave Young 
530db9ce82SKuniyuki Iwashima 	if (time_is_before_jiffies(rs->begin + interval)) {
546b1d174bSBorislav Petkov 		if (rs->missed) {
556b1d174bSBorislav Petkov 			if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) {
56656d61ceSSergey Senozhatsky 				printk_deferred(KERN_WARNING
57656d61ceSSergey Senozhatsky 						"%s: %d callbacks suppressed\n",
58656d61ceSSergey Senozhatsky 						func, rs->missed);
596b1d174bSBorislav Petkov 				rs->missed = 0;
606b1d174bSBorislav Petkov 			}
616b1d174bSBorislav Petkov 		}
62c2594bc3SJaewon Kim 		rs->begin   = jiffies;
63717115e1SDave Young 		rs->printed = 0;
645f97a5a8SDave Young 	}
650db9ce82SKuniyuki Iwashima 	if (burst && burst > rs->printed) {
66717115e1SDave Young 		rs->printed++;
67979f693dSIngo Molnar 		ret = 1;
68979f693dSIngo Molnar 	} else {
69979f693dSIngo Molnar 		rs->missed++;
70979f693dSIngo Molnar 		ret = 0;
71979f693dSIngo Molnar 	}
7207354eb1SThomas Gleixner 	raw_spin_unlock_irqrestore(&rs->lock, flags);
73979f693dSIngo Molnar 
74979f693dSIngo Molnar 	return ret;
755f97a5a8SDave Young }
765c828713SChristian Borntraeger EXPORT_SYMBOL(___ratelimit);
77