Skip to content

Commit 97851c6

Browse files
committed
Merge tag 'ratelimit.2025.05.25a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu
Pull rate-limit updates from Paul McKenney: "lib/ratelimit: Reduce false-positive and silent misses: - Reduce open-coded use of ratelimit_state structure fields. - Convert the ->missed field to atomic_t. - Count misses that are due to lock contention. - Eliminate jiffies=0 special case. - Reduce ___ratelimit() false-positive rate limiting (Petr Mladek). - Allow zero ->burst to hard-disable rate limiting. - Optimize away atomic operations when a miss is guaranteed. - Warn if ->interval or ->burst are negative (Petr Mladek). - Simplify the resulting code. A smoke test and stress test have been created, but they are not yet ready for mainline. With luck, we will offer them for the v6.17 merge window" * tag 'ratelimit.2025.05.25a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: ratelimit: Drop redundant accesses to burst ratelimit: Use nolock_ret restructuring to collapse common case code ratelimit: Use nolock_ret label to collapse lock-failure code ratelimit: Use nolock_ret label to save a couple of lines of code ratelimit: Simplify common-case exit path ratelimit: Warn if ->interval or ->burst are negative ratelimit: Avoid atomic decrement under lock if already rate-limited ratelimit: Avoid atomic decrement if already rate-limited ratelimit: Don't flush misses counter if RATELIMIT_MSG_ON_RELEASE ratelimit: Force re-initialization when rate-limiting re-enabled ratelimit: Allow zero ->burst to disable ratelimiting ratelimit: Reduce ___ratelimit() false-positive rate limiting ratelimit: Avoid jiffies=0 special case ratelimit: Count misses due to lock contention ratelimit: Convert the ->missed field to atomic_t drm/amd/pm: Avoid open-coded use of ratelimit_state structure's internals drm/i915: Avoid open-coded use of ratelimit_state structure's ->missed field random: Avoid open-coded use of ratelimit_state structure's ->missed field ratelimit: Create functions to handle ratelimit_state internals
2 parents dd3922c + ba575ce commit 97851c6

File tree

6 files changed

+98
-47
lines changed

6 files changed

+98
-47
lines changed

drivers/char/random.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,7 @@ static void __cold _credit_init_bits(size_t bits)
727727
static DECLARE_WORK(set_ready, crng_set_ready);
728728
unsigned int new, orig, add;
729729
unsigned long flags;
730+
int m;
730731

731732
if (!bits)
732733
return;
@@ -749,9 +750,9 @@ static void __cold _credit_init_bits(size_t bits)
749750
wake_up_interruptible(&crng_init_wait);
750751
kill_fasync(&fasync, SIGIO, POLL_IN);
751752
pr_notice("crng init done\n");
752-
if (urandom_warning.missed)
753-
pr_notice("%d urandom warning(s) missed due to ratelimiting\n",
754-
urandom_warning.missed);
753+
m = ratelimit_state_get_miss(&urandom_warning);
754+
if (m)
755+
pr_notice("%d urandom warning(s) missed due to ratelimiting\n", m);
755756
} else if (orig < POOL_EARLY_BITS && new >= POOL_EARLY_BITS) {
756757
spin_lock_irqsave(&base_crng.lock, flags);
757758
/* Check if crng_init is CRNG_EMPTY, to avoid race with crng_reseed(). */
@@ -1467,7 +1468,7 @@ static ssize_t urandom_read_iter(struct kiocb *kiocb, struct iov_iter *iter)
14671468

14681469
if (!crng_ready()) {
14691470
if (!ratelimit_disable && maxwarn <= 0)
1470-
++urandom_warning.missed;
1471+
ratelimit_state_inc_miss(&urandom_warning);
14711472
else if (ratelimit_disable || __ratelimit(&urandom_warning)) {
14721473
--maxwarn;
14731474
pr_notice("%s: uninitialized urandom read (%zu bytes read)\n",

drivers/gpu/drm/amd/pm/amdgpu_pm.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,7 +1606,6 @@ static ssize_t amdgpu_set_thermal_throttling_logging(struct device *dev,
16061606
struct drm_device *ddev = dev_get_drvdata(dev);
16071607
struct amdgpu_device *adev = drm_to_adev(ddev);
16081608
long throttling_logging_interval;
1609-
unsigned long flags;
16101609
int ret = 0;
16111610

16121611
ret = kstrtol(buf, 0, &throttling_logging_interval);
@@ -1617,18 +1616,12 @@ static ssize_t amdgpu_set_thermal_throttling_logging(struct device *dev,
16171616
return -EINVAL;
16181617

16191618
if (throttling_logging_interval > 0) {
1620-
raw_spin_lock_irqsave(&adev->throttling_logging_rs.lock, flags);
16211619
/*
16221620
* Reset the ratelimit timer internals.
16231621
* This can effectively restart the timer.
16241622
*/
1625-
adev->throttling_logging_rs.interval =
1626-
(throttling_logging_interval - 1) * HZ;
1627-
adev->throttling_logging_rs.begin = 0;
1628-
adev->throttling_logging_rs.printed = 0;
1629-
adev->throttling_logging_rs.missed = 0;
1630-
raw_spin_unlock_irqrestore(&adev->throttling_logging_rs.lock, flags);
1631-
1623+
ratelimit_state_reset_interval(&adev->throttling_logging_rs,
1624+
(throttling_logging_interval - 1) * HZ);
16321625
atomic_set(&adev->throttling_logging_enabled, 1);
16331626
} else {
16341627
atomic_set(&adev->throttling_logging_enabled, 0);

drivers/gpu/drm/i915/i915_perf.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,7 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream)
16661666
struct i915_perf *perf = stream->perf;
16671667
struct intel_gt *gt = stream->engine->gt;
16681668
struct i915_perf_group *g = stream->engine->oa_group;
1669+
int m;
16691670

16701671
if (WARN_ON(stream != g->exclusive_stream))
16711672
return;
@@ -1690,10 +1691,9 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream)
16901691
free_oa_configs(stream);
16911692
free_noa_wait(stream);
16921693

1693-
if (perf->spurious_report_rs.missed) {
1694-
gt_notice(gt, "%d spurious OA report notices suppressed due to ratelimiting\n",
1695-
perf->spurious_report_rs.missed);
1696-
}
1694+
m = ratelimit_state_get_miss(&perf->spurious_report_rs);
1695+
if (m)
1696+
gt_notice(gt, "%d spurious OA report notices suppressed due to ratelimiting\n", m);
16971697
}
16981698

16991699
static void gen7_init_oa_buffer(struct i915_perf_stream *stream)

include/linux/ratelimit.h

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,43 @@ static inline void ratelimit_default_init(struct ratelimit_state *rs)
2222
DEFAULT_RATELIMIT_BURST);
2323
}
2424

25+
static inline void ratelimit_state_inc_miss(struct ratelimit_state *rs)
26+
{
27+
atomic_inc(&rs->missed);
28+
}
29+
30+
static inline int ratelimit_state_get_miss(struct ratelimit_state *rs)
31+
{
32+
return atomic_read(&rs->missed);
33+
}
34+
35+
static inline int ratelimit_state_reset_miss(struct ratelimit_state *rs)
36+
{
37+
return atomic_xchg_relaxed(&rs->missed, 0);
38+
}
39+
40+
static inline void ratelimit_state_reset_interval(struct ratelimit_state *rs, int interval_init)
41+
{
42+
unsigned long flags;
43+
44+
raw_spin_lock_irqsave(&rs->lock, flags);
45+
rs->interval = interval_init;
46+
rs->flags &= ~RATELIMIT_INITIALIZED;
47+
atomic_set(&rs->rs_n_left, rs->burst);
48+
ratelimit_state_reset_miss(rs);
49+
raw_spin_unlock_irqrestore(&rs->lock, flags);
50+
}
51+
2552
static inline void ratelimit_state_exit(struct ratelimit_state *rs)
2653
{
54+
int m;
55+
2756
if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE))
2857
return;
2958

30-
if (rs->missed) {
31-
pr_warn("%s: %d output lines suppressed due to ratelimiting\n",
32-
current->comm, rs->missed);
33-
rs->missed = 0;
34-
}
59+
m = ratelimit_state_reset_miss(rs);
60+
if (m)
61+
pr_warn("%s: %d output lines suppressed due to ratelimiting\n", current->comm, m);
3562
}
3663

3764
static inline void

include/linux/ratelimit_types.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111

1212
/* issue num suppressed message on exit */
1313
#define RATELIMIT_MSG_ON_RELEASE BIT(0)
14+
#define RATELIMIT_INITIALIZED BIT(1)
1415

1516
struct ratelimit_state {
1617
raw_spinlock_t lock; /* protect the state */
1718

1819
int interval;
1920
int burst;
20-
int printed;
21-
int missed;
21+
atomic_t rs_n_left;
22+
atomic_t missed;
2223
unsigned int flags;
2324
unsigned long begin;
2425
};

lib/ratelimit.c

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,44 +33,73 @@ int ___ratelimit(struct ratelimit_state *rs, const char *func)
3333
int interval = READ_ONCE(rs->interval);
3434
int burst = READ_ONCE(rs->burst);
3535
unsigned long flags;
36-
int ret;
36+
int ret = 0;
3737

38-
if (!interval)
39-
return 1;
38+
/*
39+
* Zero interval says never limit, otherwise, non-positive burst
40+
* says always limit.
41+
*/
42+
if (interval <= 0 || burst <= 0) {
43+
WARN_ONCE(interval < 0 || burst < 0, "Negative interval (%d) or burst (%d): Uninitialized ratelimit_state structure?\n", interval, burst);
44+
ret = interval == 0 || burst > 0;
45+
if (!(READ_ONCE(rs->flags) & RATELIMIT_INITIALIZED) || (!interval && !burst) ||
46+
!raw_spin_trylock_irqsave(&rs->lock, flags))
47+
goto nolock_ret;
48+
49+
/* Force re-initialization once re-enabled. */
50+
rs->flags &= ~RATELIMIT_INITIALIZED;
51+
goto unlock_ret;
52+
}
4053

4154
/*
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:
55+
* If we contend on this state's lock then just check if
56+
* the current burst is used or not. It might cause
57+
* false positive when we are past the interval and
58+
* the current lock owner is just about to reset it.
4659
*/
47-
if (!raw_spin_trylock_irqsave(&rs->lock, flags))
48-
return 0;
60+
if (!raw_spin_trylock_irqsave(&rs->lock, flags)) {
61+
if (READ_ONCE(rs->flags) & RATELIMIT_INITIALIZED &&
62+
atomic_read(&rs->rs_n_left) > 0 && atomic_dec_return(&rs->rs_n_left) >= 0)
63+
ret = 1;
64+
goto nolock_ret;
65+
}
4966

50-
if (!rs->begin)
67+
if (!(rs->flags & RATELIMIT_INITIALIZED)) {
5168
rs->begin = jiffies;
69+
rs->flags |= RATELIMIT_INITIALIZED;
70+
atomic_set(&rs->rs_n_left, rs->burst);
71+
}
5272

5373
if (time_is_before_jiffies(rs->begin + interval)) {
54-
if (rs->missed) {
55-
if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) {
74+
int m;
75+
76+
/*
77+
* Reset rs_n_left ASAP to reduce false positives
78+
* in parallel calls, see above.
79+
*/
80+
atomic_set(&rs->rs_n_left, rs->burst);
81+
rs->begin = jiffies;
82+
83+
if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) {
84+
m = ratelimit_state_reset_miss(rs);
85+
if (m) {
5686
printk_deferred(KERN_WARNING
57-
"%s: %d callbacks suppressed\n",
58-
func, rs->missed);
59-
rs->missed = 0;
87+
"%s: %d callbacks suppressed\n", func, m);
6088
}
6189
}
62-
rs->begin = jiffies;
63-
rs->printed = 0;
6490
}
65-
if (burst && burst > rs->printed) {
66-
rs->printed++;
91+
92+
/* Note that the burst might be taken by a parallel call. */
93+
if (atomic_read(&rs->rs_n_left) > 0 && atomic_dec_return(&rs->rs_n_left) >= 0)
6794
ret = 1;
68-
} else {
69-
rs->missed++;
70-
ret = 0;
71-
}
95+
96+
unlock_ret:
7297
raw_spin_unlock_irqrestore(&rs->lock, flags);
7398

99+
nolock_ret:
100+
if (!ret)
101+
ratelimit_state_inc_miss(rs);
102+
74103
return ret;
75104
}
76105
EXPORT_SYMBOL(___ratelimit);

0 commit comments

Comments
 (0)