Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Asahi Lina and committed by
Danilo Krummrich
a98a73be 0600032c

+107 -2
+1
rust/bindings/bindings_helper.h
··· 8 8 9 9 #include <drm/drm_device.h> 10 10 #include <drm/drm_drv.h> 11 + #include <drm/drm_file.h> 11 12 #include <drm/drm_ioctl.h> 12 13 #include <kunit/test.h> 13 14 #include <linux/auxiliary_bus.h>
+2 -2
rust/kernel/drm/device.rs
··· 63 63 impl<T: drm::Driver> Device<T> { 64 64 const VTABLE: bindings::drm_driver = drm_legacy_fields! { 65 65 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), 68 68 unload: None, 69 69 release: None, 70 70 master_set: None,
+3
rust/kernel/drm/driver.rs
··· 105 105 /// The type used to manage memory for this driver. 106 106 type Object: AllocImpl; 107 107 108 + /// The type used to represent a DRM File (client) 109 + type File: drm::file::DriverFile; 110 + 108 111 /// Driver metadata 109 112 const INFO: DriverInfo; 110 113
+99
rust/kernel/drm/file.rs
··· 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> {}
+2
rust/kernel/drm/mod.rs
··· 4 4 5 5 pub mod device; 6 6 pub mod driver; 7 + pub mod file; 7 8 pub mod ioctl; 8 9 9 10 pub use self::device::Device; 10 11 pub use self::driver::Driver; 11 12 pub use self::driver::DriverInfo; 12 13 pub use self::driver::Registration; 14 + pub use self::file::File; 13 15 14 16 pub(crate) mod private { 15 17 pub trait Sealed {}