Skip to content

Commit a98a73b

Browse files
hoshinolinaDanilo Krummrich
authored andcommitted
rust: drm: file: Add File abstraction
A DRM File is the DRM counterpart to a kernel file structure, representing an open DRM file descriptor. Add a Rust abstraction to allow drivers to implement their own File types that implement the DriverFile trait. Reviewed-by: Maxime Ripard <mripard@kernel.org> Signed-off-by: Asahi Lina <lina@asahilina.net> Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Reviewed-by: Lyude Paul <lyude@redhat.com> Link: https://lore.kernel.org/r/20250410235546.43736-7-dakr@kernel.org [ Rework of drm::File * switch to the Opaque<T> type * fix (mutable) references to struct drm_file (which in this context is UB) * restructure and rename functions to align with common kernel schemes * write and fix safety and invariant comments * remove necessity for and convert 'as' casts * original source archive: https://archive.is/GH8oy - Danilo ] Signed-off-by: Danilo Krummrich <dakr@kernel.org>
1 parent 0600032 commit a98a73b

5 files changed

Lines changed: 107 additions & 2 deletions

File tree

rust/bindings/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <drm/drm_device.h>
1010
#include <drm/drm_drv.h>
11+
#include <drm/drm_file.h>
1112
#include <drm/drm_ioctl.h>
1213
#include <kunit/test.h>
1314
#include <linux/auxiliary_bus.h>

rust/kernel/drm/device.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ pub struct Device<T: drm::Driver> {
6363
impl<T: drm::Driver> Device<T> {
6464
const VTABLE: bindings::drm_driver = drm_legacy_fields! {
6565
load: None,
66-
open: None, // TODO: File abstraction
67-
postclose: None, // TODO: File abstraction
66+
open: Some(drm::File::<T::File>::open_callback),
67+
postclose: Some(drm::File::<T::File>::postclose_callback),
6868
unload: None,
6969
release: None,
7070
master_set: None,

rust/kernel/drm/driver.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ pub trait Driver {
105105
/// The type used to manage memory for this driver.
106106
type Object: AllocImpl;
107107

108+
/// The type used to represent a DRM File (client)
109+
type File: drm::file::DriverFile;
110+
108111
/// Driver metadata
109112
const INFO: DriverInfo;
110113

rust/kernel/drm/file.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// SPDX-License-Identifier: GPL-2.0 OR MIT
2+
3+
//! DRM File objects.
4+
//!
5+
//! C header: [`include/linux/drm/drm_file.h`](srctree/include/linux/drm/drm_file.h)
6+
7+
use crate::{bindings, drm, error::Result, prelude::*, types::Opaque};
8+
use core::marker::PhantomData;
9+
use core::pin::Pin;
10+
11+
/// Trait that must be implemented by DRM drivers to represent a DRM File (a client instance).
12+
pub trait DriverFile {
13+
/// The parent `Driver` implementation for this `DriverFile`.
14+
type Driver: drm::Driver;
15+
16+
/// Open a new file (called when a client opens the DRM device).
17+
fn open(device: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>>;
18+
}
19+
20+
/// An open DRM File.
21+
///
22+
/// # Invariants
23+
///
24+
/// `self.0` is a valid instance of a `struct drm_file`.
25+
#[repr(transparent)]
26+
pub struct File<T: DriverFile>(Opaque<bindings::drm_file>, PhantomData<T>);
27+
28+
impl<T: DriverFile> File<T> {
29+
#[doc(hidden)]
30+
/// Not intended to be called externally, except via declare_drm_ioctls!()
31+
///
32+
/// # Safety
33+
///
34+
/// `raw_file` must be a valid pointer to an open `struct drm_file`, opened through `T::open`.
35+
pub unsafe fn as_ref<'a>(ptr: *mut bindings::drm_file) -> &'a File<T> {
36+
// SAFETY: `raw_file` is valid by the safety requirements of this function.
37+
unsafe { &*ptr.cast() }
38+
}
39+
40+
pub(super) fn as_raw(&self) -> *mut bindings::drm_file {
41+
self.0.get()
42+
}
43+
44+
fn driver_priv(&self) -> *mut T {
45+
// SAFETY: By the type invariants of `Self`, `self.as_raw()` is always valid.
46+
unsafe { (*self.as_raw()).driver_priv }.cast()
47+
}
48+
49+
/// Return a pinned reference to the driver file structure.
50+
pub fn inner(&self) -> Pin<&T> {
51+
// SAFETY: By the type invariant the pointer `self.as_raw()` points to a valid and opened
52+
// `struct drm_file`, hence `driver_priv` has been properly initialized by `open_callback`.
53+
unsafe { Pin::new_unchecked(&*(self.driver_priv())) }
54+
}
55+
56+
/// The open callback of a `struct drm_file`.
57+
pub(crate) extern "C" fn open_callback(
58+
raw_dev: *mut bindings::drm_device,
59+
raw_file: *mut bindings::drm_file,
60+
) -> core::ffi::c_int {
61+
// SAFETY: A callback from `struct drm_driver::open` guarantees that
62+
// - `raw_dev` is valid pointer to a `struct drm_device`,
63+
// - the corresponding `struct drm_device` has been registered.
64+
let drm = unsafe { drm::Device::as_ref(raw_dev) };
65+
66+
// SAFETY: `raw_file` is a valid pointer to a `struct drm_file`.
67+
let file = unsafe { File::<T>::as_ref(raw_file) };
68+
69+
let inner = match T::open(drm) {
70+
Err(e) => {
71+
return e.to_errno();
72+
}
73+
Ok(i) => i,
74+
};
75+
76+
// SAFETY: This pointer is treated as pinned, and the Drop guarantee is upheld in
77+
// `postclose_callback()`.
78+
let driver_priv = KBox::into_raw(unsafe { Pin::into_inner_unchecked(inner) });
79+
80+
// SAFETY: By the type invariants of `Self`, `self.as_raw()` is always valid.
81+
unsafe { (*file.as_raw()).driver_priv = driver_priv.cast() };
82+
83+
0
84+
}
85+
86+
/// The postclose callback of a `struct drm_file`.
87+
pub(crate) extern "C" fn postclose_callback(
88+
_raw_dev: *mut bindings::drm_device,
89+
raw_file: *mut bindings::drm_file,
90+
) {
91+
// SAFETY: This reference won't escape this function
92+
let file = unsafe { File::<T>::as_ref(raw_file) };
93+
94+
// SAFETY: `file.driver_priv` has been created in `open_callback` through `KBox::into_raw`.
95+
let _ = unsafe { KBox::from_raw(file.driver_priv()) };
96+
}
97+
}
98+
99+
impl<T: DriverFile> super::private::Sealed for File<T> {}

rust/kernel/drm/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
55
pub mod device;
66
pub mod driver;
7+
pub mod file;
78
pub mod ioctl;
89

910
pub use self::device::Device;
1011
pub use self::driver::Driver;
1112
pub use self::driver::DriverInfo;
1213
pub use self::driver::Registration;
14+
pub use self::file::File;
1315

1416
pub(crate) mod private {
1517
pub trait Sealed {}

0 commit comments

Comments
 (0)