From: Boqun Feng <boqun.feng@gmail.com>
To: Beata Michalska <beata.michalska@arm.com>
Cc: ojeda@kernel.org, alex.gaynor@gmail.com, dakr@kernel.org,
aliceryhl@google.com, daniel.almeida@collabora.com,
gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org,
a.hindborg@kernel.org, tmgross@umich.edu, alyssa@rosenzweig.io,
lyude@redhat.com, rust-for-linux@vger.kernel.org,
dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v4] rust: drm: Drop the use of Opaque for ioctl arguments
Date: Wed, 25 Jun 2025 20:42:35 -0700 [thread overview]
Message-ID: <aFzBq4wDVbLFry6z@Mac.home> (raw)
In-Reply-To: <20250625081333.2217887-1-beata.michalska@arm.com>
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@arm.com>
> Acked-by: Danilo Krummrich <dakr@kernel.org>
> ---
Appreciate it if you could put a change log here mentioning changes
between each version.
> 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()) };
?
With that fixed, feel free to add:
Reviewed-by: Boqun Feng <boqun.feng@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
>
next prev parent reply other threads:[~2025-06-26 3:42 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-25 8:13 [PATCH v4] rust: drm: Drop the use of Opaque for ioctl arguments Beata Michalska
2025-06-26 3:42 ` Boqun Feng [this message]
2025-06-26 16:25 ` Beata Michalska
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aFzBq4wDVbLFry6z@Mac.home \
--to=boqun.feng@gmail.com \
--cc=a.hindborg@kernel.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=alyssa@rosenzweig.io \
--cc=beata.michalska@arm.com \
--cc=bjorn3_gh@protonmail.com \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).