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}