Skip to content

Commit 212f64b

Browse files
committed
rust: sync: Replace static LockClassKey refs with a pointer wrapper
We want to be able to handle dynamic lock class creation and using pointers to things that aren't a real lock_class_key as lock classes. Doing this by casting around Rust references is difficult without accidentally invoking UB. Instead, switch LockClassKey to being a raw pointer wrapper around a lock_class_key, which means there is no UB possible on the Rust side just by creating and consuming these objects. The C code also should never actually dereference lock classes, only use their address (possibly with an offset). We still provide a dummy ZST version of this wrapper, to be used when lockdep is disabled. Signed-off-by: Asahi Lina <[email protected]>
1 parent bd102b8 commit 212f64b

6 files changed

Lines changed: 42 additions & 15 deletions

File tree

rust/kernel/sync.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ use no_lockdep as lockdep;
2020
pub use arc::{Arc, ArcBorrow, UniqueArc};
2121
pub use condvar::CondVar;
2222
pub use lock::{mutex::Mutex, spinlock::SpinLock};
23-
pub use lockdep::LockClassKey;
23+
pub use lockdep::{LockClassKey, StaticLockClassKey};
2424
pub use locked_by::LockedBy;
2525

2626
/// Defines a new static lock class and returns a pointer to it.
2727
#[doc(hidden)]
2828
#[macro_export]
2929
macro_rules! static_lock_class {
3030
() => {{
31-
static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
32-
&CLASS
31+
static CLASS: $crate::sync::StaticLockClassKey = $crate::sync::StaticLockClassKey::new();
32+
CLASS.key()
3333
}};
3434
}
3535

rust/kernel/sync/condvar.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ unsafe impl Sync for CondVar {}
9292
impl CondVar {
9393
/// Constructs a new condvar initialiser.
9494
#[allow(clippy::new_ret_no_self)]
95-
pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
95+
pub fn new(name: &'static CStr, key: LockClassKey) -> impl PinInit<Self> {
9696
pin_init!(Self {
9797
_pin: PhantomPinned,
9898
// SAFETY: `slot` is valid while the closure is called and both `name` and `key` have

rust/kernel/sync/lock.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
103103
impl<T, B: Backend> Lock<T, B> {
104104
/// Constructs a new lock initialiser.
105105
#[allow(clippy::new_ret_no_self)]
106-
pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
106+
pub fn new(t: T, name: &'static CStr, key: LockClassKey) -> impl PinInit<Self> {
107107
pin_init!(Self {
108108
data: UnsafeCell::new(t),
109109
_pin: PhantomPinned,
@@ -119,7 +119,7 @@ impl<T, B: Backend> Lock<T, B> {
119119
pub fn pin_init<E>(
120120
t: impl PinInit<T, E>,
121121
name: &'static CStr,
122-
key: &'static LockClassKey,
122+
key: LockClassKey,
123123
) -> impl PinInit<Self, E>
124124
where
125125
E: core::convert::From<core::convert::Infallible>,

rust/kernel/sync/lockdep.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,36 @@ use crate::types::Opaque;
99

1010
/// Represents a lockdep class. It's a wrapper around C's `lock_class_key`.
1111
#[repr(transparent)]
12-
pub struct LockClassKey(Opaque<bindings::lock_class_key>);
12+
pub struct StaticLockClassKey(Opaque<bindings::lock_class_key>);
1313

14-
impl LockClassKey {
14+
impl StaticLockClassKey {
1515
/// Creates a new lock class key.
1616
pub const fn new() -> Self {
1717
Self(Opaque::uninit())
1818
}
1919

20+
/// Returns the lock class key reference for this static lock class.
21+
pub const fn key(&self) -> LockClassKey {
22+
LockClassKey(self.0.get())
23+
}
24+
}
25+
26+
// SAFETY: `bindings::lock_class_key` just represents an opaque memory location, and is never
27+
// actually dereferenced.
28+
unsafe impl Sync for StaticLockClassKey {}
29+
30+
/// A reference to a lock class key. This is a raw pointer to a lock_class_key,
31+
/// which is required to have a static lifetime.
32+
#[derive(Copy, Clone)]
33+
pub struct LockClassKey(*mut bindings::lock_class_key);
34+
35+
impl LockClassKey {
2036
pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key {
21-
self.0.get()
37+
self.0
2238
}
2339
}
2440

25-
// SAFETY: `bindings::lock_class_key` is designed to be used concurrently from multiple threads and
26-
// provides its own synchronization.
41+
// SAFETY: `bindings::lock_class_key` just represents an opaque memory location, and is never
42+
// actually dereferenced.
43+
unsafe impl Send for LockClassKey {}
2744
unsafe impl Sync for LockClassKey {}
28-

rust/kernel/sync/no_lockdep.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,25 @@
55
//! Takes the place of the `lockdep` module when lockdep is disabled.
66
77
/// A dummy, zero-sized lock class.
8-
pub struct LockClassKey();
8+
pub struct StaticLockClassKey();
99

10-
impl LockClassKey {
10+
impl StaticLockClassKey {
1111
/// Creates a new dummy lock class key.
1212
pub const fn new() -> Self {
1313
Self()
1414
}
1515

16+
/// Returns the lock class key reference for this static lock class.
17+
pub const fn key(&self) -> LockClassKey {
18+
LockClassKey()
19+
}
20+
}
21+
22+
/// A dummy reference to a lock class key.
23+
#[derive(Copy, Clone)]
24+
pub struct LockClassKey();
25+
26+
impl LockClassKey {
1627
pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key {
1728
core::ptr::null_mut()
1829
}

rust/kernel/types.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ impl<T> Opaque<T> {
262262
}
263263

264264
/// Returns a raw pointer to the opaque data.
265-
pub fn get(&self) -> *mut T {
265+
pub const fn get(&self) -> *mut T {
266266
UnsafeCell::raw_get(self.0.as_ptr())
267267
}
268268

0 commit comments

Comments
 (0)