Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-only 2 : /* 3 : * ratelimit.c - Do something with rate limit. 4 : * 5 : * Isolated from kernel/printk.c by Dave Young <hidave.darkstar@gmail.com> 6 : * 7 : * 2008-05-01 rewrite the function and use a ratelimit_state data struct as 8 : * parameter. Now every user can use their own standalone ratelimit_state. 9 : */ 10 : 11 : #include <linux/ratelimit.h> 12 : #include <linux/jiffies.h> 13 : #include <linux/export.h> 14 : 15 : /* 16 : * __ratelimit - rate limiting 17 : * @rs: ratelimit_state data 18 : * @func: name of calling function 19 : * 20 : * This enforces a rate limit: not more than @rs->burst callbacks 21 : * in every @rs->interval 22 : * 23 : * RETURNS: 24 : * 0 means callbacks will be suppressed. 25 : * 1 means go ahead and do it. 26 : */ 27 0 : int ___ratelimit(struct ratelimit_state *rs, const char *func) 28 : { 29 : /* Paired with WRITE_ONCE() in .proc_handler(). 30 : * Changing two values seperately could be inconsistent 31 : * and some message could be lost. (See: net_ratelimit_state). 32 : */ 33 0 : int interval = READ_ONCE(rs->interval); 34 0 : int burst = READ_ONCE(rs->burst); 35 : unsigned long flags; 36 : int ret; 37 : 38 0 : if (!interval) 39 : return 1; 40 : 41 : /* 42 : * If we contend on this state's lock then almost 43 : * by definition we are too busy to print a message, 44 : * in addition to the one that will be printed by 45 : * the entity that is holding the lock already: 46 : */ 47 0 : if (!raw_spin_trylock_irqsave(&rs->lock, flags)) 48 : return 0; 49 : 50 0 : if (!rs->begin) 51 0 : rs->begin = jiffies; 52 : 53 0 : if (time_is_before_jiffies(rs->begin + interval)) { 54 0 : if (rs->missed) { 55 0 : if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) { 56 0 : printk_deferred(KERN_WARNING 57 : "%s: %d callbacks suppressed\n", 58 : func, rs->missed); 59 0 : rs->missed = 0; 60 : } 61 : } 62 0 : rs->begin = jiffies; 63 0 : rs->printed = 0; 64 : } 65 0 : if (burst && burst > rs->printed) { 66 0 : rs->printed++; 67 0 : ret = 1; 68 : } else { 69 0 : rs->missed++; 70 0 : ret = 0; 71 : } 72 0 : raw_spin_unlock_irqrestore(&rs->lock, flags); 73 : 74 0 : return ret; 75 : } 76 : EXPORT_SYMBOL(___ratelimit);