Skip to content

Commit 4d320e3

Browse files
Danilo Krummrichgregkh
authored andcommitted
rust: platform: fix unrestricted &mut platform::Device
As by now, platform::Device is implemented as: #[derive(Clone)] pub struct Device(ARef<device::Device>); This may be convenient, but has the implication that drivers can call device methods that require a mutable reference concurrently at any point of time. Instead define platform::Device as pub struct Device<Ctx: DeviceContext = Normal>( Opaque<bindings::platform_dev>, PhantomData<Ctx>, ); and manually implement the AlwaysRefCounted trait. With this we can implement methods that should only be called from bus callbacks (such as probe()) for platform::Device<Core>. Consequently, we make this type accessible in bus callbacks only. Arbitrary references taken by the driver are still of type ARef<platform::Device> and hence don't provide access to methods that are reserved for bus callbacks. Fixes: 683a63b ("rust: platform: add basic platform device / driver abstractions") Reviewed-by: Benno Lossin <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]> Acked-by: Boqun Feng <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 7b948a2 commit 4d320e3

File tree

2 files changed

+72
-34
lines changed

2 files changed

+72
-34
lines changed

rust/kernel/platform.rs

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
//! C header: [`include/linux/platform_device.h`](srctree/include/linux/platform_device.h)
66
77
use crate::{
8-
bindings, container_of, device, driver,
8+
bindings, device, driver,
99
error::{to_result, Result},
1010
of,
1111
prelude::*,
@@ -14,7 +14,11 @@ use crate::{
1414
ThisModule,
1515
};
1616

17-
use core::ptr::addr_of_mut;
17+
use core::{
18+
marker::PhantomData,
19+
ops::Deref,
20+
ptr::{addr_of_mut, NonNull},
21+
};
1822

1923
/// An adapter for the registration of platform drivers.
2024
pub struct Adapter<T: Driver>(T);
@@ -54,14 +58,14 @@ unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> {
5458

5559
impl<T: Driver + 'static> Adapter<T> {
5660
extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ffi::c_int {
57-
// SAFETY: The platform bus only ever calls the probe callback with a valid `pdev`.
58-
let dev = unsafe { device::Device::get_device(addr_of_mut!((*pdev).dev)) };
59-
// SAFETY: `dev` is guaranteed to be embedded in a valid `struct platform_device` by the
60-
// call above.
61-
let mut pdev = unsafe { Device::from_dev(dev) };
61+
// SAFETY: The platform bus only ever calls the probe callback with a valid pointer to a
62+
// `struct platform_device`.
63+
//
64+
// INVARIANT: `pdev` is valid for the duration of `probe_callback()`.
65+
let pdev = unsafe { &*pdev.cast::<Device<device::Core>>() };
6266

6367
let info = <Self as driver::Adapter>::id_info(pdev.as_ref());
64-
match T::probe(&mut pdev, info) {
68+
match T::probe(pdev, info) {
6569
Ok(data) => {
6670
// Let the `struct platform_device` own a reference of the driver's private data.
6771
// SAFETY: By the type invariant `pdev.as_raw` returns a valid pointer to a
@@ -120,7 +124,7 @@ macro_rules! module_platform_driver {
120124
/// # Example
121125
///
122126
///```
123-
/// # use kernel::{bindings, c_str, of, platform};
127+
/// # use kernel::{bindings, c_str, device::Core, of, platform};
124128
///
125129
/// struct MyDriver;
126130
///
@@ -138,7 +142,7 @@ macro_rules! module_platform_driver {
138142
/// const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
139143
///
140144
/// fn probe(
141-
/// _pdev: &mut platform::Device,
145+
/// _pdev: &platform::Device<Core>,
142146
/// _id_info: Option<&Self::IdInfo>,
143147
/// ) -> Result<Pin<KBox<Self>>> {
144148
/// Err(ENODEV)
@@ -160,41 +164,72 @@ pub trait Driver {
160164
///
161165
/// Called when a new platform device is added or discovered.
162166
/// Implementers should attempt to initialize the device here.
163-
fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Pin<KBox<Self>>>;
167+
fn probe(dev: &Device<device::Core>, id_info: Option<&Self::IdInfo>)
168+
-> Result<Pin<KBox<Self>>>;
164169
}
165170

166171
/// The platform device representation.
167172
///
168-
/// A platform device is based on an always reference counted `device:Device` instance. Cloning a
169-
/// platform device, hence, also increments the base device' reference count.
173+
/// This structure represents the Rust abstraction for a C `struct platform_device`. The
174+
/// implementation abstracts the usage of an already existing C `struct platform_device` within Rust
175+
/// code that we get passed from the C side.
170176
///
171177
/// # Invariants
172178
///
173-
/// `Device` holds a valid reference of `ARef<device::Device>` whose underlying `struct device` is a
174-
/// member of a `struct platform_device`.
175-
#[derive(Clone)]
176-
pub struct Device(ARef<device::Device>);
179+
/// A [`Device`] instance represents a valid `struct platform_device` created by the C portion of
180+
/// the kernel.
181+
#[repr(transparent)]
182+
pub struct Device<Ctx: device::DeviceContext = device::Normal>(
183+
Opaque<bindings::platform_device>,
184+
PhantomData<Ctx>,
185+
);
177186

178187
impl Device {
179-
/// Convert a raw kernel device into a `Device`
180-
///
181-
/// # Safety
182-
///
183-
/// `dev` must be an `Aref<device::Device>` whose underlying `bindings::device` is a member of a
184-
/// `bindings::platform_device`.
185-
unsafe fn from_dev(dev: ARef<device::Device>) -> Self {
186-
Self(dev)
188+
fn as_raw(&self) -> *mut bindings::platform_device {
189+
self.0.get()
187190
}
191+
}
188192

189-
fn as_raw(&self) -> *mut bindings::platform_device {
190-
// SAFETY: By the type invariant `self.0.as_raw` is a pointer to the `struct device`
191-
// embedded in `struct platform_device`.
192-
unsafe { container_of!(self.0.as_raw(), bindings::platform_device, dev) }.cast_mut()
193+
impl Deref for Device<device::Core> {
194+
type Target = Device;
195+
196+
fn deref(&self) -> &Self::Target {
197+
let ptr: *const Self = self;
198+
199+
// CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::platform_device>`.
200+
let ptr = ptr.cast::<Device>();
201+
202+
// SAFETY: `ptr` was derived from `&self`.
203+
unsafe { &*ptr }
204+
}
205+
}
206+
207+
impl From<&Device<device::Core>> for ARef<Device> {
208+
fn from(dev: &Device<device::Core>) -> Self {
209+
(&**dev).into()
210+
}
211+
}
212+
213+
// SAFETY: Instances of `Device` are always reference-counted.
214+
unsafe impl crate::types::AlwaysRefCounted for Device {
215+
fn inc_ref(&self) {
216+
// SAFETY: The existence of a shared reference guarantees that the refcount is non-zero.
217+
unsafe { bindings::get_device(self.as_ref().as_raw()) };
218+
}
219+
220+
unsafe fn dec_ref(obj: NonNull<Self>) {
221+
// SAFETY: The safety requirements guarantee that the refcount is non-zero.
222+
unsafe { bindings::platform_device_put(obj.cast().as_ptr()) }
193223
}
194224
}
195225

196226
impl AsRef<device::Device> for Device {
197227
fn as_ref(&self) -> &device::Device {
198-
&self.0
228+
// SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
229+
// `struct platform_device`.
230+
let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) };
231+
232+
// SAFETY: `dev` points to a valid `struct device`.
233+
unsafe { device::Device::as_ref(dev) }
199234
}
200235
}

samples/rust/rust_driver_platform.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
//! Rust Platform driver sample.
44
5-
use kernel::{c_str, of, platform, prelude::*};
5+
use kernel::{c_str, device::Core, of, platform, prelude::*, types::ARef};
66

77
struct SampleDriver {
8-
pdev: platform::Device,
8+
pdev: ARef<platform::Device>,
99
}
1010

1111
struct Info(u32);
@@ -21,14 +21,17 @@ impl platform::Driver for SampleDriver {
2121
type IdInfo = Info;
2222
const OF_ID_TABLE: Option<of::IdTable<Self::IdInfo>> = Some(&OF_TABLE);
2323

24-
fn probe(pdev: &mut platform::Device, info: Option<&Self::IdInfo>) -> Result<Pin<KBox<Self>>> {
24+
fn probe(
25+
pdev: &platform::Device<Core>,
26+
info: Option<&Self::IdInfo>,
27+
) -> Result<Pin<KBox<Self>>> {
2528
dev_dbg!(pdev.as_ref(), "Probe Rust Platform driver sample.\n");
2629

2730
if let Some(info) = info {
2831
dev_info!(pdev.as_ref(), "Probed with info: '{}'.\n", info.0);
2932
}
3033

31-
let drvdata = KBox::new(Self { pdev: pdev.clone() }, GFP_KERNEL)?;
34+
let drvdata = KBox::new(Self { pdev: pdev.into() }, GFP_KERNEL)?;
3235

3336
Ok(drvdata.into())
3437
}

0 commit comments

Comments
 (0)