Skip to content

Commit 50f2249

Browse files
authored
Merge pull request #292 from TheSven73/rust-for-linux-pin-wrapper
Improve safety with fallible version of `pointer::pin()`
2 parents 0c7a4fa + 5a67315 commit 50f2249

File tree

4 files changed

+37
-11
lines changed

4 files changed

+37
-11
lines changed

rust/kernel/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub mod file_operations;
4747
pub mod miscdev;
4848
pub mod pages;
4949
pub mod str;
50+
pub mod traits;
5051

5152
pub mod linked_list;
5253
mod raw_list;

rust/kernel/prelude.rs

+2
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ pub use super::{pr_alert, pr_cont, pr_crit, pr_emerg, pr_err, pr_info, pr_notice
2222
pub use super::static_assert;
2323

2424
pub use super::{KernelModule, Result};
25+
26+
pub use crate::traits::TryPin;

rust/kernel/traits.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Traits useful to drivers, and their implementations for common types.
4+
5+
use core::{ops::Deref, pin::Pin};
6+
7+
use alloc::{alloc::AllocError, sync::Arc};
8+
9+
/// Trait which provides a fallible version of `pin()` for pointer types.
10+
///
11+
/// Common pointer types which implement a `pin()` method include [`Box`], [`Arc`] and [`Rc`].
12+
pub trait TryPin<P: Deref> {
13+
/// Constructs a new `Pin<pointer<T>>`. If `T` does not implement [`Unpin`], then data
14+
/// will be pinned in memory and unable to be moved. An error will be returned
15+
/// if allocation fails.
16+
fn try_pin(data: P::Target) -> core::result::Result<Pin<P>, AllocError>;
17+
}
18+
19+
impl<T> TryPin<Arc<T>> for Arc<T> {
20+
fn try_pin(data: T) -> core::result::Result<Pin<Arc<T>>, AllocError> {
21+
// SAFETY: the data `T` is exposed only through a `Pin<Arc<T>>`, which
22+
// does not allow data to move out of the `Arc`. Therefore it can
23+
// never be moved.
24+
Ok(unsafe { Pin::new_unchecked(Arc::try_new(data)?) })
25+
}
26+
}

samples/rust/rust_miscdev.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,16 @@ struct SharedState {
3939

4040
impl SharedState {
4141
fn try_new() -> Result<Pin<Arc<Self>>> {
42-
// SAFETY: `state` is pinning `Arc`, which implements `Unpin`.
43-
let state = unsafe {
44-
Pin::new_unchecked(Arc::try_new(Self {
45-
// SAFETY: `condvar_init!` is called below.
46-
state_changed: CondVar::new(),
47-
// SAFETY: `mutex_init!` is called below.
48-
inner: Mutex::new(SharedStateInner { token_count: 0 }),
49-
})?)
50-
};
51-
// SAFETY: `state_changed` is pinned behind `Arc`.
42+
let state = Arc::try_pin(Self {
43+
// SAFETY: `condvar_init!` is called below.
44+
state_changed: unsafe { CondVar::new() },
45+
// SAFETY: `mutex_init!` is called below.
46+
inner: unsafe { Mutex::new(SharedStateInner { token_count: 0 }) },
47+
})?;
48+
// SAFETY: `state_changed` is pinned behind `Pin<Arc>`.
5249
let state_changed = unsafe { Pin::new_unchecked(&state.state_changed) };
5350
kernel::condvar_init!(state_changed, "SharedState::state_changed");
54-
// SAFETY: `inner` is pinned behind `Arc`.
51+
// SAFETY: `inner` is pinned behind `Pin<Arc>`.
5552
let inner = unsafe { Pin::new_unchecked(&state.inner) };
5653
kernel::mutex_init!(inner, "SharedState::inner");
5754
Ok(state)

0 commit comments

Comments
 (0)