All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alvin Sun <alvin.sun@linux.dev>
To: Alice Ryhl <aliceryhl@google.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Carlos Llamas <cmllamas@google.com>,
	Boqun Feng <boqun@kernel.org>, Gary Guo <gary@garyguo.net>
Cc: "Onur Özkan" <work@onurozkan.dev>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Benno Lossin" <lossin@kernel.org>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Ingo Molnar" <mingo@redhat.com>, "Lyude Paul" <lyude@redhat.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Peter Zijlstra" <peterz@infradead.org>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Waiman Long" <longman@redhat.com>,
	"Will Deacon" <will@kernel.org>,
	linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org
Subject: Re: [PATCH 3/5] rust: add pr_*_ratelimit! macros for printing
Date: Thu, 2 Jul 2026 14:15:35 +0800	[thread overview]
Message-ID: <d63a68b2-4301-4ce2-a28c-637f4c6bf4fa@linux.dev> (raw)
In-Reply-To: <20260623-pr-ratelimited-v1-3-cc922f544dc0@google.com>


On 6/23/26 23:38, 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.
>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>

Tested-by: Alvin Sun <alvin.sun@linux.dev>

The binder-related patches couldn't be applied to the mainline
repository. I wrote a simple misc device to test pr_warn_ratelimited:

[   80.655483] misc misc_test: Opening Rust Misc Test Device
[   80.655546] Rust: 1990 callbacks suppressed
[   80.656102] rust_misc_test: pr_warn_ratelimited triggered (0) from 
/dev/misc_test
[   80.656137] rust_misc_test: pr_warn_ratelimited triggered (1) from 
/dev/misc_test

> ---
>   rust/helpers/helpers.c   |   1 +
>   rust/helpers/ratelimit.c |  14 ++++
>   rust/kernel/lib.rs       |   1 +
>   rust/kernel/prelude.rs   |   8 ++
>   rust/kernel/ratelimit.rs | 202 +++++++++++++++++++++++++++++++++++++++++++++++
>   5 files changed, 226 insertions(+)
>
> diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
> index d17eaec76450..2184b11c927f 100644
> --- a/rust/helpers/helpers.c
> +++ b/rust/helpers/helpers.c
> @@ -80,6 +80,7 @@
>   #include "processor.c"
>   #include "property.c"
>   #include "pwm.c"
> +#include "ratelimit.c"
>   #include "rbtree.c"
>   #include "rcu.c"
>   #include "refcount.c"
> diff --git a/rust/helpers/ratelimit.c b/rust/helpers/ratelimit.c
> new file mode 100644
> index 000000000000..e5052f568b81
> --- /dev/null
> +++ b/rust/helpers/ratelimit.c
> @@ -0,0 +1,14 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/ratelimit.h>
> +
> +__rust_helper void rust_helper_ratelimit_state_init(struct ratelimit_state *rs,
> +						    int interval, int burst)
> +{
> +	ratelimit_state_init(rs, interval, burst);
> +}
> +
> +__rust_helper void rust_helper_ratelimit_state_exit(struct ratelimit_state *rs)
> +{
> +	ratelimit_state_exit(rs);
> +}
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index b72b2fbe046d..ba65ab4f0b8c 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -111,6 +111,7 @@
>   pub mod ptr;
>   #[cfg(CONFIG_RUST_PWM_ABSTRACTIONS)]
>   pub mod pwm;
> +pub mod ratelimit;
>   pub mod rbtree;
>   pub mod regulator;
>   pub mod revocable;
> diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
> index 44edf72a4a24..5a66028dd973 100644
> --- a/rust/kernel/prelude.rs
> +++ b/rust/kernel/prelude.rs
> @@ -89,13 +89,21 @@
>       },
>       init::InPlaceInit,
>       pr_alert,
> +    pr_alert_ratelimited,
>       pr_crit,
> +    pr_crit_ratelimited,
>       pr_debug,
> +    pr_debug_ratelimited,
>       pr_emerg,
> +    pr_emerg_ratelimited,
>       pr_err,
> +    pr_err_ratelimited,
>       pr_info,
> +    pr_info_ratelimited,
>       pr_notice,
> +    pr_notice_ratelimited,
>       pr_warn,
> +    pr_warn_ratelimited,
>       static_assert,
>       str::CStrExt as _,
>       try_init,
> diff --git a/rust/kernel/ratelimit.rs b/rust/kernel/ratelimit.rs
> new file mode 100644
> index 000000000000..da0a49412023
> --- /dev/null
> +++ b/rust/kernel/ratelimit.rs
> @@ -0,0 +1,202 @@
> +// 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 init: $crate::bindings::ratelimit_state = $crate::bindings::ratelimit_state {
> +                lock: $crate::sync::lock::spinlock::raw_spin_lock_unlocked($crate::c_str!(
> +                    ::core::stringify!($name)
> +                )),
> +                interval: $interval,
> +                burst: $burst,
> +                // SAFETY: This type can be zeroed.
> +                ..unsafe { ::core::mem::zeroed() }
> +            };
> +            // SAFETY: This is a repr(transparent) wrapper, and the invariants are satisfied.
> +            unsafe { ::core::mem::transmute(init) }
> +        };
> +    };
> +}
> +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)
> +    }
> +
> +    /// The default interval used for rate limiting.
> +    pub const DEFAULT_INTERVAL: i32 = bindings::DEFAULT_RATELIMIT_INTERVAL as i32;
> +
> +    /// The default burst size.
> +    pub const DEFAULT_BURST: i32 = bindings::DEFAULT_RATELIMIT_BURST as i32;
> +
> +    /// Check if an action should be rate-limited.
> +    ///
> +    /// Returns `true` if the action is allowed, and `false` if it should be suppressed.
> +    #[inline]
> +    pub fn ratelimit(&self) -> bool {
> +        // We don't set `RATELIMIT_MSG_ON_RELEASE`, so the function name parameter is not used.
> +        //
> +        // SAFETY: `self.inner.get()` is a valid pointer to a `struct ratelimit_state`.
> +        // The lifetime of `func` ensures the pointer remains valid for the duration of the call.
> +        // The C function `___ratelimit` handles its own internal locking, so it is safe to call
> +        // concurrently.
> +        unsafe { bindings::___ratelimit(self.inner.get(), c"Rust".as_char_ptr()) != 0 }
> +    }
> +}
> +
> +#[pinned_drop]
> +impl PinnedDrop for Ratelimit {
> +    #[inline]
> +    fn drop(self: Pin<&mut Self>) {
> +        // SAFETY: By the type invariants, this struct contains an initialized `struct
> +        // ratelimit_state`.
> +        unsafe { bindings::ratelimit_state_exit(self.inner.get()) };
> +    }
> +}
> +
> +/// Helper macro to implement ratelimited printing.
> +#[macro_export]
> +#[doc(hidden)]
> +macro_rules! print_ratelimited {
> +    ($print_macro:ident, $($arg:tt)*) => {{
> +        $crate::ratelimit::ratelimit_state_init!(
> +            _rs,
> +            $crate::ratelimit::Ratelimit::DEFAULT_INTERVAL,
> +            $crate::ratelimit::Ratelimit::DEFAULT_BURST,
> +        );
> +        if $crate::ratelimit::Ratelimit::ratelimit(&_rs) {
> +            $crate::$print_macro!($($arg)*);
> +        }
> +    }};
> +}
> +
> +/// Prints an emergency-level message (level 0) if allowed by a rate limiter.
> +///
> +/// [`Ratelimit`]: $crate::ratelimit::Ratelimit
> +#[macro_export]
> +macro_rules! pr_emerg_ratelimited (
> +    ($($arg:tt)*) => (
> +        $crate::print_ratelimited!(pr_emerg, $($arg)*)
> +    )
> +);
> +
> +/// Prints an alert-level message (level 1) if allowed by a rate limiter.
> +///
> +/// [`Ratelimit`]: $crate::ratelimit::Ratelimit
> +#[macro_export]
> +macro_rules! pr_alert_ratelimited (
> +    ($($arg:tt)*) => (
> +        $crate::print_ratelimited!(pr_alert, $($arg)*)
> +    )
> +);
> +
> +/// Prints a critical-level message (level 2) if allowed by a rate limiter.
> +///
> +/// [`Ratelimit`]: $crate::ratelimit::Ratelimit
> +#[macro_export]
> +macro_rules! pr_crit_ratelimited (
> +    ($($arg:tt)*) => (
> +        $crate::print_ratelimited!(pr_crit, $($arg)*)
> +    )
> +);
> +
> +/// Prints an error-level message (level 3) if allowed by a rate limiter.
> +///
> +/// [`Ratelimit`]: $crate::ratelimit::Ratelimit
> +#[macro_export]
> +macro_rules! pr_err_ratelimited (
> +    ($($arg:tt)*) => (
> +        $crate::print_ratelimited!(pr_err, $($arg)*)
> +    )
> +);
> +
> +/// Prints a warning-level message (level 4) if allowed by a rate limiter.
> +///
> +/// [`Ratelimit`]: $crate::ratelimit::Ratelimit
> +#[macro_export]
> +macro_rules! pr_warn_ratelimited (
> +    ($($arg:tt)*) => (
> +        $crate::print_ratelimited!(pr_warn, $($arg)*)
> +    )
> +);
> +
> +/// Prints a notice-level message (level 5) if allowed by a rate limiter.
> +///
> +/// [`Ratelimit`]: $crate::ratelimit::Ratelimit
> +#[macro_export]
> +macro_rules! pr_notice_ratelimited (
> +    ($($arg:tt)*) => (
> +        $crate::print_ratelimited!(pr_notice, $($arg)*)
> +    )
> +);
> +
> +/// Prints an info-level message (level 6) if allowed by a rate limiter.
> +///
> +/// [`Ratelimit`]: $crate::ratelimit::Ratelimit
> +#[macro_export]
> +macro_rules! pr_info_ratelimited (
> +    ($($arg:tt)*) => (
> +        $crate::print_ratelimited!(pr_info, $($arg)*)
> +    )
> +);
> +
> +/// Prints a debug-level message (level 7) if allowed by a rate limiter.
> +///
> +/// [`Ratelimit`]: $crate::ratelimit::Ratelimit
> +#[macro_export]
> +macro_rules! pr_debug_ratelimited (
> +    ($($arg:tt)*) => (
> +        if cfg!(debug_assertions) {
> +            $crate::print_ratelimited!(pr_debug, $($arg)*)
> +        }
> +    )
> +);
>

  parent reply	other threads:[~2026-07-02  6:16 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-23 15:38 [PATCH 0/5] Rate limited printing for Rust Alice Ryhl
2026-06-23 15:38 ` [PATCH 1/5] rust: sync: move lockdep types to rust/kernel/sync/lockdep.rs Alice Ryhl
2026-06-26 20:26   ` Carlos Llamas
2026-06-30  3:20   ` Boqun Feng
2026-07-01 16:10   ` Gary Guo
2026-06-23 15:38 ` [PATCH 2/5] rust: sync: add const constructor for raw_spinlock_t Alice Ryhl
2026-06-26 20:52   ` Carlos Llamas
2026-07-07 13:12     ` Alice Ryhl
2026-06-30  3:44   ` Boqun Feng
2026-07-07 13:13     ` Alice Ryhl
2026-07-01 16:15   ` Gary Guo
2026-07-07 13:17     ` Alice Ryhl
2026-07-07 13:33       ` Gary Guo
2026-07-07 13:52         ` Alice Ryhl
2026-06-23 15:38 ` [PATCH 3/5] rust: add pr_*_ratelimit! macros for printing Alice Ryhl
2026-06-23 15:55   ` Gary Guo
2026-06-23 19:11     ` Alice Ryhl
2026-06-23 19:53     ` Miguel Ojeda
2026-06-23 20:06       ` Gary Guo
2026-06-23 19:31   ` Miguel Ojeda
2026-06-23 20:05     ` Alice Ryhl
2026-06-26 23:12   ` Carlos Llamas
2026-07-01 16:20   ` Gary Guo
2026-07-01 17:02     ` Alice Ryhl
2026-07-01 17:14       ` Gary Guo
2026-07-02  7:50         ` Alice Ryhl
2026-07-02  6:15   ` Alvin Sun [this message]
2026-07-07 13:13     ` Alice Ryhl
2026-06-23 15:38 ` [PATCH 4/5] rust_binder: consolidate transaction failure prints Alice Ryhl
2026-06-26 23:28   ` Carlos Llamas
2026-07-07 13:18     ` Alice Ryhl
2026-06-23 15:38 ` [PATCH 5/5] rust_binder: use pr_*_ratelimited! for printing Alice Ryhl
2026-06-26 23:34   ` Carlos Llamas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d63a68b2-4301-4ce2-a28c-637f4c6bf4fa@linux.dev \
    --to=alvin.sun@linux.dev \
    --cc=a.hindborg@kernel.org \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=cmllamas@google.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=gary@garyguo.net \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=longman@redhat.com \
    --cc=lossin@kernel.org \
    --cc=lyude@redhat.com \
    --cc=mingo@redhat.com \
    --cc=ojeda@kernel.org \
    --cc=peterz@infradead.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tmgross@umich.edu \
    --cc=will@kernel.org \
    --cc=work@onurozkan.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.