[PATCH v4] rust: drm: Drop the use of Opaque for ioctl arguments
Beata Michalska
beata.michalska at arm.com
Thu Jun 26 16:25:34 UTC 2025
On Wed, Jun 25, 2025 at 08:42:35PM -0700, Boqun Feng wrote:
Hi,
> Hi Beata,
>
> On Wed, Jun 25, 2025 at 10:13:33AM +0200, Beata Michalska wrote:
> > With the Opaque<T>, the expectations are that Rust should not
> > make any assumptions on the layout or invariants of the wrapped
> > C types. That runs rather counter to ioctl arguments, which must
> > adhere to certain data-layout constraits. By using Opaque<T>,
> > ioctl handlers are forced to use unsafe code where none is acually
> > needed. This adds needless complexity and maintenance overhead,
> > brining no safety benefits.
> > Drop the use of Opaque for ioctl arguments as that is not the best
> > fit here.
> >
> > Signed-off-by: Beata Michalska <beata.michalska at arm.com>
> > Acked-by: Danilo Krummrich <dakr at kernel.org>
> > ---
>
> Appreciate it if you could put a change log here mentioning changes
> between each version.
Done
>
> > drivers/gpu/drm/nova/file.rs | 23 ++++++--------
> > drivers/gpu/drm/nova/nova.rs | 1 -
> > drivers/gpu/drm/nova/uapi.rs | 61 ------------------------------------
> > rust/kernel/drm/ioctl.rs | 11 ++++---
> > 4 files changed, 16 insertions(+), 80 deletions(-)
> > delete mode 100644 drivers/gpu/drm/nova/uapi.rs
> >
> > diff --git a/drivers/gpu/drm/nova/file.rs b/drivers/gpu/drm/nova/file.rs
> > index 7e59a34b830d..7e7d4e2de2fb 100644
> > --- a/drivers/gpu/drm/nova/file.rs
> > +++ b/drivers/gpu/drm/nova/file.rs
> > @@ -2,13 +2,11 @@
> >
> > use crate::driver::{NovaDevice, NovaDriver};
> > use crate::gem::NovaObject;
> > -use crate::uapi::{GemCreate, GemInfo, Getparam};
> > use kernel::{
> > alloc::flags::*,
> > drm::{self, gem::BaseObject},
> > pci,
> > prelude::*,
> > - types::Opaque,
> > uapi,
> > };
> >
> > @@ -26,20 +24,19 @@ impl File {
> > /// IOCTL: get_param: Query GPU / driver metadata.
> > pub(crate) fn get_param(
> > dev: &NovaDevice,
> > - getparam: &Opaque<uapi::drm_nova_getparam>,
> > + getparam: &mut uapi::drm_nova_getparam,
> > _file: &drm::File<File>,
> > ) -> Result<u32> {
> > let adev = &dev.adev;
> > let parent = adev.parent().ok_or(ENOENT)?;
> > let pdev: &pci::Device = parent.try_into()?;
> > - let getparam: &Getparam = getparam.into();
> >
> > - let value = match getparam.param() as u32 {
> > + let value = match getparam.param as u32 {
> > uapi::NOVA_GETPARAM_VRAM_BAR_SIZE => pdev.resource_len(1)?,
> > _ => return Err(EINVAL),
> > };
> >
> > - getparam.set_value(value);
> > + getparam.value = value;
> >
> > Ok(0)
> > }
> > @@ -47,13 +44,12 @@ pub(crate) fn get_param(
> > /// IOCTL: gem_create: Create a new DRM GEM object.
> > pub(crate) fn gem_create(
> > dev: &NovaDevice,
> > - req: &Opaque<uapi::drm_nova_gem_create>,
> > + req: &mut uapi::drm_nova_gem_create,
> > file: &drm::File<File>,
> > ) -> Result<u32> {
> > - let req: &GemCreate = req.into();
> > - let obj = NovaObject::new(dev, req.size().try_into()?)?;
> > + let obj = NovaObject::new(dev, req.size.try_into()?)?;
> >
> > - req.set_handle(obj.create_handle(file)?);
> > + req.handle = obj.create_handle(file)?;
> >
> > Ok(0)
> > }
> > @@ -61,13 +57,12 @@ pub(crate) fn gem_create(
> > /// IOCTL: gem_info: Query GEM metadata.
> > pub(crate) fn gem_info(
> > _dev: &NovaDevice,
> > - req: &Opaque<uapi::drm_nova_gem_info>,
> > + req: &mut uapi::drm_nova_gem_info,
> > file: &drm::File<File>,
> > ) -> Result<u32> {
> > - let req: &GemInfo = req.into();
> > - let bo = NovaObject::lookup_handle(file, req.handle())?;
> > + let bo = NovaObject::lookup_handle(file, req.handle)?;
> >
> > - req.set_size(bo.size().try_into()?);
> > + req.size = bo.size().try_into()?;
> >
> > Ok(0)
> > }
> > diff --git a/drivers/gpu/drm/nova/nova.rs b/drivers/gpu/drm/nova/nova.rs
> > index 902876aa14d1..730598defe04 100644
> > --- a/drivers/gpu/drm/nova/nova.rs
> > +++ b/drivers/gpu/drm/nova/nova.rs
> > @@ -5,7 +5,6 @@
> > mod driver;
> > mod file;
> > mod gem;
> > -mod uapi;
> >
> > use crate::driver::NovaDriver;
> >
> > diff --git a/drivers/gpu/drm/nova/uapi.rs b/drivers/gpu/drm/nova/uapi.rs
> > deleted file mode 100644
> > index eb228a58d423..000000000000
> > --- a/drivers/gpu/drm/nova/uapi.rs
> > +++ /dev/null
> > @@ -1,61 +0,0 @@
> > -// SPDX-License-Identifier: GPL-2.0
> > -
> > -use kernel::uapi;
> > -
> > -// TODO Work out some common infrastructure to avoid boilerplate code for uAPI abstractions.
> > -
> > -macro_rules! define_uapi_abstraction {
> > - ($name:ident <= $inner:ty) => {
> > - #[repr(transparent)]
> > - pub struct $name(::kernel::types::Opaque<$inner>);
> > -
> > - impl ::core::convert::From<&::kernel::types::Opaque<$inner>> for &$name {
> > - fn from(value: &::kernel::types::Opaque<$inner>) -> Self {
> > - // SAFETY: `Self` is a transparent wrapper of `$inner`.
> > - unsafe { ::core::mem::transmute(value) }
> > - }
> > - }
> > - };
> > -}
> > -
> > -define_uapi_abstraction!(Getparam <= uapi::drm_nova_getparam);
> > -
> > -impl Getparam {
> > - pub fn param(&self) -> u64 {
> > - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_getparam`.
> > - unsafe { (*self.0.get()).param }
> > - }
> > -
> > - pub fn set_value(&self, v: u64) {
> > - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_getparam`.
> > - unsafe { (*self.0.get()).value = v };
> > - }
> > -}
> > -
> > -define_uapi_abstraction!(GemCreate <= uapi::drm_nova_gem_create);
> > -
> > -impl GemCreate {
> > - pub fn size(&self) -> u64 {
> > - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_create`.
> > - unsafe { (*self.0.get()).size }
> > - }
> > -
> > - pub fn set_handle(&self, handle: u32) {
> > - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_create`.
> > - unsafe { (*self.0.get()).handle = handle };
> > - }
> > -}
> > -
> > -define_uapi_abstraction!(GemInfo <= uapi::drm_nova_gem_info);
> > -
> > -impl GemInfo {
> > - pub fn handle(&self) -> u32 {
> > - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_info`.
> > - unsafe { (*self.0.get()).handle }
> > - }
> > -
> > - pub fn set_size(&self, size: u64) {
> > - // SAFETY: `self.get()` is a valid pointer to a `struct drm_nova_gem_info`.
> > - unsafe { (*self.0.get()).size = size };
> > - }
> > -}
> > diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs
> > index 445639404fb7..3425a835f9cd 100644
> > --- a/rust/kernel/drm/ioctl.rs
> > +++ b/rust/kernel/drm/ioctl.rs
> > @@ -83,7 +83,7 @@ pub mod internal {
> > ///
> > /// ```ignore
> > /// fn foo(device: &kernel::drm::Device<Self>,
> > -/// data: &Opaque<uapi::argument_type>,
> > +/// data: &mut uapi::argument_type,
> > /// file: &kernel::drm::File<Self::File>,
> > /// ) -> Result<u32>
> > /// ```
> > @@ -138,9 +138,12 @@ pub mod internal {
> > // 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.
> > - let data = unsafe {
> > - &*(raw_data as *const $crate::types::Opaque<$crate::uapi::$struct>)
> > - };
> > + // The `ioctl` argument is exclusively owned by the handler
> > + // and guaranteed by the C implementation (`drm_ioctl()`) to remain
> > + // valid for the entire lifetime of the reference taken here.
> > + // There is no concurrent access or aliasing; no other references
> > + // to this object exist during this call.
> > + let data = unsafe { &mut *(raw_data as *mut $crate::uapi::$struct) };
>
> "ptr as ptr" should be avoided, see:
>
> https://lore.kernel.org/rust-for-linux/20250615-ptr-as-ptr-v12-1-f43b024581e8@gmail.com/
>
> so probably
>
> let data = unsafe { &mut *(raw_data.cast()) };
>
> ?
>
Thank you for pointing that one out.
---
BR
Beata
> With that fixed, feel free to add:
>
> Reviewed-by: Boqun Feng <boqun.feng at gmail.com>
>
> Regards,
> Boqun
>
> > // SAFETY: This is just the DRM file structure
> > let file = unsafe { $crate::drm::File::as_ref(raw_file) };
> >
> > --
> > 2.25.1
> >
More information about the dri-devel
mailing list