xref: /linux-6.15/rust/kernel/sync/lock.rs (revision dbd5058b)
176d4bd59SWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0
276d4bd59SWedson Almeida Filho 
376d4bd59SWedson Almeida Filho //! Generic kernel lock and guard.
476d4bd59SWedson Almeida Filho //!
576d4bd59SWedson Almeida Filho //! It contains a generic Rust lock and guard that allow for different backends (e.g., mutexes,
676d4bd59SWedson Almeida Filho //! spinlocks, raw spinlocks) to be provided with minimal effort.
776d4bd59SWedson Almeida Filho 
876d4bd59SWedson Almeida Filho use super::LockClassKey;
9e7572e5dSAlice Ryhl use crate::{
10e7572e5dSAlice Ryhl     str::CStr,
11e7572e5dSAlice Ryhl     types::{NotThreadSafe, Opaque, ScopeGuard},
12e7572e5dSAlice Ryhl };
13e7572e5dSAlice Ryhl use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
14*dbd5058bSBenno Lossin use pin_init::{pin_data, pin_init, PinInit};
1576d4bd59SWedson Almeida Filho 
166d20d629SWedson Almeida Filho pub mod mutex;
17c6d917a4SWedson Almeida Filho pub mod spinlock;
186d20d629SWedson Almeida Filho 
198eea62ffSAlice Ryhl pub(super) mod global;
208eea62ffSAlice Ryhl pub use global::{GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy};
218eea62ffSAlice Ryhl 
2276d4bd59SWedson Almeida Filho /// The "backend" of a lock.
2376d4bd59SWedson Almeida Filho ///
2476d4bd59SWedson Almeida Filho /// It is the actual implementation of the lock, without the need to repeat patterns used in all
2576d4bd59SWedson Almeida Filho /// locks.
2676d4bd59SWedson Almeida Filho ///
2776d4bd59SWedson Almeida Filho /// # Safety
2876d4bd59SWedson Almeida Filho ///
2976d4bd59SWedson Almeida Filho /// - Implementers must ensure that only one thread/CPU may access the protected data once the lock
304c799d1dSValentin Obst ///   is owned, that is, between calls to [`lock`] and [`unlock`].
314c799d1dSValentin Obst /// - Implementers must also ensure that [`relock`] uses the same locking method as the original
32e32cca32SWedson Almeida Filho ///   lock operation.
334c799d1dSValentin Obst ///
344c799d1dSValentin Obst /// [`lock`]: Backend::lock
354c799d1dSValentin Obst /// [`unlock`]: Backend::unlock
364c799d1dSValentin Obst /// [`relock`]: Backend::relock
3776d4bd59SWedson Almeida Filho pub unsafe trait Backend {
3876d4bd59SWedson Almeida Filho     /// The state required by the lock.
3976d4bd59SWedson Almeida Filho     type State;
4076d4bd59SWedson Almeida Filho 
414c799d1dSValentin Obst     /// The state required to be kept between [`lock`] and [`unlock`].
424c799d1dSValentin Obst     ///
434c799d1dSValentin Obst     /// [`lock`]: Backend::lock
444c799d1dSValentin Obst     /// [`unlock`]: Backend::unlock
4576d4bd59SWedson Almeida Filho     type GuardState;
4676d4bd59SWedson Almeida Filho 
4776d4bd59SWedson Almeida Filho     /// Initialises the lock.
4876d4bd59SWedson Almeida Filho     ///
4976d4bd59SWedson Almeida Filho     /// # Safety
5076d4bd59SWedson Almeida Filho     ///
5176d4bd59SWedson Almeida Filho     /// `ptr` must be valid for write for the duration of the call, while `name` and `key` must
5276d4bd59SWedson Almeida Filho     /// remain valid for read indefinitely.
init( ptr: *mut Self::State, name: *const crate::ffi::c_char, key: *mut bindings::lock_class_key, )5376d4bd59SWedson Almeida Filho     unsafe fn init(
5476d4bd59SWedson Almeida Filho         ptr: *mut Self::State,
55d072acdaSGary Guo         name: *const crate::ffi::c_char,
5676d4bd59SWedson Almeida Filho         key: *mut bindings::lock_class_key,
5776d4bd59SWedson Almeida Filho     );
5876d4bd59SWedson Almeida Filho 
5976d4bd59SWedson Almeida Filho     /// Acquires the lock, making the caller its owner.
6076d4bd59SWedson Almeida Filho     ///
6176d4bd59SWedson Almeida Filho     /// # Safety
6276d4bd59SWedson Almeida Filho     ///
6376d4bd59SWedson Almeida Filho     /// Callers must ensure that [`Backend::init`] has been previously called.
6476d4bd59SWedson Almeida Filho     #[must_use]
lock(ptr: *mut Self::State) -> Self::GuardState6576d4bd59SWedson Almeida Filho     unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState;
6676d4bd59SWedson Almeida Filho 
67f4c2c90bSFilipe Xavier     /// Tries to acquire the lock.
68f4c2c90bSFilipe Xavier     ///
69f4c2c90bSFilipe Xavier     /// # Safety
70f4c2c90bSFilipe Xavier     ///
71f4c2c90bSFilipe Xavier     /// Callers must ensure that [`Backend::init`] has been previously called.
try_lock(ptr: *mut Self::State) -> Option<Self::GuardState>72f4c2c90bSFilipe Xavier     unsafe fn try_lock(ptr: *mut Self::State) -> Option<Self::GuardState>;
73f4c2c90bSFilipe Xavier 
7476d4bd59SWedson Almeida Filho     /// Releases the lock, giving up its ownership.
7576d4bd59SWedson Almeida Filho     ///
7676d4bd59SWedson Almeida Filho     /// # Safety
7776d4bd59SWedson Almeida Filho     ///
7876d4bd59SWedson Almeida Filho     /// It must only be called by the current owner of the lock.
unlock(ptr: *mut Self::State, guard_state: &Self::GuardState)7976d4bd59SWedson Almeida Filho     unsafe fn unlock(ptr: *mut Self::State, guard_state: &Self::GuardState);
80e32cca32SWedson Almeida Filho 
81e32cca32SWedson Almeida Filho     /// Reacquires the lock, making the caller its owner.
82e32cca32SWedson Almeida Filho     ///
83e32cca32SWedson Almeida Filho     /// # Safety
84e32cca32SWedson Almeida Filho     ///
85e32cca32SWedson Almeida Filho     /// Callers must ensure that `guard_state` comes from a previous call to [`Backend::lock`] (or
86e32cca32SWedson Almeida Filho     /// variant) that has been unlocked with [`Backend::unlock`] and will be relocked now.
relock(ptr: *mut Self::State, guard_state: &mut Self::GuardState)87e32cca32SWedson Almeida Filho     unsafe fn relock(ptr: *mut Self::State, guard_state: &mut Self::GuardState) {
88e32cca32SWedson Almeida Filho         // SAFETY: The safety requirements ensure that the lock is initialised.
89e32cca32SWedson Almeida Filho         *guard_state = unsafe { Self::lock(ptr) };
90e32cca32SWedson Almeida Filho     }
91fbd7a5a0SLyude Paul 
92fbd7a5a0SLyude Paul     /// Asserts that the lock is held using lockdep.
93fbd7a5a0SLyude Paul     ///
94fbd7a5a0SLyude Paul     /// # Safety
95fbd7a5a0SLyude Paul     ///
96fbd7a5a0SLyude Paul     /// Callers must ensure that [`Backend::init`] has been previously called.
assert_is_held(ptr: *mut Self::State)97fbd7a5a0SLyude Paul     unsafe fn assert_is_held(ptr: *mut Self::State);
9876d4bd59SWedson Almeida Filho }
9976d4bd59SWedson Almeida Filho 
10076d4bd59SWedson Almeida Filho /// A mutual exclusion primitive.
10176d4bd59SWedson Almeida Filho ///
102db7193a5SBen Gooding /// Exposes one of the kernel locking primitives. Which one is exposed depends on the lock
103db7193a5SBen Gooding /// [`Backend`] specified as the generic parameter `B`.
10415abc880SLyude Paul #[repr(C)]
10576d4bd59SWedson Almeida Filho #[pin_data]
10676d4bd59SWedson Almeida Filho pub struct Lock<T: ?Sized, B: Backend> {
10776d4bd59SWedson Almeida Filho     /// The kernel lock object.
10876d4bd59SWedson Almeida Filho     #[pin]
10976d4bd59SWedson Almeida Filho     state: Opaque<B::State>,
11076d4bd59SWedson Almeida Filho 
11176d4bd59SWedson Almeida Filho     /// Some locks are known to be self-referential (e.g., mutexes), while others are architecture
11276d4bd59SWedson Almeida Filho     /// or config defined (e.g., spinlocks). So we conservatively require them to be pinned in case
11376d4bd59SWedson Almeida Filho     /// some architecture uses self-references now or in the future.
11476d4bd59SWedson Almeida Filho     #[pin]
11576d4bd59SWedson Almeida Filho     _pin: PhantomPinned,
11676d4bd59SWedson Almeida Filho 
11776d4bd59SWedson Almeida Filho     /// The data protected by the lock.
1187b1f55e3SWedson Almeida Filho     pub(crate) data: UnsafeCell<T>,
11976d4bd59SWedson Almeida Filho }
12076d4bd59SWedson Almeida Filho 
12176d4bd59SWedson Almeida Filho // SAFETY: `Lock` can be transferred across thread boundaries iff the data it protects can.
12276d4bd59SWedson Almeida Filho unsafe impl<T: ?Sized + Send, B: Backend> Send for Lock<T, B> {}
12376d4bd59SWedson Almeida Filho 
12476d4bd59SWedson Almeida Filho // SAFETY: `Lock` serialises the interior mutability it provides, so it is `Sync` as long as the
12576d4bd59SWedson Almeida Filho // data it protects is `Send`.
12676d4bd59SWedson Almeida Filho unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
12776d4bd59SWedson Almeida Filho 
12876d4bd59SWedson Almeida Filho impl<T, B: Backend> Lock<T, B> {
12976d4bd59SWedson Almeida Filho     /// Constructs a new lock initialiser.
new(t: T, name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self>13076d4bd59SWedson Almeida Filho     pub fn new(t: T, name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
13176d4bd59SWedson Almeida Filho         pin_init!(Self {
13276d4bd59SWedson Almeida Filho             data: UnsafeCell::new(t),
13376d4bd59SWedson Almeida Filho             _pin: PhantomPinned,
13476d4bd59SWedson Almeida Filho             // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have
13576d4bd59SWedson Almeida Filho             // static lifetimes so they live indefinitely.
13676d4bd59SWedson Almeida Filho             state <- Opaque::ffi_init(|slot| unsafe {
13776d4bd59SWedson Almeida Filho                 B::init(slot, name.as_char_ptr(), key.as_ptr())
13876d4bd59SWedson Almeida Filho             }),
13976d4bd59SWedson Almeida Filho         })
14076d4bd59SWedson Almeida Filho     }
14176d4bd59SWedson Almeida Filho }
14276d4bd59SWedson Almeida Filho 
14315abc880SLyude Paul impl<B: Backend> Lock<(), B> {
14415abc880SLyude Paul     /// Constructs a [`Lock`] from a raw pointer.
14515abc880SLyude Paul     ///
14615abc880SLyude Paul     /// This can be useful for interacting with a lock which was initialised outside of Rust.
14715abc880SLyude Paul     ///
14815abc880SLyude Paul     /// # Safety
14915abc880SLyude Paul     ///
15015abc880SLyude Paul     /// The caller promises that `ptr` points to a valid initialised instance of [`State`] during
15115abc880SLyude Paul     /// the whole lifetime of `'a`.
15215abc880SLyude Paul     ///
15315abc880SLyude Paul     /// [`State`]: Backend::State
from_raw<'a>(ptr: *mut B::State) -> &'a Self15415abc880SLyude Paul     pub unsafe fn from_raw<'a>(ptr: *mut B::State) -> &'a Self {
15515abc880SLyude Paul         // SAFETY:
15615abc880SLyude Paul         // - By the safety contract `ptr` must point to a valid initialised instance of `B::State`
15715abc880SLyude Paul         // - Since the lock data type is `()` which is a ZST, `state` is the only non-ZST member of
15815abc880SLyude Paul         //   the struct
15915abc880SLyude Paul         // - Combined with `#[repr(C)]`, this guarantees `Self` has an equivalent data layout to
16015abc880SLyude Paul         //   `B::State`.
16115abc880SLyude Paul         unsafe { &*ptr.cast() }
16215abc880SLyude Paul     }
16315abc880SLyude Paul }
16415abc880SLyude Paul 
16576d4bd59SWedson Almeida Filho impl<T: ?Sized, B: Backend> Lock<T, B> {
16676d4bd59SWedson Almeida Filho     /// Acquires the lock and gives the caller access to the data protected by it.
lock(&self) -> Guard<'_, T, B>16776d4bd59SWedson Almeida Filho     pub fn lock(&self) -> Guard<'_, T, B> {
16876d4bd59SWedson Almeida Filho         // SAFETY: The constructor of the type calls `init`, so the existence of the object proves
16976d4bd59SWedson Almeida Filho         // that `init` was called.
17076d4bd59SWedson Almeida Filho         let state = unsafe { B::lock(self.state.get()) };
17176d4bd59SWedson Almeida Filho         // SAFETY: The lock was just acquired.
17276d4bd59SWedson Almeida Filho         unsafe { Guard::new(self, state) }
17376d4bd59SWedson Almeida Filho     }
174f4c2c90bSFilipe Xavier 
175f4c2c90bSFilipe Xavier     /// Tries to acquire the lock.
176f4c2c90bSFilipe Xavier     ///
177f4c2c90bSFilipe Xavier     /// Returns a guard that can be used to access the data protected by the lock if successful.
try_lock(&self) -> Option<Guard<'_, T, B>>178f4c2c90bSFilipe Xavier     pub fn try_lock(&self) -> Option<Guard<'_, T, B>> {
179f4c2c90bSFilipe Xavier         // SAFETY: The constructor of the type calls `init`, so the existence of the object proves
180f4c2c90bSFilipe Xavier         // that `init` was called.
181f4c2c90bSFilipe Xavier         unsafe { B::try_lock(self.state.get()).map(|state| Guard::new(self, state)) }
182f4c2c90bSFilipe Xavier     }
18376d4bd59SWedson Almeida Filho }
18476d4bd59SWedson Almeida Filho 
18576d4bd59SWedson Almeida Filho /// A lock guard.
18676d4bd59SWedson Almeida Filho ///
187db7193a5SBen Gooding /// Allows mutual exclusion primitives that implement the [`Backend`] trait to automatically unlock
18876d4bd59SWedson Almeida Filho /// when a guard goes out of scope. It also provides a safe and convenient way to access the data
18976d4bd59SWedson Almeida Filho /// protected by the lock.
19076d4bd59SWedson Almeida Filho #[must_use = "the lock unlocks immediately when the guard is unused"]
19176d4bd59SWedson Almeida Filho pub struct Guard<'a, T: ?Sized, B: Backend> {
19276d4bd59SWedson Almeida Filho     pub(crate) lock: &'a Lock<T, B>,
19376d4bd59SWedson Almeida Filho     pub(crate) state: B::GuardState,
194e7572e5dSAlice Ryhl     _not_send: NotThreadSafe,
19576d4bd59SWedson Almeida Filho }
19676d4bd59SWedson Almeida Filho 
19776d4bd59SWedson Almeida Filho // SAFETY: `Guard` is sync when the data protected by the lock is also sync.
19876d4bd59SWedson Almeida Filho unsafe impl<T: Sync + ?Sized, B: Backend> Sync for Guard<'_, T, B> {}
19976d4bd59SWedson Almeida Filho 
200e32cca32SWedson Almeida Filho impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
201e7b9b1ffSAlice Ryhl     /// Returns the lock that this guard originates from.
202e32cca32SWedson Almeida Filho     ///
203e32cca32SWedson Almeida Filho     /// # Examples
204e32cca32SWedson Almeida Filho     ///
205db4f72c9SMiguel Ojeda     /// The following example shows how to use [`Guard::lock_ref()`] to assert the corresponding
206e32cca32SWedson Almeida Filho     /// lock is held.
207db4f72c9SMiguel Ojeda     ///
208e32cca32SWedson Almeida Filho     /// ```
209e7b9b1ffSAlice Ryhl     /// # use kernel::{new_spinlock, sync::lock::{Backend, Guard, Lock}};
210e32cca32SWedson Almeida Filho     /// # use pin_init::stack_pin_init;
211e32cca32SWedson Almeida Filho     ///
212e32cca32SWedson Almeida Filho     /// fn assert_held<T, B: Backend>(guard: &Guard<'_, T, B>, lock: &Lock<T, B>) {
21376d4bd59SWedson Almeida Filho     ///     // Address-equal means the same lock.
21476d4bd59SWedson Almeida Filho     ///     assert!(core::ptr::eq(guard.lock_ref(), lock));
21576d4bd59SWedson Almeida Filho     /// }
21676d4bd59SWedson Almeida Filho     ///
21776d4bd59SWedson Almeida Filho     /// // Creates a new lock on the stack.
21876d4bd59SWedson Almeida Filho     /// stack_pin_init!{
21976d4bd59SWedson Almeida Filho     ///     let l = new_spinlock!(42)
22076d4bd59SWedson Almeida Filho     /// }
22176d4bd59SWedson Almeida Filho     ///
22276d4bd59SWedson Almeida Filho     /// let g = l.lock();
22376d4bd59SWedson Almeida Filho     ///
22476d4bd59SWedson Almeida Filho     /// // `g` originates from `l`.
22576d4bd59SWedson Almeida Filho     /// assert_held(&g, &l);
22676d4bd59SWedson Almeida Filho     /// ```
lock_ref(&self) -> &'a Lock<T, B>22776d4bd59SWedson Almeida Filho     pub fn lock_ref(&self) -> &'a Lock<T, B> {
22876d4bd59SWedson Almeida Filho         self.lock
22976d4bd59SWedson Almeida Filho     }
23076d4bd59SWedson Almeida Filho 
do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U23176d4bd59SWedson Almeida Filho     pub(crate) fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
23276d4bd59SWedson Almeida Filho         // SAFETY: The caller owns the lock, so it is safe to unlock it.
23376d4bd59SWedson Almeida Filho         unsafe { B::unlock(self.lock.state.get(), &self.state) };
23476d4bd59SWedson Almeida Filho 
23576d4bd59SWedson Almeida Filho         let _relock = ScopeGuard::new(||
23676d4bd59SWedson Almeida Filho                 // SAFETY: The lock was just unlocked above and is being relocked now.
23776d4bd59SWedson Almeida Filho                 unsafe { B::relock(self.lock.state.get(), &mut self.state) });
23876d4bd59SWedson Almeida Filho 
23976d4bd59SWedson Almeida Filho         cb()
24076d4bd59SWedson Almeida Filho     }
24176d4bd59SWedson Almeida Filho }
242daa03fe5SLyude Paul 
243fbd7a5a0SLyude Paul impl<T: ?Sized, B: Backend> core::ops::Deref for Guard<'_, T, B> {
244fbd7a5a0SLyude Paul     type Target = T;
245fbd7a5a0SLyude Paul 
deref(&self) -> &Self::Target24676d4bd59SWedson Almeida Filho     fn deref(&self) -> &Self::Target {
24776d4bd59SWedson Almeida Filho         // SAFETY: The caller owns the lock, so it is safe to deref the protected data.
24876d4bd59SWedson Almeida Filho         unsafe { &*self.lock.data.get() }
249e7572e5dSAlice Ryhl     }
25076d4bd59SWedson Almeida Filho }
25176d4bd59SWedson Almeida Filho 
25276d4bd59SWedson Almeida Filho impl<T: ?Sized, B: Backend> core::ops::DerefMut for Guard<'_, T, B> {
deref_mut(&mut self) -> &mut Self::Target253     fn deref_mut(&mut self) -> &mut Self::Target {
254         // SAFETY: The caller owns the lock, so it is safe to deref the protected data.
255         unsafe { &mut *self.lock.data.get() }
256     }
257 }
258 
259 impl<T: ?Sized, B: Backend> Drop for Guard<'_, T, B> {
drop(&mut self)260     fn drop(&mut self) {
261         // SAFETY: The caller owns the lock, so it is safe to unlock it.
262         unsafe { B::unlock(self.lock.state.get(), &self.state) };
263     }
264 }
265 
266 impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
267     /// Constructs a new immutable lock guard.
268     ///
269     /// # Safety
270     ///
271     /// The caller must ensure that it owns the lock.
new(lock: &'a Lock<T, B>, state: B::GuardState) -> Self272     pub unsafe fn new(lock: &'a Lock<T, B>, state: B::GuardState) -> Self {
273         // SAFETY: The caller can only hold the lock if `Backend::init` has already been called.
274         unsafe { B::assert_is_held(lock.state.get()) };
275 
276         Self {
277             lock,
278             state,
279             _not_send: NotThreadSafe,
280         }
281     }
282 }
283