Skip to content

Commit a5ddd9d

Browse files
committed
rust: drm: device: Convert Device to AlwaysRefCounted
Switch from being a refcount wrapper itself to a transparent wrapper around `bindings::drm_device`. The refcounted type then becomes ARef<Device<T>>. Signed-off-by: Asahi Lina <[email protected]>
1 parent b1c498c commit a5ddd9d

6 files changed

Lines changed: 64 additions & 75 deletions

File tree

rust/kernel/drm/device.rs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,73 +4,66 @@
44
//!
55
//! C header: [`include/linux/drm/drm_device.h`](../../../../include/linux/drm/drm_device.h)
66
7-
use crate::{bindings, device, drm, types::ForeignOwnable};
7+
use crate::{
8+
bindings, device, drm,
9+
types::{ARef, AlwaysRefCounted, ForeignOwnable},
10+
};
11+
use core::cell::UnsafeCell;
812
use core::marker::PhantomData;
13+
use core::ptr::NonNull;
914

10-
/// Represents a reference to a DRM device. The device is reference-counted and is guaranteed to
11-
/// not be dropped while this object is alive.
15+
/// A typed DRM device with a specific driver. The device is always reference-counted.
16+
#[repr(transparent)]
1217
pub struct Device<T: drm::drv::Driver> {
13-
// Type invariant: ptr must be a valid and initialized drm_device,
14-
// and this value must either own a reference to it or the caller
15-
// must ensure that it is never dropped if the reference is borrowed.
16-
pub(super) ptr: *mut bindings::drm_device,
18+
pub(super) drm: UnsafeCell<bindings::drm_device>,
1719
_p: PhantomData<T>,
1820
}
1921

2022
impl<T: drm::drv::Driver> Device<T> {
21-
// Not intended to be called externally, except via declare_drm_ioctls!()
22-
#[doc(hidden)]
23-
pub unsafe fn from_raw(raw: *mut bindings::drm_device) -> Device<T> {
24-
Device {
25-
ptr: raw,
26-
_p: PhantomData,
27-
}
28-
}
29-
30-
#[allow(dead_code)]
31-
pub(crate) fn raw(&self) -> *const bindings::drm_device {
32-
self.ptr
23+
#[allow(dead_code, clippy::mut_from_ref)]
24+
pub(crate) unsafe fn raw_mut(&self) -> &mut bindings::drm_device {
25+
unsafe { &mut *self.drm.get() }
3326
}
3427

35-
pub(crate) fn raw_mut(&mut self) -> *mut bindings::drm_device {
36-
self.ptr
28+
// Not intended to be called externally, except via declare_drm_ioctls!()
29+
#[doc(hidden)]
30+
pub unsafe fn borrow<'a>(raw: *const bindings::drm_device) -> &'a Self {
31+
unsafe { &*(raw as *const Self) }
3732
}
3833

3934
/// Returns a borrowed reference to the user data associated with this Device.
4035
pub fn data(&self) -> <T::Data as ForeignOwnable>::Borrowed<'_> {
41-
unsafe { T::Data::borrow((*self.ptr).dev_private) }
36+
// SAFETY: dev_private is guaranteed to be initialized for all
37+
// Device objects exposed to users.
38+
unsafe { T::Data::borrow((*self.drm.get()).dev_private) }
4239
}
4340
}
4441

45-
impl<T: drm::drv::Driver> Drop for Device<T> {
46-
fn drop(&mut self) {
47-
// SAFETY: By the type invariants, we know that `self` owns a reference, so it is safe to
48-
// relinquish it now.
49-
unsafe { bindings::drm_dev_put(self.ptr) };
42+
// SAFETY: DRM device objects are always reference counted and the get/put functions
43+
// satisfy the requirements.
44+
unsafe impl<T: drm::drv::Driver> AlwaysRefCounted for Device<T> {
45+
fn inc_ref(&self) {
46+
unsafe { bindings::drm_dev_get(&self.drm as *const _ as *mut _) };
5047
}
51-
}
5248

53-
impl<T: drm::drv::Driver> Clone for Device<T> {
54-
fn clone(&self) -> Self {
55-
// SAFETY: We get a new reference and then create a new owning object from the raw pointer
56-
unsafe {
57-
bindings::drm_dev_get(self.ptr);
58-
Device::from_raw(self.ptr)
59-
}
49+
unsafe fn dec_ref(obj: NonNull<Self>) {
50+
// SAFETY: The Device<T> type has the same layout as drm_device,
51+
// so we can just cast.
52+
unsafe { bindings::drm_dev_put(obj.as_ptr() as *mut _) };
6053
}
6154
}
6255

6356
// SAFETY: `Device` only holds a pointer to a C device, which is safe to be used from any thread.
64-
unsafe impl<T: drm::drv::Driver> Send for Device<T> {}
57+
unsafe impl<T: drm::drv::Driver> Send for ARef<Device<T>> {}
6558

6659
// SAFETY: `Device` only holds a pointer to a C device, references to which are safe to be used
6760
// from any thread.
68-
unsafe impl<T: drm::drv::Driver> Sync for Device<T> {}
61+
unsafe impl<T: drm::drv::Driver> Sync for ARef<Device<T>> {}
6962

7063
// Make drm::Device work for dev_info!() and friends
7164
unsafe impl<T: drm::drv::Driver> device::RawDevice for Device<T> {
7265
fn raw_device(&self) -> *mut bindings::device {
73-
// SAFETY: ptr must be valid per the type invariant
74-
unsafe { (*self.ptr).dev }
66+
// SAFETY: dev is initialized by C for all Device objects
67+
unsafe { (*self.drm.get()).dev }
7568
}
7669
}

rust/kernel/drm/drv.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ use crate::{
1212
prelude::*,
1313
private::Sealed,
1414
str::CStr,
15-
types::ForeignOwnable,
15+
types::{ARef, ForeignOwnable},
1616
ThisModule,
1717
};
1818
use core::{
1919
marker::{PhantomData, PhantomPinned},
2020
pin::Pin,
21+
ptr::NonNull,
2122
};
2223
use macros::vtable;
2324

@@ -163,7 +164,7 @@ pub trait Driver {
163164
///
164165
/// drm is always a valid pointer to an allocated drm_device
165166
pub struct Registration<T: Driver> {
166-
drm: drm::device::Device<T>,
167+
drm: ARef<drm::device::Device<T>>,
167168
registered: bool,
168169
fops: bindings::file_operations,
169170
vtable: Pin<Box<bindings::drm_driver>>,
@@ -253,11 +254,11 @@ impl<T: Driver> Registration<T> {
253254
pub fn new(parent: &dyn device::RawDevice) -> Result<Self> {
254255
let vtable = Pin::new(Box::try_new(Self::VTABLE)?);
255256
let raw_drm = unsafe { bindings::drm_dev_alloc(&*vtable, parent.raw_device()) };
256-
let raw_drm = from_err_ptr(raw_drm)?;
257+
let raw_drm = NonNull::new(from_err_ptr(raw_drm)? as *mut _).ok_or(ENOMEM)?;
257258

258259
// The reference count is one, and now we take ownership of that reference as a
259260
// drm::device::Device.
260-
let drm = unsafe { drm::device::Device::from_raw(raw_drm) };
261+
let drm = unsafe { ARef::from_raw(raw_drm) };
261262

262263
Ok(Self {
263264
drm,
@@ -287,10 +288,9 @@ impl<T: Driver> Registration<T> {
287288
// SAFETY: We never move out of `this`.
288289
let this = unsafe { self.get_unchecked_mut() };
289290
let data_pointer = <T::Data as ForeignOwnable>::into_foreign(data);
290-
// SAFETY: `drm` is valid per the type invariant
291-
unsafe {
292-
(*this.drm.raw_mut()).dev_private = data_pointer as *mut _;
293-
}
291+
// SAFETY: This is the only code touching dev_private, so it is safe to upgrade to a
292+
// mutable reference.
293+
unsafe { this.drm.raw_mut() }.dev_private = data_pointer as *mut _;
294294

295295
this.fops.owner = module.0;
296296
this.vtable.fops = &this.fops;
@@ -309,6 +309,7 @@ impl<T: Driver> Registration<T> {
309309

310310
/// Returns a reference to the `Device` instance for this registration.
311311
pub fn device(&self) -> &drm::device::Device<T> {
312+
// TODO: rework this, ensure this only works after registration
312313
&self.drm
313314
}
314315
}
@@ -329,7 +330,7 @@ impl<T: Driver> Drop for Registration<T> {
329330
if self.registered {
330331
// Get a pointer to the data stored in device before destroying it.
331332
// SAFETY: `drm` is valid per the type invariant
332-
let data_pointer = unsafe { (*self.drm.raw_mut()).dev_private };
333+
let data_pointer = unsafe { self.drm.raw_mut().dev_private };
333334

334335
// SAFETY: Since `registered` is true, `self.drm` is both valid and registered.
335336
unsafe { bindings::drm_dev_unregister(self.drm.raw_mut()) };

rust/kernel/drm/file.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@ pub(super) unsafe extern "C" fn open_callback<T: DriverFile>(
3232
raw_dev: *mut bindings::drm_device,
3333
raw_file: *mut bindings::drm_file,
3434
) -> core::ffi::c_int {
35-
let drm = core::mem::ManuallyDrop::new(unsafe { drm::device::Device::from_raw(raw_dev) });
35+
let drm = unsafe { drm::device::Device::borrow(raw_dev) };
3636
// SAFETY: This reference won't escape this function
3737
let file = unsafe { &mut *raw_file };
3838

39-
let inner = match T::open(&drm) {
39+
let inner = match T::open(drm) {
4040
Err(e) => {
4141
return e.to_errno();
4242
}

rust/kernel/drm/gem/mod.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
error::{to_result, Result},
1616
prelude::*,
1717
};
18-
use core::{marker::PhantomPinned, mem, mem::ManuallyDrop, ops::Deref, ops::DerefMut};
18+
use core::{marker::PhantomPinned, mem, ops::Deref, ops::DerefMut};
1919

2020
/// GEM object functions, which must be implemented by drivers.
2121
pub trait BaseDriverObject<T: BaseObject>: Sync + Send + Sized {
@@ -211,9 +211,7 @@ impl<T: IntoGEMObject> BaseObject for T {}
211211
#[pin_data]
212212
pub struct Object<T: DriverObject> {
213213
obj: bindings::drm_gem_object,
214-
// The DRM core ensures the Device exists as long as its objects exist, so we don't need to
215-
// manage the reference count here.
216-
dev: ManuallyDrop<device::Device<T::Driver>>,
214+
dev: *const bindings::drm_device,
217215
#[pin]
218216
inner: T,
219217
#[pin]
@@ -251,14 +249,12 @@ impl<T: DriverObject> Object<T> {
251249
..Default::default()
252250
},
253251
inner <- T::new(dev, size),
254-
// SAFETY: The drm subsystem guarantees that the drm_device will live as long as
255-
// the GEM object lives, so we can conjure a reference out of thin air.
256-
dev: ManuallyDrop::new(unsafe { device::Device::from_raw(dev.ptr) }),
252+
dev: dev.drm.get(),
257253
_p: PhantomPinned
258254
}))?;
259255

260256
to_result(unsafe {
261-
bindings::drm_gem_object_init(dev.raw() as *mut _, &obj.obj as *const _ as *mut _, size)
257+
bindings::drm_gem_object_init(dev.raw_mut(), &obj.obj as *const _ as *mut _, size)
262258
})?;
263259

264260
// SAFETY: We never move out of self
@@ -275,7 +271,9 @@ impl<T: DriverObject> Object<T> {
275271

276272
/// Returns the `Device` that owns this GEM object.
277273
pub fn dev(&self) -> &device::Device<T::Driver> {
278-
&self.dev
274+
// SAFETY: The drm subsystem guarantees that the drm_device will live as long as
275+
// the GEM object lives, so we can just borrow from the raw pointer.
276+
unsafe { device::Device::borrow(self.dev) }
279277
}
280278
}
281279

rust/kernel/drm/gem/shmem.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
use core::{
1313
marker::{PhantomData, PhantomPinned},
1414
mem,
15-
mem::{ManuallyDrop, MaybeUninit},
15+
mem::MaybeUninit,
1616
ops::{Deref, DerefMut},
1717
slice,
1818
};
@@ -71,7 +71,7 @@ pub struct Object<T: DriverObject> {
7171
obj: bindings::drm_gem_shmem_object,
7272
// The DRM core ensures the Device exists as long as its objects exist, so we don't need to
7373
// manage the reference count here.
74-
dev: ManuallyDrop<device::Device<T::Driver>>,
74+
dev: *const bindings::drm_device,
7575
#[pin]
7676
inner: T,
7777
}
@@ -80,13 +80,9 @@ pub struct Object<T: DriverObject> {
8080
unsafe impl init::Zeroable for bindings::drm_gem_shmem_object {}
8181

8282
unsafe extern "C" fn gem_create_object<T: DriverObject>(
83-
raw_dev: *mut bindings::drm_device,
83+
dev: *mut bindings::drm_device,
8484
size: usize,
8585
) -> *mut bindings::drm_gem_object {
86-
// SAFETY: GEM ensures the device lives as long as its objects live,
87-
// so we can conjure up a reference from thin air and never drop it.
88-
let dev = ManuallyDrop::new(unsafe { device::Device::from_raw(raw_dev) });
89-
9086
let p = unsafe {
9187
bindings::krealloc(core::ptr::null(), Object::<T>::SIZE, bindings::GFP_KERNEL)
9288
as *mut Object<T>
@@ -98,7 +94,8 @@ unsafe extern "C" fn gem_create_object<T: DriverObject>(
9894

9995
let init = try_pin_init!(Object {
10096
obj <- init::zeroed(),
101-
inner <- T::new(&*dev, size),
97+
// SAFETY: GEM ensures the device lives as long as its objects live
98+
inner <- T::new(unsafe { device::Device::borrow(dev)}, size),
10299
dev,
103100
});
104101

@@ -163,7 +160,7 @@ impl<T: DriverObject> Object<T> {
163160
pub fn new(dev: &device::Device<T::Driver>, size: usize) -> Result<gem::UniqueObjectRef<Self>> {
164161
// SAFETY: This function can be called as long as the ALLOC_OPS are set properly
165162
// for this driver, and the gem_create_object is called.
166-
let p = unsafe { bindings::drm_gem_shmem_create(dev.raw() as *mut _, size) };
163+
let p = unsafe { bindings::drm_gem_shmem_create(dev.raw_mut(), size) };
167164
let p = crate::container_of!(p, Object<T>, obj) as *mut _;
168165

169166
// SAFETY: The gem_create_object callback ensures this is a valid Object<T>,
@@ -178,7 +175,9 @@ impl<T: DriverObject> Object<T> {
178175

179176
/// Returns the `Device` that owns this GEM object.
180177
pub fn dev(&self) -> &device::Device<T::Driver> {
181-
&self.dev
178+
// SAFETY: GEM ensures that the device outlives its objects, so we can
179+
// just borrow here.
180+
unsafe { device::Device::borrow(self.dev) }
182181
}
183182

184183
/// Creates (if necessary) and returns a scatter-gather table of DMA pages for this object.

rust/kernel/drm/ioctl.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,22 +128,20 @@ macro_rules! declare_drm_ioctls {
128128
raw_data: *mut ::core::ffi::c_void,
129129
raw_file_priv: *mut $crate::drm::ioctl::internal::drm_file,
130130
) -> core::ffi::c_int {
131-
// SAFETY: We never drop this, and the DRM core ensures the device lives
132-
// while callbacks are being called.
131+
// SAFETY: The DRM core ensures the device lives while callbacks are
132+
// being called.
133133
//
134134
// FIXME: Currently there is nothing enforcing that the types of the
135135
// dev/file match the current driver these ioctls are being declared
136136
// for, and it's not clear how to enforce this within the type system.
137-
let dev = ::core::mem::ManuallyDrop::new(unsafe {
138-
$crate::drm::device::Device::from_raw(raw_dev)
139-
});
137+
let dev = $crate::drm::device::Device::borrow(raw_dev);
140138
// SAFETY: This is just the ioctl argument, which hopefully has the right type
141139
// (we've done our best checking the size).
142140
let data = unsafe { &mut *(raw_data as *mut $crate::uapi::$struct) };
143141
// SAFETY: This is just the DRM file structure
144142
let file = unsafe { $crate::drm::file::File::from_raw(raw_file_priv) };
145143

146-
match $func(&*dev, data, &file) {
144+
match $func(dev, data, &file) {
147145
Err(e) => e.to_errno(),
148146
Ok(i) => i.try_into().unwrap_or(ERANGE.to_errno()),
149147
}

0 commit comments

Comments
 (0)