mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
rust: drm: Wrap ioctl dispatch in RegistrationGuard
Make Ioctl handlers receive a &Device<T, Registered> reference, proving at the type level that the device is registered and its parent bus device is bound. This is achieved by calling registration_guard() on the Device<T, Ioctl> obtained in ioctl dispatch context. If the device has been unplugged, the ioctl returns -ENODEV without calling the handler. To resolve the driver type parameter T for type inference, which the compiler cannot propagate through method resolution and associated-type projections alone, a dead-code closure and a helper function are used as a type-inference anchor. Reviewed-by: Lyude Paul <lyude@redhat.com> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Tested-by: Deborah Brouwer <deborah.brouwer@collabora.com> Link: https://patch.msgid.link/20260628145406.2107056-14-dakr@kernel.org [ Use imperative mood in commit message; clarify __dev_ctx_cast() doc comment to reflect Ioctl-to-Registered cast. - Danilo ] Signed-off-by: Danilo Krummrich <dakr@kernel.org>
This commit is contained in:
parent
2455d5f2d5
commit
478da53e5b
|
|
@ -4,7 +4,11 @@
|
|||
use crate::gem::NovaObject;
|
||||
use kernel::{
|
||||
alloc::flags::*,
|
||||
drm::{self, gem::BaseObject},
|
||||
drm::{
|
||||
self,
|
||||
gem::BaseObject,
|
||||
Registered, //
|
||||
},
|
||||
pci,
|
||||
prelude::*,
|
||||
uapi,
|
||||
|
|
@ -23,7 +27,7 @@ fn open(_dev: &NovaDevice) -> Result<Pin<KBox<Self>>> {
|
|||
impl File {
|
||||
/// IOCTL: get_param: Query GPU / driver metadata.
|
||||
pub(crate) fn get_param(
|
||||
dev: &NovaDevice,
|
||||
dev: &NovaDevice<Registered>,
|
||||
getparam: &mut uapi::drm_nova_getparam,
|
||||
_file: &drm::File<File>,
|
||||
) -> Result<u32> {
|
||||
|
|
@ -43,7 +47,7 @@ pub(crate) fn get_param(
|
|||
|
||||
/// IOCTL: gem_create: Create a new DRM GEM object.
|
||||
pub(crate) fn gem_create(
|
||||
dev: &NovaDevice,
|
||||
dev: &NovaDevice<Registered>,
|
||||
req: &mut uapi::drm_nova_gem_create,
|
||||
file: &drm::File<File>,
|
||||
) -> Result<u32> {
|
||||
|
|
@ -56,7 +60,7 @@ pub(crate) fn gem_create(
|
|||
|
||||
/// IOCTL: gem_info: Query GEM metadata.
|
||||
pub(crate) fn gem_info(
|
||||
_dev: &NovaDevice,
|
||||
_dev: &NovaDevice<Registered>,
|
||||
req: &mut uapi::drm_nova_gem_info,
|
||||
file: &drm::File<File>,
|
||||
) -> Result<u32> {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 or MIT
|
||||
|
||||
use kernel::{
|
||||
drm,
|
||||
drm::{
|
||||
self,
|
||||
Registered, //
|
||||
},
|
||||
prelude::*,
|
||||
uaccess::UserSlice,
|
||||
uapi, //
|
||||
|
|
@ -28,7 +31,7 @@ fn open(_dev: &drm::Device<Self::Driver>) -> Result<Pin<KBox<Self>>> {
|
|||
|
||||
impl TyrDrmFileData {
|
||||
pub(crate) fn dev_query(
|
||||
ddev: &TyrDrmDevice,
|
||||
ddev: &TyrDrmDevice<Registered>,
|
||||
devquery: &mut uapi::drm_panthor_dev_query,
|
||||
_file: &TyrDrmFile,
|
||||
) -> Result<u32> {
|
||||
|
|
|
|||
|
|
@ -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,7 @@ 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>,
|
||||
/// data: &mut uapi::argument_type,
|
||||
/// file: &kernel::drm::File<Self::File>,
|
||||
/// ) -> Result<u32>
|
||||
|
|
@ -131,17 +143,44 @@ 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<_, $crate::drm::Normal> =
|
||||
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!(),
|
||||
)
|
||||
};
|
||||
|
||||
// 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 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.
|
||||
|
|
@ -154,7 +193,7 @@ 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 $func(&*guard, data, file) {
|
||||
Err(e) => e.to_errno(),
|
||||
Ok(i) => i.try_into()
|
||||
.unwrap_or($crate::error::code::ERANGE.to_errno()),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user