Skip to content

Commit c708e80

Browse files
authored
Merge pull request torvalds#570 from wedsonaf/device-data
rust: add `device::Data`.
2 parents 8a4fed2 + 9d7d482 commit c708e80

File tree

1 file changed

+131
-1
lines changed

1 file changed

+131
-1
lines changed

rust/kernel/device.rs

+131-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,17 @@
44
//!
55
//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
66
7-
use crate::{bindings, str::CStr};
7+
use crate::{
8+
bindings,
9+
revocable::{Revocable, RevocableGuard},
10+
str::CStr,
11+
sync::{NeedsLockClass, RevocableMutex, RevocableMutexGuard, UniqueRef},
12+
Result,
13+
};
14+
use core::{
15+
ops::{Deref, DerefMut},
16+
pin::Pin,
17+
};
818

919
/// A raw device.
1020
///
@@ -74,3 +84,123 @@ impl Drop for Device {
7484
unsafe { bindings::put_device(self.ptr) };
7585
}
7686
}
87+
88+
/// Device data.
89+
///
90+
/// When a device is removed (for whatever reason, for example, because the device was unplugged or
91+
/// because the user decided to unbind the driver), the driver is given a chance to clean its state
92+
/// up, and all io resources should ideally not be used anymore.
93+
///
94+
/// However, the device data is reference-counted because other subsystems hold pointers to it. So
95+
/// some device state must be freed and not used anymore, while others must remain accessible.
96+
///
97+
/// This struct separates the device data into three categories:
98+
/// 1. Registrations: are destroyed when the device is removed, but before the io resources
99+
/// become inaccessible.
100+
/// 2. Io resources: are available until the device is removed.
101+
/// 3. General data: remain available as long as the ref count is nonzero.
102+
///
103+
/// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not
104+
/// explicitly called by the device drivers.
105+
pub struct Data<T, U, V> {
106+
registrations: RevocableMutex<T>,
107+
resources: Revocable<U>,
108+
general: V,
109+
}
110+
111+
/// Safely creates an new reference-counted instance of [`Data`].
112+
#[doc(hidden)]
113+
#[macro_export]
114+
macro_rules! new_device_data {
115+
($reg:expr, $res:expr, $gen:expr, $name:literal) => {{
116+
static mut CLASS1: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
117+
core::mem::MaybeUninit::uninit();
118+
static mut CLASS2: core::mem::MaybeUninit<$crate::bindings::lock_class_key> =
119+
core::mem::MaybeUninit::uninit();
120+
let regs = $reg;
121+
let res = $res;
122+
let gen = $gen;
123+
let name = $crate::c_str!($name);
124+
// SAFETY: `CLASS1` and `CLASS2` are never used by Rust code directly; the C portion of the
125+
// kernel may change it though.
126+
unsafe {
127+
$crate::device::Data::try_new(
128+
regs,
129+
res,
130+
gen,
131+
name,
132+
CLASS1.as_mut_ptr(),
133+
CLASS2.as_mut_ptr(),
134+
)
135+
}
136+
}};
137+
}
138+
139+
impl<T, U, V> Data<T, U, V> {
140+
/// Creates a new instance of `Data`.
141+
///
142+
/// It is recommended that the [`new_device_data`] macro be used as it automatically creates
143+
/// the lock classes.
144+
///
145+
/// # Safety
146+
///
147+
/// `key1` and `key2` must point to valid memory locations and remain valid until `self` is
148+
/// dropped.
149+
pub unsafe fn try_new(
150+
registrations: T,
151+
resources: U,
152+
general: V,
153+
name: &'static CStr,
154+
key1: *mut bindings::lock_class_key,
155+
key2: *mut bindings::lock_class_key,
156+
) -> Result<Pin<UniqueRef<Self>>> {
157+
let mut ret = Pin::from(UniqueRef::try_new(Self {
158+
// SAFETY: We call `RevocableMutex::init` below.
159+
registrations: unsafe { RevocableMutex::new(registrations) },
160+
resources: Revocable::new(resources),
161+
general,
162+
})?);
163+
164+
// SAFETY: `Data::registrations` is pinned when `Data` is.
165+
let pinned = unsafe { ret.as_mut().map_unchecked_mut(|d| &mut d.registrations) };
166+
167+
// SAFETY: The safety requirements of this function satisfy those of `RevocableMutex::init`.
168+
unsafe { pinned.init(name, key1, key2) };
169+
Ok(ret)
170+
}
171+
172+
/// Returns the resources if they're still available.
173+
pub fn resources(&self) -> Option<RevocableGuard<'_, U>> {
174+
self.resources.try_access()
175+
}
176+
177+
/// Returns the locked registrations if they're still available.
178+
pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
179+
self.registrations.try_lock()
180+
}
181+
}
182+
183+
impl<T, U, V> crate::driver::DeviceRemoval for Data<T, U, V> {
184+
fn device_remove(&self) {
185+
// We revoke the registrations first so that resources are still available to them during
186+
// unregistration.
187+
self.registrations.revoke();
188+
189+
// Release resources now. General data remains available.
190+
self.resources.revoke();
191+
}
192+
}
193+
194+
impl<T, U, V> Deref for Data<T, U, V> {
195+
type Target = V;
196+
197+
fn deref(&self) -> &V {
198+
&self.general
199+
}
200+
}
201+
202+
impl<T, U, V> DerefMut for Data<T, U, V> {
203+
fn deref_mut(&mut self) -> &mut V {
204+
&mut self.general
205+
}
206+
}

0 commit comments

Comments
 (0)