xref: /linux/rust/kernel/sync/lock/spinlock.rs (revision 5967f4df55521de596cbe34e0c0c96e962ef3f2e)
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`.
6 use super::*;
7 use crate::prelude::*;
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]
14 macro_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 }
20 pub 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
87 pub type SpinLock<T> = Lock<T, SpinLockBackend>;
88 
89 /// A kernel `spinlock_t` lock backend.
90 pub 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.
96 pub 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.
100 unsafe 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]
153 macro_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 }
159 pub use new_spinlock_irq;
160 
161 /// A variant of `SpinLock` that ensures interrupts are disabled in the critical section.
162 ///
163 /// For more info on spinlocks, see [`SpinLock`]. For more information on interrupts,
164 /// [see the interrupt module](kernel::interrupt).
165 ///
166 /// # Examples
167 ///
168 /// The following example shows how to declare, allocate initialise and access a struct (`Example`)
169 /// that contains an inner struct (`Inner`) that is protected by a spinlock that requires local
170 /// processor interrupts to be disabled.
171 ///
172 /// ```
173 /// use kernel::sync::{new_spinlock_irq, SpinLockIrq};
174 ///
175 /// struct Inner {
176 ///     a: u32,
177 ///     b: u32,
178 /// }
179 ///
180 /// #[pin_data]
181 /// struct Example {
182 ///     #[pin]
183 ///     c: SpinLockIrq<Inner>,
184 ///     #[pin]
185 ///     d: SpinLockIrq<Inner>,
186 /// }
187 ///
188 /// impl Example {
189 ///     fn new() -> impl PinInit<Self> {
190 ///         pin_init!(Self {
191 ///             c <- new_spinlock_irq!(Inner { a: 0, b: 10 }),
192 ///             d <- new_spinlock_irq!(Inner { a: 20, b: 30 }),
193 ///         })
194 ///     }
195 /// }
196 ///
197 /// // Allocate a boxed `Example`
198 /// let e = KBox::pin_init(Example::new(), GFP_KERNEL)?;
199 ///
200 /// // Accessing an `Example` from a context where interrupts may not be disabled already.
201 /// let c_guard = e.c.lock(); // interrupts are disabled now, +1 interrupt disable refcount
202 /// let d_guard = e.d.lock(); // no interrupt state change, +1 interrupt disable refcount
203 ///
204 /// assert_eq!(c_guard.a, 0);
205 /// assert_eq!(c_guard.b, 10);
206 /// assert_eq!(d_guard.a, 20);
207 /// assert_eq!(d_guard.b, 30);
208 ///
209 /// drop(c_guard); // Dropping c_guard will not re-enable interrupts just yet, since d_guard is
210 ///                // still in scope.
211 /// drop(d_guard); // Last interrupt disable reference dropped here, so interrupts are re-enabled
212 ///                // now
213 /// # Ok::<(), Error>(())
214 /// ```
215 ///
216 /// [`lock()`]: SpinLockIrq::lock
217 pub type SpinLockIrq<T> = super::Lock<T, SpinLockIrqBackend>;
218 
219 /// A kernel `spinlock_t` lock backend that can only be acquired in interrupt disabled contexts.
220 pub struct SpinLockIrqBackend;
221 
222 /// A [`Guard`] acquired from locking a [`SpinLockIrq`] using [`lock()`].
223 ///
224 /// This is simply a type alias for a [`Guard`] returned from locking a [`SpinLockIrq`] using
225 /// [`lock()`]. It will unlock the [`SpinLockIrq`] and decrement the local processor's interrupt
226 /// disablement refcount upon being dropped.
227 ///
228 /// [`lock()`]: SpinLockIrq::lock
229 pub type SpinLockIrqGuard<'a, T> = Guard<'a, T, SpinLockIrqBackend>;
230 
231 // SAFETY: The underlying kernel `spinlock_t` object ensures mutual exclusion. `relock` uses the
232 // default implementation that always calls the same locking method.
233 unsafe impl Backend for SpinLockIrqBackend {
234     type State = bindings::spinlock_t;
235     type GuardState = ();
236 
237     #[inline]
238     unsafe fn init(
239         ptr: *mut Self::State,
240         name: *const crate::ffi::c_char,
241         key: *mut bindings::lock_class_key,
242     ) {
243         // SAFETY: The safety requirements ensure that `ptr` is valid for writes, and `name` and
244         // `key` are valid for read indefinitely.
245         unsafe { bindings::__spin_lock_init(ptr, name, key) }
246     }
247 
248     #[inline]
249     unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState {
250         // SAFETY: The safety requirements of this function ensure that `ptr` points to valid
251         // memory, and that it has been initialised before.
252         unsafe { bindings::spin_lock_irq_disable(ptr) }
253     }
254 
255     #[inline]
256     unsafe fn unlock(ptr: *mut Self::State, _guard_state: &Self::GuardState) {
257         // SAFETY: The safety requirements of this function ensure that `ptr` is valid and that the
258         // caller is the owner of the spinlock.
259         unsafe { bindings::spin_unlock_irq_enable(ptr) }
260     }
261 
262     #[inline]
263     unsafe fn try_lock(ptr: *mut Self::State) -> Option<Self::GuardState> {
264         // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use.
265         let result = unsafe { bindings::spin_trylock_irq_disable(ptr) };
266 
267         if result != 0 {
268             Some(())
269         } else {
270             None
271         }
272     }
273 
274     #[inline]
275     unsafe fn assert_is_held(ptr: *mut Self::State) {
276         // SAFETY: The `ptr` pointer is guaranteed to be valid and initialized before use.
277         unsafe { bindings::spin_assert_is_held(ptr) }
278     }
279 }
280 
281 #[kunit_tests(rust_spinlock_irq_condvar)]
282 mod tests {
283     use super::*;
284     use crate::{
285         sync::*,
286         workqueue::{
287             self,
288             impl_has_work,
289             new_work,
290             Work,
291             WorkItem, //
292         },
293     };
294 
295     struct TestState {
296         value: u32,
297         waiter_ready: bool,
298     }
299 
300     #[pin_data]
301     struct Test {
302         #[pin]
303         state: SpinLockIrq<TestState>,
304 
305         #[pin]
306         state_changed: CondVar,
307 
308         #[pin]
309         waiter_state_changed: CondVar,
310 
311         #[pin]
312         wait_work: Work<Self>,
313     }
314 
315     impl_has_work! {
316         impl HasWork<Self> for Test { self.wait_work }
317     }
318 
319     impl Test {
320         pub(crate) fn new() -> Result<Arc<Self>> {
321             Arc::try_pin_init(
322                 try_pin_init!(
323                     Self {
324                         state <- new_spinlock_irq!(TestState {
325                             value: 1,
326                             waiter_ready: false
327                         }),
328                         state_changed <- new_condvar!(),
329                         waiter_state_changed <- new_condvar!(),
330                         wait_work <- new_work!("IrqCondvarTest::wait_work")
331                     }
332                 ),
333                 GFP_KERNEL,
334             )
335         }
336     }
337 
338     impl WorkItem for Test {
339         type Pointer = Arc<Self>;
340 
341         fn run(this: Arc<Self>) {
342             // Wait for the test to be ready to wait for us
343             let mut state = this.state.lock();
344 
345             // Make sure the interrupts actually turned off
346             // SAFETY: It's always safe to call `lockdep_assert_irqs_disabled()`
347             unsafe { bindings::lockdep_assert_irqs_disabled() };
348 
349             while !state.waiter_ready {
350                 this.waiter_state_changed.wait(&mut state);
351             }
352 
353             // Deliver the exciting value update our test has been waiting for
354             state.value += 1;
355             this.state_changed.notify_sync();
356         }
357     }
358 
359     #[test]
360     fn spinlock_irq_condvar() -> Result {
361         let testdata = Test::new()?;
362 
363         let _ = workqueue::system().enqueue(testdata.clone());
364 
365         // Let the updater know when we're ready to wait
366         let mut state = testdata.state.lock();
367         state.waiter_ready = true;
368         testdata.waiter_state_changed.notify_sync();
369 
370         // Wait for the exciting value update
371         testdata.state_changed.wait(&mut state);
372         assert_eq!(state.value, 2);
373         Ok(())
374     }
375 }
376