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