Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+99 -48
+5 -4
drivers/char/random.c
··· 727 727 static DECLARE_WORK(set_ready, crng_set_ready); 728 728 unsigned int new, orig, add; 729 729 unsigned long flags; 730 + int m; 730 731 731 732 if (!bits) 732 733 return; ··· 750 749 wake_up_interruptible(&crng_init_wait); 751 750 kill_fasync(&fasync, SIGIO, POLL_IN); 752 751 pr_notice("crng init done\n"); 753 - if (urandom_warning.missed) 754 - pr_notice("%d urandom warning(s) missed due to ratelimiting\n", 755 - urandom_warning.missed); 752 + m = ratelimit_state_get_miss(&urandom_warning); 753 + if (m) 754 + pr_notice("%d urandom warning(s) missed due to ratelimiting\n", m); 756 755 } else if (orig < POOL_EARLY_BITS && new >= POOL_EARLY_BITS) { 757 756 spin_lock_irqsave(&base_crng.lock, flags); 758 757 /* Check if crng_init is CRNG_EMPTY, to avoid race with crng_reseed(). */ ··· 1468 1467 1469 1468 if (!crng_ready()) { 1470 1469 if (!ratelimit_disable && maxwarn <= 0) 1471 - ++urandom_warning.missed; 1470 + ratelimit_state_inc_miss(&urandom_warning); 1472 1471 else if (ratelimit_disable || __ratelimit(&urandom_warning)) { 1473 1472 --maxwarn; 1474 1473 pr_notice("%s: uninitialized urandom read (%zu bytes read)\n",
+2 -9
drivers/gpu/drm/amd/pm/amdgpu_pm.c
··· 1606 1606 struct drm_device *ddev = dev_get_drvdata(dev); 1607 1607 struct amdgpu_device *adev = drm_to_adev(ddev); 1608 1608 long throttling_logging_interval; 1609 - unsigned long flags; 1610 1609 int ret = 0; 1611 1610 1612 1611 ret = kstrtol(buf, 0, &throttling_logging_interval); ··· 1616 1617 return -EINVAL; 1617 1618 1618 1619 if (throttling_logging_interval > 0) { 1619 - raw_spin_lock_irqsave(&adev->throttling_logging_rs.lock, flags); 1620 1620 /* 1621 1621 * Reset the ratelimit timer internals. 1622 1622 * This can effectively restart the timer. 1623 1623 */ 1624 - adev->throttling_logging_rs.interval = 1625 - (throttling_logging_interval - 1) * HZ; 1626 - adev->throttling_logging_rs.begin = 0; 1627 - adev->throttling_logging_rs.printed = 0; 1628 - adev->throttling_logging_rs.missed = 0; 1629 - raw_spin_unlock_irqrestore(&adev->throttling_logging_rs.lock, flags); 1630 - 1624 + ratelimit_state_reset_interval(&adev->throttling_logging_rs, 1625 + (throttling_logging_interval - 1) * HZ); 1631 1626 atomic_set(&adev->throttling_logging_enabled, 1); 1632 1627 } else { 1633 1628 atomic_set(&adev->throttling_logging_enabled, 0);
+4 -4
drivers/gpu/drm/i915/i915_perf.c
··· 1666 1666 struct i915_perf *perf = stream->perf; 1667 1667 struct intel_gt *gt = stream->engine->gt; 1668 1668 struct i915_perf_group *g = stream->engine->oa_group; 1669 + int m; 1669 1670 1670 1671 if (WARN_ON(stream != g->exclusive_stream)) 1671 1672 return; ··· 1691 1690 free_oa_configs(stream); 1692 1691 free_noa_wait(stream); 1693 1692 1694 - if (perf->spurious_report_rs.missed) { 1695 - gt_notice(gt, "%d spurious OA report notices suppressed due to ratelimiting\n", 1696 - perf->spurious_report_rs.missed); 1697 - } 1693 + m = ratelimit_state_get_miss(&perf->spurious_report_rs); 1694 + if (m) 1695 + gt_notice(gt, "%d spurious OA report notices suppressed due to ratelimiting\n", m); 1698 1696 } 1699 1697 1700 1698 static void gen7_init_oa_buffer(struct i915_perf_stream *stream)
+32 -5
include/linux/ratelimit.h
··· 22 22 DEFAULT_RATELIMIT_BURST); 23 23 } 24 24 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 + 25 52 static inline void ratelimit_state_exit(struct ratelimit_state *rs) 26 53 { 54 + int m; 55 + 27 56 if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) 28 57 return; 29 58 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); 35 62 } 36 63 37 64 static inline void
+3 -2
include/linux/ratelimit_types.h
··· 11 11 12 12 /* issue num suppressed message on exit */ 13 13 #define RATELIMIT_MSG_ON_RELEASE BIT(0) 14 + #define RATELIMIT_INITIALIZED BIT(1) 14 15 15 16 struct ratelimit_state { 16 17 raw_spinlock_t lock; /* protect the state */ 17 18 18 19 int interval; 19 20 int burst; 20 - int printed; 21 - int missed; 21 + atomic_t rs_n_left; 22 + atomic_t missed; 22 23 unsigned int flags; 23 24 unsigned long begin; 24 25 };
+53 -24
lib/ratelimit.c
··· 33 33 int interval = READ_ONCE(rs->interval); 34 34 int burst = READ_ONCE(rs->burst); 35 35 unsigned long flags; 36 - int ret; 37 - 38 - if (!interval) 39 - return 1; 36 + int ret = 0; 40 37 41 38 /* 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: 39 + * Zero interval says never limit, otherwise, non-positive burst 40 + * says always limit. 46 41 */ 47 - if (!raw_spin_trylock_irqsave(&rs->lock, flags)) 48 - return 0; 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; 49 48 50 - if (!rs->begin) 49 + /* Force re-initialization once re-enabled. */ 50 + rs->flags &= ~RATELIMIT_INITIALIZED; 51 + goto unlock_ret; 52 + } 53 + 54 + /* 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. 59 + */ 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 + } 66 + 67 + if (!(rs->flags & RATELIMIT_INITIALIZED)) { 51 68 rs->begin = jiffies; 69 + rs->flags |= RATELIMIT_INITIALIZED; 70 + atomic_set(&rs->rs_n_left, rs->burst); 71 + } 52 72 53 73 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) { 56 86 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); 60 88 } 61 89 } 62 - rs->begin = jiffies; 63 - rs->printed = 0; 64 90 } 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) 67 94 ret = 1; 68 - } else { 69 - rs->missed++; 70 - ret = 0; 71 - } 95 + 96 + unlock_ret: 72 97 raw_spin_unlock_irqrestore(&rs->lock, flags); 98 + 99 + nolock_ret: 100 + if (!ret) 101 + ratelimit_state_inc_miss(rs); 73 102 74 103 return ret; 75 104 }