Re: [PATCH v3 3/5] rust: add pr_*_ratelimit! macros for printing
From: Gary Guo
Date: Wed Jul 22 2026 - 14:16:18 EST
On Wed Jul 22, 2026 at 11:12 AM BST, Alice Ryhl wrote:
> Printing can be very expensive if it occurs often, so printing that can
> be triggered by userspace should be rate limited. For this purpose, add
> a Rust wrapper around `struct ratelimit_state` and use it in the new
> macros.
>
> Tested-by: Alvin Sun <alvin.sun@xxxxxxxxx>
> Reviewed-by: Carlos Llamas <cmllamas@xxxxxxxxxx>
> Link: https://github.com/Rust-for-Linux/linux/issues/122
> Signed-off-by: Alice Ryhl <aliceryhl@xxxxxxxxxx>
> ---
> rust/helpers/helpers.c | 1 +
> rust/helpers/ratelimit.c | 14 +++
> rust/kernel/lib.rs | 1 +
> rust/kernel/prelude.rs | 8 ++
> rust/kernel/ratelimit.rs | 215 ++++++++++++++++++++++++++++++++++++++
> rust/kernel/sync/lock/spinlock.rs | 1 -
> 6 files changed, 239 insertions(+), 1 deletion(-)
>
> diff --git a/rust/kernel/ratelimit.rs b/rust/kernel/ratelimit.rs
> new file mode 100644
> index 000000000000..426992e452a2
> --- /dev/null
> +++ b/rust/kernel/ratelimit.rs
> @@ -0,0 +1,215 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Rate limiting support.
> +//!
> +//! C header: [`include/linux/ratelimit.h`](srctree/include/linux/ratelimit.h)
> +
> +use crate::{
> + bindings,
> + prelude::*,
> + types::Opaque, //
> +};
> +
> +/// Defines a `static` containing a [`Ratelimit`].
> +#[macro_export]
> +macro_rules! ratelimit_state_init {
> + ($name:ident, $interval:expr, $burst:expr $(,)?) => {
> + static $name: $crate::ratelimit::Ratelimit = {
> + let name = $crate::c_str!(::core::stringify!($name));
> + let interval = $interval;
> + let burst = $burst;
> + // SAFETY: This will be stored in static memory.
> + unsafe { $crate::ratelimit::Ratelimit::new_static(name, interval, burst) }
> + };
> + };
> +}
> +pub use ratelimit_state_init;
> +
> +/// Rate limiter state.
> +///
> +/// # Invariants
> +///
> +/// The `inner` field contains an initialized `struct ratelimit_state`.
> +#[pin_data(PinnedDrop)]
> +#[repr(transparent)]
> +pub struct Ratelimit {
> + #[pin]
> + inner: Opaque<bindings::ratelimit_state>,
> +}
> +
> +// SAFETY: `Ratelimit` is safe to be sent to any task.
> +unsafe impl Send for Ratelimit {}
> +
> +// SAFETY: `Ratelimit` is safe to be accessed concurrently as it is protected by an internal
> +// spinlock.
> +unsafe impl Sync for Ratelimit {}
> +
> +impl Ratelimit {
> + /// Constructs a [`Ratelimit`] with the specified configuration.
> + ///
> + /// If `interval` is zero, then no rate limit is applied.
> + #[inline]
> + pub fn new(interval: i32, burst: i32) -> impl PinInit<Self> {
> + // INVARIANT: This creates a `Ratelimit` containing an initialized `struct ratelimit_state`
> + pin_init!(Self {
> + inner <- Opaque::ffi_init(|slot: *mut bindings::ratelimit_state| {
> + // SAFETY: `slot` is a valid pointer to an uninitialized `struct ratelimit_state`.
> + // The memory is pinned so it remains valid until `ratelimit_state_exit` is called.
> + unsafe { bindings::ratelimit_state_init(slot, interval, burst) };
> + }),
> + })
> + }
> +
> + /// Constructs a [`Ratelimit`] with the default configuration.
> + #[inline]
> + pub fn new_default() -> impl PinInit<Self> {
> + Ratelimit::new(Ratelimit::DEFAULT_INTERVAL, Ratelimit::DEFAULT_BURST)
> + }
> +
> + /// Constructs a [`Ratelimit`] with the specified configuration.
> + ///
> + /// The name will be used for the lockdep name of the internal spinlock. See [`Self::new`] for
> + /// the meaning of `interval` and `burst`.
> + ///
> + /// # Safety
> + ///
> + /// The resulting value must be stored in static memory.
This one is const-only so shouldn't be code-generated.
#[inline]
Best,
Gary
> + pub const unsafe fn new_static(name: &'static CStr, interval: i32, burst: i32) -> Self {
> + Self {
> + inner: Opaque::new(bindings::ratelimit_state {
> + lock: kernel::sync::lock::spinlock::raw_spin_lock_unlocked(name),
> + interval,
> + burst,
> + ..pin_init::zeroed()
> + }),
> + }
> + }