Skip to content

Commit bbaea47

Browse files
hoshinolinajannau
authored andcommitted
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 <lina@asahilina.net>
1 parent 17b9af3 commit bbaea47

6 files changed

Lines changed: 43 additions & 15 deletions

File tree

rust/kernel/sync.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ pub use arc::{Arc, ArcBorrow, UniqueArc};
2222
pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
2323
pub use lock::mutex::{new_mutex, Mutex};
2424
pub use lock::spinlock::{new_spinlock, SpinLock};
25-
pub use lockdep::LockClassKey;
25+
pub use lockdep::{LockClassKey, StaticLockClassKey};
2626
pub use locked_by::LockedBy;
2727

28-
impl Default for LockClassKey {
28+
impl Default for StaticLockClassKey {
2929
fn default() -> Self {
3030
Self::new()
3131
}
@@ -36,8 +36,8 @@ impl Default for LockClassKey {
3636
#[macro_export]
3737
macro_rules! static_lock_class {
3838
() => {{
39-
static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
40-
&CLASS
39+
static CLASS: $crate::sync::StaticLockClassKey = $crate::sync::StaticLockClassKey::new();
40+
CLASS.key()
4141
}};
4242
}
4343

rust/kernel/sync/condvar.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ unsafe impl Sync for CondVar {}
101101

102102
impl CondVar {
103103
/// Constructs a new condvar initialiser.
104-
pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
104+
pub fn new(name: &'static CStr, key: LockClassKey) -> impl PinInit<Self> {
105105
pin_init!(Self {
106106
_pin: PhantomPinned,
107107
// 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
@@ -114,7 +114,7 @@ unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
114114

115115
impl<T, B: Backend> Lock<T, B> {
116116
/// Constructs a new lock initialiser.
117-
pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
117+
pub fn new(t: T, name: &'static CStr, key: LockClassKey) -> impl PinInit<Self> {
118118
pin_init!(Self {
119119
data: UnsafeCell::new(t),
120120
_pin: PhantomPinned,
@@ -130,7 +130,7 @@ impl<T, B: Backend> Lock<T, B> {
130130
pub fn pin_init<E>(
131131
t: impl PinInit<T, E>,
132132
name: &'static CStr,
133-
key: &'static LockClassKey,
133+
key: LockClassKey,
134134
) -> impl PinInit<Self, E>
135135
where
136136
E: core::convert::From<core::convert::Infallible>,

rust/kernel/sync/lockdep.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +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 {}

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/workqueue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ unsafe impl<T: ?Sized, const ID: u64> Sync for Work<T, ID> {}
366366
impl<T: ?Sized, const ID: u64> Work<T, ID> {
367367
/// Creates a new instance of [`Work`].
368368
#[inline]
369-
pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self>
369+
pub fn new(name: &'static CStr, key: LockClassKey) -> impl PinInit<Self>
370370
where
371371
T: WorkItem<ID>,
372372
{

0 commit comments

Comments
 (0)