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 Borntraegerint ___ratelimit(struct ratelimit_state *rs, const char *func) 285f97a5a8SDave Young { 29*6bae8cebSKuniyuki Iwashima /* Paired with WRITE_ONCE() in .proc_handler(). 30*6bae8cebSKuniyuki Iwashima * Changing two values seperately could be inconsistent 31*6bae8cebSKuniyuki Iwashima * and some message could be lost. (See: net_ratelimit_state). 32*6bae8cebSKuniyuki Iwashima */ 33*6bae8cebSKuniyuki Iwashima int interval = READ_ONCE(rs->interval); 34*6bae8cebSKuniyuki Iwashima int burst = READ_ONCE(rs->burst); 354d9c377cSAlexey Dobriyan unsigned long flags; 36979f693dSIngo Molnar int ret; 374d9c377cSAlexey Dobriyan 38*6bae8cebSKuniyuki 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 53*6bae8cebSKuniyuki 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 } 65*6bae8cebSKuniyuki 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