[RFC PATCH 06/11] rust: add device::Data

From: Danilo Krummrich
Date: Mon May 20 2024 - 13:29:01 EST


From: Wedson Almeida Filho <wedsonaf@xxxxxxxxx>

Add a generic type `device::Data` to represent driver specific data bound
to a device.

`device::Data` also stores and allows access to registrations, which are
revoked automatically when the corresponding device is unbound, even if
the `device::Data`'s reference count is non-zero.

Signed-off-by: Wedson Almeida Filho <wedsonaf@xxxxxxxxx>
Co-developed-by: Danilo Krummrich <dakr@xxxxxxxxxx>
Signed-off-by: Danilo Krummrich <dakr@xxxxxxxxxx>
---
rust/kernel/device.rs | 103 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 102 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index fafec70effb6..b1c3f7a0d623 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -4,11 +4,24 @@
//!
//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)

+use macros::pin_data;
+
use crate::{
+ alloc::flags::*,
bindings,
+ error::Result,
+ init::InPlaceInit,
+ init::PinInit,
+ pin_init,
+ str::CStr,
+ sync::{LockClassKey, RevocableMutex, RevocableMutexGuard, UniqueArc},
types::{ARef, Opaque},
};
-use core::ptr;
+use core::{
+ ops::{Deref, DerefMut},
+ pin::Pin,
+ ptr,
+};

/// A ref-counted device.
///
@@ -74,3 +87,91 @@ unsafe impl Send for Device {}
// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
// from any thread.
unsafe impl Sync for Device {}
+
+/// Device data.
+///
+/// When a device is unbound (for whatever reason, for example, because the device was unplugged or
+/// because the user decided to unbind the driver), the driver is given a chance to clean up its
+/// state.
+///
+/// The device data is reference-counted because other subsystems may hold pointers to it; some
+/// device state must be freed and not used anymore, while others must remain accessible.
+///
+/// This struct separates the device data into two categories:
+/// 1. Registrations: are destroyed when the device is removed.
+/// 2. General data: remain available as long as the reference count is nonzero.
+///
+/// This struct implements the `DeviceRemoval` trait such that `registrations` can be revoked when
+/// the device is unbound.
+#[pin_data]
+pub struct Data<T, U> {
+ #[pin]
+ registrations: RevocableMutex<T>,
+ #[pin]
+ general: U,
+}
+
+/// Safely creates an new reference-counted instance of [`Data`].
+#[doc(hidden)]
+#[macro_export]
+macro_rules! new_device_data {
+ ($reg:expr, $gen:expr, $name:literal) => {{
+ static CLASS1: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+ let regs = $reg;
+ let gen = $gen;
+ let name = $crate::c_str!($name);
+ $crate::device::Data::try_new(regs, gen, name, &CLASS1)
+ }};
+}
+
+impl<T, U> Data<T, U> {
+ /// Creates a new instance of `Data`.
+ ///
+ /// It is recommended that the [`new_device_data`] macro be used as it automatically creates
+ /// the lock classes.
+ pub fn try_new(
+ registrations: T,
+ general: impl PinInit<U>,
+ name: &'static CStr,
+ key1: &'static LockClassKey,
+ ) -> Result<Pin<UniqueArc<Self>>> {
+ let ret = UniqueArc::pin_init(
+ pin_init!(Self {
+ registrations <- RevocableMutex::new(
+ registrations,
+ name,
+ key1,
+ ),
+ general <- general,
+ }),
+ GFP_KERNEL,
+ )?;
+
+ Ok(ret)
+ }
+
+ /// Returns the locked registrations if they're still available.
+ pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
+ self.registrations.try_write()
+ }
+}
+
+impl<T, U> crate::driver::DeviceRemoval for Data<T, U> {
+ fn device_remove(&self) {
+ self.registrations.revoke();
+ }
+}
+
+impl<T, U> Deref for Data<T, U> {
+ type Target = U;
+
+ fn deref(&self) -> &U {
+ &self.general
+ }
+}
+
+impl<T, U> DerefMut for Data<T, U> {
+ fn deref_mut(&mut self) -> &mut U {
+ &mut self.general
+ }
+}
--
2.45.1