Skip to content

Commit 743c57a

Browse files
plinkrojeda
authored andcommitted
rust: kernel: move ARef<T> and AlwaysRefCounted to new sync::aref module
Refactor the `ARef` type and `AlwaysRefCounted` trait from `types.rs` into a new `sync/aref.rs` module: - Add `rust/kernel/sync/aref.rs` with the definitions of `ARef` and `AlwaysRefCounted`. - Remove the same type and trait definitions from `rust/kernel/types.rs`. - Update relevant files to import `ARef` and `AlwaysRefCounted` from `sync/aref.rs`. The type and trait definitions remain unchanged. Suggested-by: Benno Lossin <[email protected]> Link: #1117 Signed-off-by: Aliet Exposito Garcia <[email protected]> Reviewed-by: Fiona Behrens <[email protected]> Reviewed-by: Benno Lossin <[email protected]> Link: https://lore.kernel.org/r/[email protected] [ Rebased on top of the lints series, slightly reworded and removed unneeded `use AlwaysRefCounted` in example. - Miguel ] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent 590530e commit 743c57a

File tree

9 files changed

+169
-166
lines changed

9 files changed

+169
-166
lines changed

drivers/block/rnull.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ use kernel::{
2020
error::Result,
2121
new_mutex, pr_info,
2222
prelude::*,
23-
sync::{Arc, Mutex},
24-
types::ARef,
23+
sync::{aref::ARef, Arc, Mutex},
2524
};
2625

2726
module! {

rust/kernel/block/mq.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//! The kernel will interface with the block device driver by calling the method
2121
//! implementations of the `Operations` trait.
2222
//!
23-
//! IO requests are passed to the driver as [`kernel::types::ARef<Request>`]
23+
//! IO requests are passed to the driver as [`kernel::sync::aref::ARef<Request>`]
2424
//! instances. The `Request` type is a wrapper around the C `struct request`.
2525
//! The driver must mark end of processing by calling one of the
2626
//! `Request::end`, methods. Failure to do so can lead to deadlock or timeout
@@ -61,8 +61,8 @@
6161
//! block::mq::*,
6262
//! new_mutex,
6363
//! prelude::*,
64-
//! sync::{Arc, Mutex},
65-
//! types::{ARef, ForeignOwnable},
64+
//! sync::{aref::ARef, Arc, Mutex},
65+
//! types::ForeignOwnable,
6666
//! };
6767
//!
6868
//! struct MyBlkDevice;

rust/kernel/block/mq/operations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
block::mq::request::RequestDataWrapper,
1010
block::mq::Request,
1111
error::{from_result, Result},
12-
types::ARef,
12+
sync::aref::ARef,
1313
};
1414
use core::{marker::PhantomData, sync::atomic::AtomicU64, sync::atomic::Ordering};
1515

rust/kernel/block/mq/request.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use crate::{
88
bindings,
99
block::mq::Operations,
1010
error::Result,
11-
types::{ARef, AlwaysRefCounted, Opaque},
11+
sync::aref::{ARef, AlwaysRefCounted},
12+
types::Opaque,
1213
};
1314
use core::{
1415
marker::PhantomData,

rust/kernel/device.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44
//!
55
//! C header: [`include/linux/device.h`](srctree/include/linux/device.h)
66
7-
use crate::{
8-
bindings,
9-
types::{ARef, Opaque},
10-
};
7+
use crate::{bindings, sync::aref::ARef, types::Opaque};
8+
119
use core::ptr;
1210

1311
/// A reference-counted device.
@@ -85,7 +83,7 @@ impl Device {
8583
}
8684

8785
// SAFETY: Instances of `Device` are always reference-counted.
88-
unsafe impl crate::types::AlwaysRefCounted for Device {
86+
unsafe impl crate::sync::aref::AlwaysRefCounted for Device {
8987
fn inc_ref(&self) {
9088
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
9189
unsafe { bindings::get_device(self.as_raw()) };

rust/kernel/sync.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use crate::types::Opaque;
99

1010
mod arc;
11+
pub mod aref;
1112
mod condvar;
1213
pub mod lock;
1314
mod locked_by;

rust/kernel/sync/aref.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Types and utilities for managing always-reference-counted objects.
4+
5+
use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
6+
7+
/// Types that are _always_ reference counted.
8+
///
9+
/// It allows such types to define their own custom ref increment and decrement functions.
10+
/// Additionally, it allows users to convert from a shared reference `&T` to an owned reference
11+
/// [`ARef<T>`].
12+
///
13+
/// This is usually implemented by wrappers to existing structures on the C side of the code. For
14+
/// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to create reference-counted
15+
/// instances of a type.
16+
///
17+
/// # Safety
18+
///
19+
/// Implementers must ensure that increments to the reference count keep the object alive in memory
20+
/// at least until matching decrements are performed.
21+
///
22+
/// Implementers must also ensure that all instances are reference-counted. (Otherwise they
23+
/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object
24+
/// alive.)
25+
pub unsafe trait AlwaysRefCounted {
26+
/// Increments the reference count on the object.
27+
fn inc_ref(&self);
28+
29+
/// Decrements the reference count on the object.
30+
///
31+
/// Frees the object when the count reaches zero.
32+
///
33+
/// # Safety
34+
///
35+
/// Callers must ensure that there was a previous matching increment to the reference count,
36+
/// and that the object is no longer used after its reference count is decremented (as it may
37+
/// result in the object being freed), unless the caller owns another increment on the refcount
38+
/// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls
39+
/// [`AlwaysRefCounted::dec_ref`] once).
40+
unsafe fn dec_ref(obj: NonNull<Self>);
41+
}
42+
43+
/// An owned reference to an always-reference-counted object.
44+
///
45+
/// The object's reference count is automatically decremented when an instance of [`ARef`] is
46+
/// dropped. It is also automatically incremented when a new instance is created via
47+
/// [`ARef::clone`].
48+
///
49+
/// # Invariants
50+
///
51+
/// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In
52+
/// particular, the [`ARef`] instance owns an increment on the underlying object's reference count.
53+
pub struct ARef<T: AlwaysRefCounted> {
54+
ptr: NonNull<T>,
55+
_p: PhantomData<T>,
56+
}
57+
58+
// SAFETY: It is safe to send `ARef<T>` to another thread when the underlying `T` is `Sync` because
59+
// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
60+
// `T` to be `Send` because any thread that has an `ARef<T>` may ultimately access `T` using a
61+
// mutable reference, for example, when the reference count reaches zero and `T` is dropped.
62+
unsafe impl<T: AlwaysRefCounted + Sync + Send> Send for ARef<T> {}
63+
64+
// SAFETY: It is safe to send `&ARef<T>` to another thread when the underlying `T` is `Sync`
65+
// because it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally,
66+
// it needs `T` to be `Send` because any thread that has a `&ARef<T>` may clone it and get an
67+
// `ARef<T>` on that thread, so the thread may ultimately access `T` using a mutable reference, for
68+
// example, when the reference count reaches zero and `T` is dropped.
69+
unsafe impl<T: AlwaysRefCounted + Sync + Send> Sync for ARef<T> {}
70+
71+
impl<T: AlwaysRefCounted> ARef<T> {
72+
/// Creates a new instance of [`ARef`].
73+
///
74+
/// It takes over an increment of the reference count on the underlying object.
75+
///
76+
/// # Safety
77+
///
78+
/// Callers must ensure that the reference count was incremented at least once, and that they
79+
/// are properly relinquishing one increment. That is, if there is only one increment, callers
80+
/// must not use the underlying object anymore -- it is only safe to do so via the newly
81+
/// created [`ARef`].
82+
pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
83+
// INVARIANT: The safety requirements guarantee that the new instance now owns the
84+
// increment on the refcount.
85+
Self {
86+
ptr,
87+
_p: PhantomData,
88+
}
89+
}
90+
91+
/// Consumes the `ARef`, returning a raw pointer.
92+
///
93+
/// This function does not change the refcount. After calling this function, the caller is
94+
/// responsible for the refcount previously managed by the `ARef`.
95+
///
96+
/// # Examples
97+
///
98+
/// ```
99+
/// use core::ptr::NonNull;
100+
/// use kernel::sync::aref::{ARef, AlwaysRefCounted};
101+
///
102+
/// struct Empty {}
103+
///
104+
/// # // SAFETY: TODO.
105+
/// unsafe impl AlwaysRefCounted for Empty {
106+
/// fn inc_ref(&self) {}
107+
/// unsafe fn dec_ref(_obj: NonNull<Self>) {}
108+
/// }
109+
///
110+
/// let mut data = Empty {};
111+
/// let ptr = NonNull::<Empty>::new(&mut data as *mut _).unwrap();
112+
/// # // SAFETY: TODO.
113+
/// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) };
114+
/// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref);
115+
///
116+
/// assert_eq!(ptr, raw_ptr);
117+
/// ```
118+
pub fn into_raw(me: Self) -> NonNull<T> {
119+
ManuallyDrop::new(me).ptr
120+
}
121+
}
122+
123+
impl<T: AlwaysRefCounted> Clone for ARef<T> {
124+
fn clone(&self) -> Self {
125+
self.inc_ref();
126+
// SAFETY: We just incremented the refcount above.
127+
unsafe { Self::from_raw(self.ptr) }
128+
}
129+
}
130+
131+
impl<T: AlwaysRefCounted> Deref for ARef<T> {
132+
type Target = T;
133+
134+
fn deref(&self) -> &Self::Target {
135+
// SAFETY: The type invariants guarantee that the object is valid.
136+
unsafe { self.ptr.as_ref() }
137+
}
138+
}
139+
140+
impl<T: AlwaysRefCounted> From<&T> for ARef<T> {
141+
fn from(b: &T) -> Self {
142+
b.inc_ref();
143+
// SAFETY: We just incremented the refcount above.
144+
unsafe { Self::from_raw(NonNull::from(b)) }
145+
}
146+
}
147+
148+
impl<T: AlwaysRefCounted> Drop for ARef<T> {
149+
fn drop(&mut self) {
150+
// SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
151+
// decrement.
152+
unsafe { T::dec_ref(self.ptr) };
153+
}
154+
}

rust/kernel/task.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ macro_rules! current {
6161
/// incremented when creating `State` and decremented when it is dropped:
6262
///
6363
/// ```
64-
/// use kernel::{task::Task, types::ARef};
64+
/// use kernel::{task::Task, sync::aref::ARef};
6565
///
6666
/// struct State {
6767
/// creator: ARef<Task>,
@@ -164,7 +164,7 @@ impl Task {
164164
}
165165

166166
// SAFETY: The type invariants guarantee that `Task` is always refcounted.
167-
unsafe impl crate::types::AlwaysRefCounted for Task {
167+
unsafe impl crate::sync::aref::AlwaysRefCounted for Task {
168168
fn inc_ref(&self) {
169169
// SAFETY: The existence of a shared reference means that the refcount is nonzero.
170170
unsafe { bindings::get_task_struct(self.0.get()) };

0 commit comments

Comments
 (0)