162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * ratelimit.c - Do something with rate limit.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Isolated from kernel/printk.c by Dave Young <hidave.darkstar@gmail.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * 2008-05-01 rewrite the function and use a ratelimit_state data struct as
862306a36Sopenharmony_ci * parameter. Now every user can use their own standalone ratelimit_state.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/ratelimit.h>
1262306a36Sopenharmony_ci#include <linux/jiffies.h>
1362306a36Sopenharmony_ci#include <linux/export.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * __ratelimit - rate limiting
1762306a36Sopenharmony_ci * @rs: ratelimit_state data
1862306a36Sopenharmony_ci * @func: name of calling function
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * This enforces a rate limit: not more than @rs->burst callbacks
2162306a36Sopenharmony_ci * in every @rs->interval
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * RETURNS:
2462306a36Sopenharmony_ci * 0 means callbacks will be suppressed.
2562306a36Sopenharmony_ci * 1 means go ahead and do it.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ciint ___ratelimit(struct ratelimit_state *rs, const char *func)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	/* Paired with WRITE_ONCE() in .proc_handler().
3062306a36Sopenharmony_ci	 * Changing two values seperately could be inconsistent
3162306a36Sopenharmony_ci	 * and some message could be lost.  (See: net_ratelimit_state).
3262306a36Sopenharmony_ci	 */
3362306a36Sopenharmony_ci	int interval = READ_ONCE(rs->interval);
3462306a36Sopenharmony_ci	int burst = READ_ONCE(rs->burst);
3562306a36Sopenharmony_ci	unsigned long flags;
3662306a36Sopenharmony_ci	int ret;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (!interval)
3962306a36Sopenharmony_ci		return 1;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/*
4262306a36Sopenharmony_ci	 * If we contend on this state's lock then almost
4362306a36Sopenharmony_ci	 * by definition we are too busy to print a message,
4462306a36Sopenharmony_ci	 * in addition to the one that will be printed by
4562306a36Sopenharmony_ci	 * the entity that is holding the lock already:
4662306a36Sopenharmony_ci	 */
4762306a36Sopenharmony_ci	if (!raw_spin_trylock_irqsave(&rs->lock, flags))
4862306a36Sopenharmony_ci		return 0;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (!rs->begin)
5162306a36Sopenharmony_ci		rs->begin = jiffies;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (time_is_before_jiffies(rs->begin + interval)) {
5462306a36Sopenharmony_ci		if (rs->missed) {
5562306a36Sopenharmony_ci			if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) {
5662306a36Sopenharmony_ci				printk_deferred(KERN_WARNING
5762306a36Sopenharmony_ci						"%s: %d callbacks suppressed\n",
5862306a36Sopenharmony_ci						func, rs->missed);
5962306a36Sopenharmony_ci				rs->missed = 0;
6062306a36Sopenharmony_ci			}
6162306a36Sopenharmony_ci		}
6262306a36Sopenharmony_ci		rs->begin   = jiffies;
6362306a36Sopenharmony_ci		rs->printed = 0;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	if (burst && burst > rs->printed) {
6662306a36Sopenharmony_ci		rs->printed++;
6762306a36Sopenharmony_ci		ret = 1;
6862306a36Sopenharmony_ci	} else {
6962306a36Sopenharmony_ci		rs->missed++;
7062306a36Sopenharmony_ci		ret = 0;
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&rs->lock, flags);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	return ret;
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ciEXPORT_SYMBOL(___ratelimit);
77