Skip to content

Commit bfe9e4c

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 c782b7d commit bfe9e4c

7 files changed

Lines changed: 44 additions & 16 deletions

File tree

rust/kernel/sync.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
2424
pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy};
2525
pub use lock::mutex::{new_mutex, Mutex};
2626
pub use lock::spinlock::{new_spinlock, SpinLock};
27-
pub use lockdep::LockClassKey;
27+
pub use lockdep::{LockClassKey, StaticLockClassKey};
2828
pub use locked_by::LockedBy;
2929

30-
impl Default for LockClassKey {
30+
impl Default for StaticLockClassKey {
3131
fn default() -> Self {
3232
Self::new()
3333
}
@@ -38,8 +38,8 @@ impl Default for LockClassKey {
3838
#[macro_export]
3939
macro_rules! static_lock_class {
4040
() => {{
41-
static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
42-
&CLASS
41+
static CLASS: $crate::sync::StaticLockClassKey = $crate::sync::StaticLockClassKey::new();
42+
CLASS.key()
4343
}};
4444
}
4545

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
@@ -131,7 +131,7 @@ unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
131131

132132
impl<T, B: Backend> Lock<T, B> {
133133
/// Constructs a new lock initialiser.
134-
pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
134+
pub fn new(t: T, name: &'static CStr, key: LockClassKey) -> impl PinInit<Self> {
135135
pin_init!(Self {
136136
data: UnsafeCell::new(t),
137137
_pin: PhantomPinned,
@@ -147,7 +147,7 @@ impl<T, B: Backend> Lock<T, B> {
147147
pub fn pin_init<E>(
148148
t: impl PinInit<T, E>,
149149
name: &'static CStr,
150-
key: &'static LockClassKey,
150+
key: LockClassKey,
151151
) -> impl PinInit<Self, E>
152152
where
153153
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/sync/poll.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub struct PollCondVar {
8989

9090
impl PollCondVar {
9191
/// Constructs a new condvar initialiser.
92-
pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
92+
pub fn new(name: &'static CStr, key: LockClassKey) -> impl PinInit<Self> {
9393
pin_init!(Self {
9494
inner <- CondVar::new(name, key),
9595
})

rust/kernel/workqueue.rs

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

0 commit comments

Comments
 (0)