Skip to main content

kernel/sync/
lockdep.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Utilities related to lockdep.
4//!
5//! C headers: [`include/linux/lockdep.h`](srctree/include/linux/lockdep.h)
6
7use crate::{
8    prelude::*,
9    types::Opaque, //
10};
11
12/// Represents a lockdep class.
13///
14/// Wraps the kernel's `struct lock_class_key`.
15#[repr(transparent)]
16#[pin_data(PinnedDrop)]
17pub struct LockClassKey {
18    #[pin]
19    inner: Opaque<bindings::lock_class_key>,
20}
21
22// SAFETY: Unregistering a lock class key from a different thread than where it was registered is
23// allowed.
24unsafe impl Send for LockClassKey {}
25
26// SAFETY: `bindings::lock_class_key` is designed to be used concurrently from multiple threads and
27// provides its own synchronization.
28unsafe impl Sync for LockClassKey {}
29
30impl LockClassKey {
31    /// Initializes a statically allocated lock class key.
32    ///
33    /// This is usually used indirectly through the [`static_lock_class!`] macro. See its
34    /// documentation for more information.
35    ///
36    /// # Safety
37    ///
38    /// * Before using the returned value, it must be pinned in a static memory location.
39    /// * The destructor must never run on the returned `LockClassKey`.
40    pub const unsafe fn new_static() -> Self {
41        LockClassKey {
42            inner: Opaque::uninit(),
43        }
44    }
45
46    /// Initializes a dynamically allocated lock class key.
47    ///
48    /// In the common case of using a statically allocated lock class key, the
49    /// [`static_lock_class!`] macro should be used instead.
50    ///
51    /// # Examples
52    ///
53    /// ```
54    /// use kernel::alloc::KBox;
55    /// use kernel::types::ForeignOwnable;
56    /// use kernel::sync::{LockClassKey, SpinLock};
57    /// use pin_init::stack_pin_init;
58    ///
59    /// let key = KBox::pin_init(LockClassKey::new_dynamic(), GFP_KERNEL)?;
60    /// let key_ptr = key.into_foreign();
61    ///
62    /// {
63    ///     stack_pin_init!(let num: SpinLock<u32> = SpinLock::new(
64    ///         0,
65    ///         c"my_spinlock",
66    ///         // SAFETY: `key_ptr` is returned by the above `into_foreign()`, whose
67    ///         // `from_foreign()` has not yet been called.
68    ///         unsafe { <Pin<KBox<LockClassKey>> as ForeignOwnable>::borrow(key_ptr) }
69    ///     ));
70    /// }
71    ///
72    /// // SAFETY: We dropped `num`, the only use of the key, so the result of the previous
73    /// // `borrow` has also been dropped. Thus, it's safe to use from_foreign.
74    /// unsafe { drop(<Pin<KBox<LockClassKey>> as ForeignOwnable>::from_foreign(key_ptr)) };
75    /// # Ok::<(), Error>(())
76    /// ```
77    pub fn new_dynamic() -> impl PinInit<Self> {
78        pin_init!(Self {
79            // SAFETY: lockdep_register_key expects an uninitialized block of memory
80            inner <- Opaque::ffi_init(|slot| unsafe { bindings::lockdep_register_key(slot) })
81        })
82    }
83
84    /// Returns a raw pointer to the inner C struct.
85    ///
86    /// It is up to the caller to use the raw pointer correctly.
87    pub fn as_ptr(&self) -> *mut bindings::lock_class_key {
88        self.inner.get()
89    }
90}
91
92#[pinned_drop]
93impl PinnedDrop for LockClassKey {
94    fn drop(self: Pin<&mut Self>) {
95        // SAFETY: `self.as_ptr()` was registered with lockdep and `self` is pinned, so the address
96        // hasn't changed. Thus, it's safe to pass it to unregister.
97        unsafe { bindings::lockdep_unregister_key(self.as_ptr()) }
98    }
99}
100
101/// Defines a new static lock class and returns a pointer to it.
102///
103/// # Examples
104///
105/// ```
106/// use kernel::sync::{static_lock_class, Arc, SpinLock};
107///
108/// fn new_locked_int() -> Result<Arc<SpinLock<u32>>> {
109///     Arc::pin_init(SpinLock::new(
110///         42,
111///         c"new_locked_int",
112///         static_lock_class!(),
113///     ), GFP_KERNEL)
114/// }
115/// ```
116#[macro_export]
117macro_rules! static_lock_class {
118    () => {{
119        static CLASS: $crate::sync::LockClassKey =
120            // SAFETY: The returned `LockClassKey` is stored in static memory and we pin it. Drop
121            // never runs on a static global.
122            unsafe { $crate::sync::LockClassKey::new_static() };
123        $crate::prelude::Pin::static_ref(&CLASS)
124    }};
125}
126pub use static_lock_class;
127
128/// Returns the given string, if one is provided, otherwise generates one based on the source code
129/// location.
130#[doc(hidden)]
131#[macro_export]
132macro_rules! optional_name {
133    () => {
134        $crate::c_str!(::core::concat!(::core::file!(), ":", ::core::line!()))
135    };
136    ($name:literal) => {
137        $crate::c_str!($name)
138    };
139}
140
141/// Not checked, catch all.
142pub const LD_WAIT_INV: u8 = bindings::lockdep_wait_type_LD_WAIT_INV as u8;
143/// Spin loops, `raw_spinlock_t` etc
144pub const LD_WAIT_SPIN: u8 = bindings::lockdep_wait_type_LD_WAIT_SPIN as u8;
145
146/// Helper for declaring a raw `struct lockdep_map` for locks in statics.
147///
148/// It's up to the caller to use the returned `struct lockdep_map` correctly.
149#[cfg(CONFIG_DEBUG_LOCK_ALLOC)]
150pub(crate) const fn raw_lockdep_map(
151    name: &'static CStr,
152    wait_type_inner: u8,
153    wait_type_outer: u8,
154) -> bindings::lockdep_map {
155    // SAFETY: All zeros is valid for this type.
156    let mut map: bindings::lockdep_map = unsafe { core::mem::zeroed() };
157    map.name = kernel::str::as_char_ptr_in_const_context(name);
158    map.wait_type_inner = wait_type_inner;
159    map.wait_type_outer = wait_type_outer;
160    map
161}