summaryrefslogtreecommitdiff
path: root/rust/kernel/drm/ioctl.rs
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-07-26 22:25:16 +0100
committerMark Brown <broonie@kernel.org>2026-07-26 22:25:16 +0100
commitdfdb2e2c135bb9b27c48987f458bcee195def03f (patch)
treea5651ad35a17341e41b8b9171dd79dee76241fcb /rust/kernel/drm/ioctl.rs
parentc6bc6034d94ae0b4177d86af8c0a179a1682d7ea (diff)
parent6dcbb4b1320fa91fee349462a52bb69135f2e45e (diff)
downloadlinux-next-dfdb2e2c135bb9b27c48987f458bcee195def03f.tar.gz
linux-next-dfdb2e2c135bb9b27c48987f458bcee195def03f.zip
Merge branch 'for-linux-next' of https://gitlab.freedesktop.org/drm/rust/kernel.git
Diffstat (limited to 'rust/kernel/drm/ioctl.rs')
-rw-r--r--rust/kernel/drm/ioctl.rs56
1 files changed, 53 insertions, 3 deletions
diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs
index cf328101dde4..64af9eacc306 100644
--- a/rust/kernel/drm/ioctl.rs
+++ b/rust/kernel/drm/ioctl.rs
@@ -70,6 +70,18 @@ pub mod internal {
pub use bindings::drm_device;
pub use bindings::drm_file;
pub use bindings::drm_ioctl_desc;
+
+ /// Cast an [`Ioctl`] DRM device pointer to [`Registered`], preserving the driver type
+ /// parameter `T`.
+ ///
+ /// Used by [`declare_drm_ioctls!`] to anchor type inference.
+ #[doc(hidden)]
+ #[inline]
+ pub const fn __dev_ctx_cast<T: crate::drm::Driver>(
+ ptr: *const crate::drm::Device<T, crate::drm::Ioctl>,
+ ) -> *const crate::drm::Device<T, crate::drm::Registered> {
+ ptr.cast()
+ }
}
/// Declare the DRM ioctls for a driver.
@@ -82,7 +94,8 @@ pub mod internal {
/// `user_callback` should have the following prototype:
///
/// ```ignore
-/// fn foo(device: &kernel::drm::Device<Self>,
+/// fn foo(device: &kernel::drm::Device<Self, kernel::drm::Registered>,
+/// reg_data: &Self::RegistrationData<'_>,
/// data: &mut uapi::argument_type,
/// file: &kernel::drm::File<Self::File>,
/// ) -> Result<u32>
@@ -131,10 +144,45 @@ macro_rules! declare_drm_ioctls {
// - The DRM device must have been registered when we're called through
// an IOCTL.
//
+ // INVARIANT: The `Ioctl` context requires that the device has been
+ // registered via `drm_dev_register()` at some point; the DRM core
+ // guarantees this for ioctl dispatch callbacks.
+ //
// FIXME: Currently there is nothing enforcing that the types of the
// dev/file match the current driver these ioctls are being declared
// for, and it's not clear how to enforce this within the type system.
- let dev = $crate::drm::device::Device::from_raw(raw_dev);
+ let dev: &$crate::drm::device::Device<_, $crate::drm::Ioctl> =
+ $crate::drm::device::Device::from_raw(raw_dev);
+
+ // Type-inference anchor: the closure is never called but ties `dev`'s
+ // type to `$func`'s first parameter, which the compiler cannot infer
+ // through method resolution and associated-type projections alone.
+ #[allow(unreachable_code)]
+ let _ = || {
+ let __ptr = $crate::drm::ioctl::internal::__dev_ctx_cast(
+ ::core::ptr::from_ref(dev),
+ );
+
+ $func(
+ // SAFETY: This closure is never executed; the dereference
+ // exists purely to unify the type parameter with `$func`.
+ // The pointer is valid regardless.
+ unsafe { &*__ptr },
+ unreachable!(),
+ unreachable!(),
+ unreachable!(),
+ )
+ };
+
+ // Enforce that the handler accepts higher-ranked
+ // lifetimes, preventing it from requiring 'static
+ // references that could escape this scope.
+ let _: for<'a> fn(&'a _, &'a _, &'a mut _, &'a _) -> _ = $func;
+
+ let Some(guard) = dev.registration_guard() else {
+ return $crate::error::code::ENODEV.to_errno();
+ };
+
// SAFETY: The ioctl argument has size `_IOC_SIZE(cmd)`, which we
// asserted above matches the size of this type, and all bit patterns of
// UAPI structs must be valid.
@@ -147,7 +195,9 @@ macro_rules! declare_drm_ioctls {
// SAFETY: This is just the DRM file structure
let file = unsafe { $crate::drm::File::from_raw(raw_file) };
- match $func(dev, data, file) {
+ match guard.registration_data_with(|reg_data| {
+ $func(&*guard, reg_data, data, file)
+ }) {
Err(e) => e.to_errno(),
Ok(i) => i.try_into()
.unwrap_or($crate::error::code::ERANGE.to_errno()),