Skip to main content

kernel/sync/lock/
spinlock.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! A kernel spinlock.
4//!
5//! This module allows Rust code to use the kernel's `spinlock_t`.
6use super::*;
7use crate::interrupt::LocalInterruptDisabled;
8
9/// Creates a [`SpinLock`] initialiser with the given name and a newly-created lock class.
10///
11/// It uses the name if one is given, otherwise it generates one based on the file name and line
12/// number.
13#[macro_export]
14macro_rules! new_spinlock {
15    ($inner:expr $(, $name:literal)? $(,)?) => {
16        $crate::sync::SpinLock::new(
17            $inner, $crate::optional_name!($($name)?), $crate::static_lock_class!())
18    };
19}
20pub use new_spinlock;
21
22/// A spinlock.
23///
24/// Exposes the kernel's [`spinlock_t`]. When multiple CPUs attempt to lock the same spinlock, only
25/// one at a time is allowed to progress, the others will block (spinning) until the spinlock is
26/// unlocked, at which point another CPU will be allowed to make progress.
27///
28/// Instances of [`SpinLock`] need a lock class and to be pinned. The recommended way to create such
29/// instances is with the [`pin_init`](pin_init::pin_init) and [`new_spinlock`] macros.
30///
31/// # Examples
32///
33/// The following example shows how to declare, allocate and initialise a struct (`Example`) that
34/// contains an inner struct (`Inner`) that is protected by a spinlock.
35///
36/// ```
37/// use kernel::sync::{new_spinlock, SpinLock};
38///
39/// struct Inner {
40///     a: u32,
41///     b: u32,
42/// }
43///
44/// #[pin_data]
45/// struct Example {
46///     c: u32,
47///     #[pin]
48///     d: SpinLock<Inner>,
49/// }
50///
51/// impl Example {
52///     fn new() -> impl PinInit<Self> {
53///         pin_init!(Self {
54///             c: 10,
55///             d <- new_spinlock!(Inner { a: 20, b: 30 }),
56///         })
57///     }
58/// }
59///
60/// // Allocate a boxed `Example`.
61/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?;
62/// assert_eq!(e.c, 10);
63/// assert_eq!(e.d.lock().a, 20);
64/// assert_eq!(e.d.lock().b, 30);
65/// # Ok::<(), Error>(())
66/// ```
67///
68/// The following example shows how to use interior mutability to modify the contents of a struct
69/// protected by a spinlock despite only having a shared reference:
70///
71/// ```
72/// use kernel::sync::SpinLock;
73///
74/// struct Example {
75///     a: u32,
76///     b: u32,
77/// }
78///
79/// fn example(m: &SpinLock<Example>) {
80///     let mut guard = m.lock();
81///     guard.a += 10;
82///     guard.b += 20;
83/// }
84/// ```
85///
86/// [`spinlock_t`]: srctree/include/linux/spinlock.h
87pub type SpinLock<T> = Lock<T, SpinLockBackend>;
88
89/// A kernel `spinlock_t` lock backend.
90pub struct SpinLockBackend;
91
92/// A [`Guard`] acquired from locking a [`SpinLock`].
93///
94/// This is simply a type alias for a [`Guard`] returned from locking a [`SpinLock`]. It will unlock
95/// the [`SpinLock`] upon being dropped.
96pub type SpinLockGuard<'a, T> = Guard<'a, T, SpinLockBackend>;
97
98// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion. `relock` uses the
99// default implementation that always calls the same locking method.
100unsafe impl Backend for SpinLockBackend {
101    type State = bindings::spinlock_t;
102    type GuardState = ();
103
104    #[inline]
105    unsafe fn init(
106        ptr: *mut Self::State,
107        name: *const crate::ffi::c_char,
108        key: *mut bindings::lock_class_key,
109    ) {
110        // SAFETY: The safety requirements ensure that `ptr` is valid for writes, and `name` and
111        // `key` are valid for read indefinitely.
112        unsafe { bindings::__spin_lock_init(ptr, name, key) }
113    }
114
115    #[inline]
116    unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState {
117        // SAFETY: The safety requirements of this function ensure that `ptr` points to valid
118        // memory, and that it has been initialised before.
119        unsafe { bindings::spin_lock(ptr) }
120    }
121
122    #[inline]
123    unsafe fn unlock(ptr: *mut Self::State, _guard_state: &Self::GuardState) {
124        // SAFETY: The safety requirements of this function ensure that `ptr` is valid and that the
125        // caller is the owner of the spinlock.
126        unsafe { bindings::spin_unlock(ptr) }
127    }
128
129    #[inline]
130    unsafe fn try_lock(ptr: *mut Self::State) -> Option<Self::GuardState> {
131        // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use.
132        let result = unsafe { bindings::spin_trylock(ptr) };
133
134        if result != 0 {
135            Some(())
136        } else {
137            None
138        }
139    }
140
141    #[inline]
142    unsafe fn assert_is_held(ptr: *mut Self::State) {
143        // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use.
144        unsafe { bindings::spin_assert_is_held(ptr) }
145    }
146}
147
148/// Creates a [`SpinLockIrq`] initialiser with the given name and a newly-created lock class.
149///
150/// It uses the name if one is given, otherwise it generates one based on the file name and line
151/// number.
152#[macro_export]
153macro_rules! new_spinlock_irq {
154    ($inner:expr $(, $name:literal)? $(,)?) => {
155        $crate::sync::SpinLockIrq::new(
156            $inner, $crate::optional_name!($($name)?), $crate::static_lock_class!())
157    };
158}
159pub use new_spinlock_irq;
160
161/// A variant of `SpinLock` that ensures interrupts are disabled in the critical section.
162///
163/// This lock can be acquired in two ways:
164///
165/// - Using [`lock()`] like any other type of lock, in which case the bindings will modify the
166///   interrupt state to ensure that local processor interrupts remain disabled for at least as
167///   long as the [`SpinLockIrqGuard`] exists.
168/// - Using [`lock_with()`] in contexts where a [`LocalInterruptDisabled`] token is present and
169///   local processor interrupts are already known to be disabled, in which case the local
170///   interrupt state will not be touched. This method should be preferred if a
171///   [`LocalInterruptDisabled`] token is present in the scope.
172///
173/// For more info on spinlocks, see [`SpinLock`]. For more information on interrupts,
174/// [see the interrupt module](kernel::interrupt).
175///
176/// # Examples
177///
178/// The following example shows how to declare, allocate initialise and access a struct (`Example`)
179/// that contains an inner struct (`Inner`) that is protected by a spinlock that requires local
180/// processor interrupts to be disabled.
181///
182/// ```
183/// use kernel::sync::{new_spinlock_irq, SpinLockIrq};
184///
185/// struct Inner {
186///     a: u32,
187///     b: u32,
188/// }
189///
190/// #[pin_data]
191/// struct Example {
192///     #[pin]
193///     c: SpinLockIrq<Inner>,
194///     #[pin]
195///     d: SpinLockIrq<Inner>,
196/// }
197///
198/// impl Example {
199///     fn new() -> impl PinInit<Self> {
200///         pin_init!(Self {
201///             c <- new_spinlock_irq!(Inner { a: 0, b: 10 }),
202///             d <- new_spinlock_irq!(Inner { a: 20, b: 30 }),
203///         })
204///     }
205/// }
206///
207/// // Allocate a boxed `Example`
208/// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?;
209///
210/// // Accessing an `Example` from a context where interrupts may not be disabled already.
211/// let c_guard = e.c.lock(); // interrupts are disabled now, +1 interrupt disable refcount
212/// let d_guard = e.d.lock(); // no interrupt state change, +1 interrupt disable refcount
213///
214/// assert_eq!(c_guard.a, 0);
215/// assert_eq!(c_guard.b, 10);
216/// assert_eq!(d_guard.a, 20);
217/// assert_eq!(d_guard.b, 30);
218///
219/// drop(c_guard); // Dropping c_guard will not re-enable interrupts just yet, since d_guard is
220///                // still in scope.
221/// drop(d_guard); // Last interrupt disable reference dropped here, so interrupts are re-enabled
222///                // now
223/// # Ok::<(), Error>(())
224/// ```
225///
226/// The next example demonstrates locking a [`SpinLockIrq`] using [`lock_with()`] in a function
227/// which can only be called when local processor interrupts are already disabled.
228///
229/// ```
230/// use kernel::sync::{new_spinlock_irq, SpinLockIrq};
231/// use kernel::interrupt::*;
232///
233/// struct Inner {
234///     a: u32,
235/// }
236///
237/// #[pin_data]
238/// struct Example {
239///     #[pin]
240///     inner: SpinLockIrq<Inner>,
241/// }
242///
243/// impl Example {
244///     fn new() -> impl PinInit<Self> {
245///         pin_init!(Self {
246///             inner <- new_spinlock_irq!(Inner { a: 20 }),
247///         })
248///     }
249/// }
250///
251/// // Accessing an `Example` from a function that can only be called in no-interrupt contexts.
252/// fn noirq_work(e: &Example, interrupt_disabled: &LocalInterruptDisabled) {
253///     // Because we know interrupts are disabled from interrupt_disable, we can skip toggling
254///     // interrupt state using lock_with() and the provided token
255///     assert_eq!(e.inner.lock_with(interrupt_disabled).a, 20);
256/// }
257///
258/// # let e = KBox::pin_init(Example::new(), GFP_KERNEL)?;
259/// # let interrupt_guard = local_interrupt_disable();
260/// # noirq_work(&e, &interrupt_guard);
261/// #
262/// # Ok::<(), Error>(())
263/// ```
264///
265/// [`lock()`]: SpinLockIrq::lock
266/// [`lock_with()`]: SpinLockIrq::lock_with
267pub type SpinLockIrq<T> = super::Lock<T, SpinLockIrqBackend>;
268
269/// A kernel `spinlock_t` lock backend that can only be acquired in interrupt disabled contexts.
270pub struct SpinLockIrqBackend;
271
272/// A [`Guard`] acquired from locking a [`SpinLockIrq`] using [`lock()`].
273///
274/// This is simply a type alias for a [`Guard`] returned from locking a [`SpinLockIrq`] using
275/// [`lock()`]. It will unlock the [`SpinLockIrq`] and decrement the local processor's interrupt
276/// disablement refcount upon being dropped.
277///
278/// [`lock()`]: SpinLockIrq::lock
279pub type SpinLockIrqGuard<'a, T> = Guard<'a, T, SpinLockIrqBackend>;
280
281// SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion. `relock` uses the
282// default implementation that always calls the same locking method.
283unsafe impl Backend for SpinLockIrqBackend {
284    type State = bindings::spinlock_t;
285    type GuardState = ();
286
287    #[inline]
288    unsafe fn init(
289        ptr: *mut Self::State,
290        name: *const crate::ffi::c_char,
291        key: *mut bindings::lock_class_key,
292    ) {
293        // SAFETY: The safety requirements ensure that `ptr` is valid for writes, and `name` and
294        // `key` are valid for read indefinitely.
295        unsafe { bindings::__spin_lock_init(ptr, name, key) }
296    }
297
298    #[inline]
299    unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState {
300        // SAFETY: The safety requirements of this function ensure that `ptr` points to valid
301        // memory, and that it has been initialised before.
302        unsafe { bindings::spin_lock_irq_disable(ptr) }
303    }
304
305    #[inline]
306    unsafe fn unlock(ptr: *mut Self::State, _guard_state: &Self::GuardState) {
307        // SAFETY: The safety requirements of this function ensure that `ptr` is valid and that the
308        // caller is the owner of the spinlock.
309        unsafe { bindings::spin_unlock_irq_enable(ptr) }
310    }
311
312    #[inline]
313    unsafe fn try_lock(ptr: *mut Self::State) -> Option<Self::GuardState> {
314        // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use.
315        let result = unsafe { bindings::spin_trylock_irq_disable(ptr) };
316
317        if result != 0 {
318            Some(())
319        } else {
320            None
321        }
322    }
323
324    #[inline]
325    unsafe fn assert_is_held(ptr: *mut Self::State) {
326        // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use.
327        unsafe { bindings::spin_assert_is_held(ptr) }
328    }
329}
330
331impl<T: ?Sized> Lock<T, SpinLockIrqBackend> {
332    /// Casts the lock as a `Lock<T, SpinLockBackend>`.
333    #[inline]
334    fn as_lock_in_interrupt<'a>(&'a self, _context: &'a LocalInterruptDisabled) -> &'a SpinLock<T> {
335        // SAFETY:
336        // - `Lock<T, SpinLockBackend>` and `Lock<T, SpinLockIrqBackend>` both have identical data
337        //   layouts.
338        // - As long as local interrupts are disabled (which is proven to be true by _context), it
339        //   is safe to treat a lock with SpinLockIrqBackend as a SpinLockBackend lock.
340        unsafe { core::mem::transmute(self) }
341    }
342
343    /// Acquires the lock without modifying local interrupt state.
344    ///
345    /// This function should be used in place of the more expensive [`Lock::lock()`] function when
346    /// possible for [`SpinLockIrq`] locks.
347    #[inline]
348    pub fn lock_with<'a>(&'a self, context: &'a LocalInterruptDisabled) -> SpinLockGuard<'a, T> {
349        self.as_lock_in_interrupt(context).lock()
350    }
351
352    /// Tries to acquire the lock without modifying local interrupt state.
353    ///
354    /// This function should be used in place of the more expensive [`Lock::try_lock()`] function
355    /// when possible for [`SpinLockIrq`] locks.
356    ///
357    /// Returns a guard that can be used to access the data protected by the lock if successful.
358    #[must_use = "if unused, the lock will be immediately unlocked"]
359    #[inline]
360    pub fn try_lock_with<'a>(
361        &'a self,
362        context: &'a LocalInterruptDisabled,
363    ) -> Option<SpinLockGuard<'a, T>> {
364        self.as_lock_in_interrupt(context).try_lock()
365    }
366}
367
368#[kunit_tests(rust_spinlock_irq_condvar)]
369mod tests {
370    use super::*;
371    use crate::{
372        sync::*,
373        workqueue::{
374            self,
375            impl_has_work,
376            new_work,
377            Work,
378            WorkItem, //
379        },
380    };
381
382    struct TestState {
383        value: u32,
384        waiter_ready: bool,
385    }
386
387    #[pin_data]
388    struct Test {
389        #[pin]
390        state: SpinLockIrq<TestState>,
391
392        #[pin]
393        state_changed: CondVar,
394
395        #[pin]
396        waiter_state_changed: CondVar,
397
398        #[pin]
399        wait_work: Work<Self>,
400    }
401
402    impl_has_work! {
403        impl HasWork<Self> for Test { self.wait_work }
404    }
405
406    impl Test {
407        pub(crate) fn new() -> Result<Arc<Self>> {
408            Arc::try_pin_init(
409                try_pin_init!(
410                    Self {
411                        state <- new_spinlock_irq!(TestState {
412                            value: 1,
413                            waiter_ready: false
414                        }),
415                        state_changed <- new_condvar!(),
416                        waiter_state_changed <- new_condvar!(),
417                        wait_work <- new_work!("IrqCondvarTest::wait_work")
418                    }
419                ),
420                GFP_KERNEL,
421            )
422        }
423    }
424
425    impl WorkItem for Test {
426        type Pointer = Arc<Self>;
427
428        fn run(this: Arc<Self>) {
429            // Wait for the test to be ready to wait for us
430            let mut state = this.state.lock();
431
432            // Make sure the interrupts actually turned off
433            // SAFETY: It's always safe to call `lockdep_assert_irqs_disabled()`
434            unsafe { bindings::lockdep_assert_irqs_disabled() };
435
436            while !state.waiter_ready {
437                this.waiter_state_changed.wait(&mut state);
438            }
439
440            // Deliver the exciting value update our test has been waiting for
441            state.value += 1;
442            this.state_changed.notify_sync();
443        }
444    }
445
446    #[test]
447    fn spinlock_irq_condvar() -> Result {
448        let testdata = Test::new()?;
449
450        let _ = workqueue::system_dfl().enqueue(testdata.clone());
451
452        // Let the updater know when we're ready to wait
453        let mut state = testdata.state.lock();
454        state.waiter_ready = true;
455        testdata.waiter_state_changed.notify_sync();
456
457        // Wait for the exciting value update
458        testdata.state_changed.wait(&mut state);
459        assert_eq!(state.value, 2);
460        Ok(())
461    }
462}
463
464/// Helper for creating a raw unlocked `bindings::raw_spinlock_t`.
465///
466/// For use in statics containing raw spinlocks.
467#[doc(alias("__SPIN_LOCK_UNLOCKED", "DEFINE_SPINLOCK"))]
468pub(crate) const fn raw_spin_lock_unlocked(name: &'static CStr) -> bindings::raw_spinlock_t {
469    // Silence unused variable warnings.
470    #[cfg(not(CONFIG_DEBUG_LOCK_ALLOC))]
471    let _ = name;
472
473    bindings::raw_spinlock_t {
474        raw_lock: bindings::__ARCH_SPIN_LOCK_UNLOCKED,
475
476        #[cfg(CONFIG_DEBUG_SPINLOCK)]
477        magic: bindings::SPINLOCK_MAGIC,
478        #[cfg(CONFIG_DEBUG_SPINLOCK)]
479        owner_cpu: u32::MAX,
480        #[cfg(CONFIG_DEBUG_SPINLOCK)]
481        owner: usize::MAX as *mut c_void,
482
483        #[cfg(CONFIG_DEBUG_LOCK_ALLOC)]
484        dep_map: kernel::sync::lockdep::raw_lockdep_map(
485            name,
486            kernel::sync::lockdep::LD_WAIT_SPIN,
487            kernel::sync::lockdep::LD_WAIT_INV,
488        ),
489    }
490}