Re: [PATCH v3 3/5] rust: add pr_*_ratelimit! macros for printing

"Gary Guo" <[email protected]>
Newsgroups org.kernel.vger.rust-for-linux,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
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 <[email protected]>
> Reviewed-by: Carlos Llamas <[email protected]>
> Link: https://github.com/Rust-for-Linux/linux/issues/122
> Signed-off-by: Alice Ryhl <[email protected]>
> ---
>  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()
> +            }),
> +        }
> +    }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.