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 7 use 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)] 17 pub 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. 24 unsafe 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. 28 unsafe impl Sync for LockClassKey {} 29 30 impl 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] 93 impl 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] 117 macro_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 } 126 pub 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] 132 macro_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. 142 pub const LD_WAIT_INV: u8 = bindings::lockdep_wait_type_LD_WAIT_INV as u8; 143 /// Spin loops, `raw_spinlock_t` etc 144 pub 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)] 150 pub(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 } 162