Skip to main content

kernel/
ratelimit.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Rate limiting support.
4//!
5//! C header: [`include/linux/ratelimit.h`](srctree/include/linux/ratelimit.h)
6
7use crate::{
8    bindings,
9    prelude::*,
10    types::Opaque, //
11};
12
13/// Defines a `static` containing a [`Ratelimit`].
14#[macro_export]
15macro_rules! ratelimit_state_init {
16    ($name:ident, $interval:expr, $burst:expr $(,)?) => {
17        #[allow(non_upper_case_globals)]
18        static $name: $crate::ratelimit::Ratelimit = {
19            let name = $crate::c_str!(::core::stringify!($name));
20            let interval = $interval;
21            let burst = $burst;
22            // SAFETY: This will be stored in static memory.
23            unsafe { $crate::ratelimit::Ratelimit::new_static(name, interval, burst) }
24        };
25    };
26}
27pub use ratelimit_state_init;
28
29/// Rate limiter state.
30///
31/// # Invariants
32///
33/// The `inner` field contains an initialized `struct ratelimit_state`.
34#[pin_data(PinnedDrop)]
35#[repr(transparent)]
36pub struct Ratelimit {
37    #[pin]
38    inner: Opaque<bindings::ratelimit_state>,
39}
40
41// SAFETY: `Ratelimit` is safe to be sent to any task.
42unsafe impl Send for Ratelimit {}
43
44// SAFETY: `Ratelimit` is safe to be accessed concurrently as it is protected by an internal
45// spinlock.
46unsafe impl Sync for Ratelimit {}
47
48impl Ratelimit {
49    /// Constructs a [`Ratelimit`] with the specified configuration.
50    ///
51    /// If `interval` is zero, then no rate limit is applied.
52    #[inline]
53    pub fn new(interval: i32, burst: i32) -> impl PinInit<Self> {
54        // INVARIANT: This creates a `Ratelimit` containing an initialized `struct ratelimit_state`
55        pin_init!(Self {
56            inner <- Opaque::ffi_init(|slot: *mut bindings::ratelimit_state| {
57                // SAFETY: `slot` is a valid pointer to an uninitialized `struct ratelimit_state`.
58                // The memory is pinned so it remains valid until `ratelimit_state_exit` is called.
59                unsafe { bindings::ratelimit_state_init(slot, interval, burst) };
60            }),
61        })
62    }
63
64    /// Constructs a [`Ratelimit`] with the default configuration.
65    #[inline]
66    pub fn new_default() -> impl PinInit<Self> {
67        Ratelimit::new(Ratelimit::DEFAULT_INTERVAL, Ratelimit::DEFAULT_BURST)
68    }
69
70    /// Constructs a [`Ratelimit`] with the specified configuration.
71    ///
72    /// The name will be used for the lockdep name of the internal spinlock. See [`Self::new`] for
73    /// the meaning of `interval` and `burst`.
74    ///
75    /// # Safety
76    ///
77    /// The resulting value must be stored in static memory.
78    #[inline]
79    pub const unsafe fn new_static(name: &'static CStr, interval: i32, burst: i32) -> Self {
80        // INVARIANT: This creates a `Ratelimit` containing an initialized `struct ratelimit_state`.
81        Self {
82            inner: Opaque::new(bindings::ratelimit_state {
83                lock: kernel::sync::lock::spinlock::raw_spin_lock_unlocked(name),
84                interval,
85                burst,
86                ..pin_init::zeroed()
87            }),
88        }
89    }
90
91    /// The default interval used for rate limiting.
92    pub const DEFAULT_INTERVAL: i32 = bindings::DEFAULT_RATELIMIT_INTERVAL as i32;
93
94    /// The default burst size.
95    pub const DEFAULT_BURST: i32 = bindings::DEFAULT_RATELIMIT_BURST as i32;
96
97    /// Check if an action should be rate-limited.
98    ///
99    /// Returns [`true`] if the action is allowed, and [`false`] if it should be suppressed.
100    #[inline]
101    pub fn ratelimit(&self, func: &CStr) -> bool {
102        // SAFETY: `self.inner.get()` is a valid pointer to a `struct ratelimit_state`.
103        // The lifetime of `func` ensures the pointer remains valid for the duration of the call.
104        // The C function `___ratelimit` handles its own internal locking, so it is safe to call
105        // concurrently.
106        unsafe { bindings::___ratelimit(self.inner.get(), func.as_char_ptr()) != 0 }
107    }
108}
109
110#[pinned_drop]
111impl PinnedDrop for Ratelimit {
112    #[inline]
113    fn drop(self: Pin<&mut Self>) {
114        // SAFETY: By the type invariants, this struct contains an initialized `struct
115        // ratelimit_state`.
116        unsafe { bindings::ratelimit_state_exit(self.inner.get()) };
117    }
118}
119
120/// Helper macro to implement ratelimited printing.
121#[macro_export]
122#[doc(hidden)]
123macro_rules! print_ratelimited {
124    ($print_macro:ident, $($arg:tt)*) => {{
125        $crate::ratelimit::ratelimit_state_init!(
126            _rs,
127            $crate::ratelimit::Ratelimit::DEFAULT_INTERVAL,
128            $crate::ratelimit::Ratelimit::DEFAULT_BURST,
129        );
130        let loc = $crate::c_str!(::core::concat!(::core::file!(), ":", ::core::line!()));
131        if $crate::ratelimit::Ratelimit::ratelimit(&_rs, loc) {
132            $crate::$print_macro!($($arg)*);
133        }
134    }};
135}
136
137/// Prints an emergency-level message (level 0) if allowed by a rate limiter.
138#[macro_export]
139macro_rules! pr_emerg_ratelimited (
140    ($($arg:tt)*) => (
141        $crate::print_ratelimited!(pr_emerg, $($arg)*)
142    )
143);
144
145/// Prints an alert-level message (level 1) if allowed by a rate limiter.
146#[macro_export]
147macro_rules! pr_alert_ratelimited (
148    ($($arg:tt)*) => (
149        $crate::print_ratelimited!(pr_alert, $($arg)*)
150    )
151);
152
153/// Prints a critical-level message (level 2) if allowed by a rate limiter.
154#[macro_export]
155macro_rules! pr_crit_ratelimited (
156    ($($arg:tt)*) => (
157        $crate::print_ratelimited!(pr_crit, $($arg)*)
158    )
159);
160
161/// Prints an error-level message (level 3) if allowed by a rate limiter.
162#[macro_export]
163macro_rules! pr_err_ratelimited (
164    ($($arg:tt)*) => (
165        $crate::print_ratelimited!(pr_err, $($arg)*)
166    )
167);
168
169/// Prints a warning-level message (level 4) if allowed by a rate limiter.
170#[macro_export]
171macro_rules! pr_warn_ratelimited (
172    ($($arg:tt)*) => (
173        $crate::print_ratelimited!(pr_warn, $($arg)*)
174    )
175);
176
177/// Prints a notice-level message (level 5) if allowed by a rate limiter.
178#[macro_export]
179macro_rules! pr_notice_ratelimited (
180    ($($arg:tt)*) => (
181        $crate::print_ratelimited!(pr_notice, $($arg)*)
182    )
183);
184
185/// Prints an info-level message (level 6) if allowed by a rate limiter.
186#[macro_export]
187macro_rules! pr_info_ratelimited (
188    ($($arg:tt)*) => (
189        $crate::print_ratelimited!(pr_info, $($arg)*)
190    )
191);
192
193/// Prints a debug-level message (level 7) if allowed by a rate limiter.
194#[macro_export]
195macro_rules! pr_debug_ratelimited (
196    ($($arg:tt)*) => (
197        if cfg!(debug_assertions) {
198            $crate::print_ratelimited!(pr_debug, $($arg)*)
199        }
200    )
201);