From nobody Sat Jun 13 20:19:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7C0EF481672; Tue, 5 May 2026 15:24:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777994651; cv=none; b=JeZdIZ34zKrUOMQshjEX0i1FWP8OrSkjdN3n9RQPssEcDuJVN45U3rHx1949Fq6IAauWBh2WxygQG285hEBfuDil0YNaWB0UY9v15eNPDCABhkOZcO9z+niW2iUdAUC1K4S2GJacQw8+sQOiIVn2aL2KbKEJe/wTIi3udJRc8hE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777994651; c=relaxed/simple; bh=/fRYQ5zjyOWJ/pjwZIQGbTj2eLYzfvrx5wG1aPkJ0yk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uSLx5/OeNMSGojeiPn/jPpzAt05Gnu8/NsC0ketm6iX0WHlMBzXDcGDpSr6CBObBKfef/aNgOgZno5WhojDqt3eG50RoC4/B97lKwKfZymznnaVHXR9CKj4UTeVUJt+0+pEy7l7p1gn1Gn2oKAhvCfGY/JRgQKIR0mldytD4o/E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=SXJ30qcv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="SXJ30qcv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 3752DC2BCF5; Tue, 5 May 2026 15:24:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777994651; bh=/fRYQ5zjyOWJ/pjwZIQGbTj2eLYzfvrx5wG1aPkJ0yk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SXJ30qcvZyrwl+5xqeEEOkQOYPEOuJoahNOTRVpjZWEZtRGtD+oA+gZn8TpWHKWBm GYYhJ13x8GubFYRcnUxl501mOCZHvRaMTcJV3u8hp0M4dIEHS/I8g60qqKfZwFQSzl 9A4jDC4V+x/sNS4OaC0oukadQ4UaMe9OcIvKgc3IGE7AGdt992KemwXAzEHHe2Xglc ad4wFuVYf/0nD1S/hmJgyQlcmf3IleEqNeFYMJIl012IlPjFoAdpH0uU76mpTtnFWS oemGjtz7Gh4M9NeBE46mWuutnWcefecejUYSwb3awnNqkNOH5rPEtVYSaE21VBfs8O nRHOS0RJ7fBhA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 1/3] rust: alloc: add Box::zeroed() Date: Tue, 5 May 2026 17:23:07 +0200 Message-ID: <20260505152400.3905096-2-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505152400.3905096-1-dakr@kernel.org> References: <20260505152400.3905096-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add Box::zeroed() for T: Zeroable types. This allocates with __GFP_ZERO directly, letting the underlying allocator deal with zeroing out the memory compared to Box::new(T::zeroed(), flags). Signed-off-by: Danilo Krummrich Reviewed-by: Alice Ryhl --- rust/kernel/alloc/kbox.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index bd6da02c7ab8..c824ed6e1523 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -19,6 +19,7 @@ use crate::fmt; use crate::init::InPlaceInit; use crate::page::AsPageIter; +use crate::prelude::*; use crate::types::ForeignOwnable; use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption}; =20 @@ -256,6 +257,27 @@ pub fn new_uninit(flags: Flags) -> Result, A>, AllocError> { Ok(Box(ptr.cast(), PhantomData)) } =20 + /// Creates a new zero-initialized `Box`. + /// + /// New memory is allocated with `A` and the [`__GFP_ZERO`] flag. The = allocation may fail, in + /// which case an error is returned. For ZSTs no memory is allocated. + /// + /// # Examples + /// + /// ``` + /// let b =3D KBox::<[u8; 128]>::zeroed(GFP_KERNEL)?; + /// assert_eq!(*b, [0; 128]); + /// # Ok::<(), Error>(()) + /// ``` + pub fn zeroed(flags: Flags) -> Result + where + T: Zeroable, + { + // SAFETY: `__GFP_ZERO` guarantees the memory is zeroed; `T: Zeroa= ble` guarantees that + // all-zeroes is a valid bit pattern for `T`. + Ok(unsafe { Self::new_uninit(flags | __GFP_ZERO)?.assume_init() }) + } + /// Constructs a new `Pin>`. If `T` does not implement [`Unp= in`], then `x` will be /// pinned in memory and can't be moved. #[inline] --=20 2.54.0 From nobody Sat Jun 13 20:19:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D895E481A8A; Tue, 5 May 2026 15:24:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777994655; cv=none; b=ShAwaS+DpvHAUlvR2tcxuWMfUhv/i6rOABtr9VuQAv3efCCqDQga+exVNarwwdbaLIJH2xcu5GuEGEYiFiY7kQXCHwhgGPU7z+jLClTSCKQhflnEZ2mTJOFntbZkjfEy2Mavaxjt15StDFftzeJNnNMn5EHPrX6q+TKhnLaDLvc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777994655; c=relaxed/simple; bh=/+x27CCeRy9tqvuQfYvVDMCFxNl0EQsDSBY5z6DLvas=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qh31y+Dsg8J4kRze1+/bJ22u6btsQVM+TPnBXtCD/Y8NV9w4c3zA3BjCSiL823Ne/64pSLa4wsh1TjX7jkyhOC6EUWffyz01gnOlvJwMHyN9bEAFKhrk92wVHmWsffrXBmxWwctmV9x8PCMASvx8GSS5bNYOnekEeykzCSngQjk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=YLTQSz6i; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="YLTQSz6i" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 91C85C2BCC7; Tue, 5 May 2026 15:24:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777994655; bh=/+x27CCeRy9tqvuQfYvVDMCFxNl0EQsDSBY5z6DLvas=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YLTQSz6iQPJUyXetgkk1H32OZVgw1GsRv5MzZKfMQqZtaFEWFmlKisFL6i3aAb5jI e7x3KkzxpbmDAeJ2ZS+TcBVszszzzq8nQFvYVF5hOznoODCuBM+ta3EjS4xtfZ5HLF vqI/S4FtLG27MKdXBG5KysaAeZPAtpsQrrX/j/YBfo1I/rQcX7lYKKqiSahZ0geFZ6 h8HbC5BjXjz0DKbkKgxbroX7dtbZY/mXXnp8MQzWMcd/Rl/cACLgRD5S1EB6bBRvhy GG1fJCD8dumf2EiDL88b3N5RgHL4IxuSLBBIv1Ktuy3bVe/ikVfF1z6w8tvhr+OJBq nE1L4RMmD/CmQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 2/3] rust: auxiliary: add registration data to auxiliary devices Date: Tue, 5 May 2026 17:23:08 +0200 Message-ID: <20260505152400.3905096-3-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505152400.3905096-1-dakr@kernel.org> References: <20260505152400.3905096-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a registration_data pointer to struct auxiliary_device, allowing the registering (parent) driver to attach private data to the device at registration time and retrieve it later when called back by the auxiliary (child) driver. By tying the data to the device's registration, Rust drivers can bind the lifetime of device resources to it, since the auxiliary bus guarantees that the parent driver remains bound while the auxiliary device is bound. On the Rust side, Registration takes ownership of the data via ForeignOwnable. A TypeId is stored alongside the data for runtime type checking, making Device::registration_data() a safe method. Signed-off-by: Danilo Krummrich Reviewed-by: Alice Ryhl --- drivers/gpu/nova-core/driver.rs | 10 +- include/linux/auxiliary_bus.h | 4 + rust/kernel/auxiliary.rs | 208 ++++++++++++++++++-------- samples/rust/rust_driver_auxiliary.rs | 40 +++-- 4 files changed, 180 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver= .rs index 84b0e1703150..8fe484d357f6 100644 --- a/drivers/gpu/nova-core/driver.rs +++ b/drivers/gpu/nova-core/driver.rs @@ -32,8 +32,7 @@ pub(crate) struct NovaCore { #[pin] pub(crate) gpu: Gpu, - #[pin] - _reg: Devres, + _reg: Devres>, } =20 const BAR0_SIZE: usize =3D SZ_16M; @@ -96,14 +95,15 @@ fn probe(pdev: &pci::Device, _info: &Self::IdInfo= ) -> impl PinInit &device::Device= { // SAFETY: A bound auxiliary device always has a bound parent devi= ce. unsafe { parent.as_bound() } } + + /// Returns a pinned reference to the registration data set by the reg= istering (parent) driver. + /// + /// Returns [`EINVAL`] if `T` does not match the type used by the pare= nt driver when calling + /// [`Registration::new()`]. + /// + /// Returns [`ENOENT`] if no registration data has been set, e.g. when= the device was + /// registered by a C driver. + pub fn registration_data(&self) -> Result> { + // SAFETY: By the type invariant, `self.as_raw()` is a valid `stru= ct auxiliary_device`. + let ptr =3D unsafe { (*self.as_raw()).registration_data_rust }; + if ptr.is_null() { + dev_warn!( + self.as_ref(), + "No registration data set; parent is not a Rust driver.\n" + ); + return Err(ENOENT); + } + + // SAFETY: `ptr` is non-null and was set via `into_foreign()` in `= Registration::new()`; + // `RegistrationData` is `#[repr(C)]` with `type_id` at offset 0, = so reading a `TypeId` + // at the start of the allocation is valid regardless of `T`. + let type_id =3D unsafe { ptr.cast::().read() }; + if type_id !=3D TypeId::of::() { + return Err(EINVAL); + } + + // SAFETY: The `TypeId` check above confirms that the stored type = is `T`; `ptr` remains + // valid until `Registration::drop()` calls `from_foreign()`. + let wrapper =3D unsafe { Pin::>>::borrow(= ptr) }; + + // SAFETY: `data` is a structurally pinned field of `RegistrationD= ata`. + Ok(unsafe { wrapper.map_unchecked(|w| &w.data) }) + } } =20 impl Device { @@ -326,87 +365,132 @@ unsafe impl Send for Device {} // (i.e. `Device) are thread safe. unsafe impl Sync for Device {} =20 +/// Wrapper that stores a [`TypeId`] alongside the registration data for r= untime type checking. +#[repr(C)] +#[pin_data] +struct RegistrationData { + type_id: TypeId, + #[pin] + data: T, +} + /// The registration of an auxiliary device. /// /// This type represents the registration of a [`struct auxiliary_device`]= . When its parent device /// is unbound, the corresponding auxiliary device will be unregistered fr= om the system. /// +/// The type parameter `T` is the type of the registration data owned by t= he registering (parent) +/// driver. It can be accessed by the auxiliary driver through +/// [`Device::registration_data()`]. +/// /// # Invariants /// -/// `self.0` always holds a valid pointer to an initialized and registered -/// [`struct auxiliary_device`]. -pub struct Registration(NonNull); - -impl Registration { - /// Create and register a new auxiliary device. - pub fn new<'a>( - parent: &'a device::Device, - name: &'a CStr, +/// `self.adev` always holds a valid pointer to an initialized and registe= red +/// [`struct auxiliary_device`] whose `registration_data_rust` field point= s to a +/// valid `Pin>>`. +pub struct Registration { + adev: NonNull, + _data: PhantomData, +} + +impl Registration { + /// Create and register a new auxiliary device with the given registra= tion data. + /// + /// The `data` is owned by the registration and can be accessed throug= h the auxiliary device + /// via [`Device::registration_data()`]. + pub fn new( + parent: &device::Device, + name: &CStr, id: u32, - modname: &'a CStr, - ) -> impl PinInit, Error> + 'a { - pin_init::pin_init_scope(move || { - let boxed =3D KBox::new(Opaque::::= zeroed(), GFP_KERNEL)?; - let adev =3D boxed.get(); - - // SAFETY: It's safe to set the fields of `struct auxiliary_de= vice` on initialization. - unsafe { - (*adev).dev.parent =3D parent.as_raw(); - (*adev).dev.release =3D Some(Device::release); - (*adev).name =3D name.as_char_ptr(); - (*adev).id =3D id; - } - - // SAFETY: `adev` is guaranteed to be a valid pointer to a `st= ruct auxiliary_device`, - // which has not been initialized yet. - unsafe { bindings::auxiliary_device_init(adev) }; - - // Now that `adev` is initialized, leak the `Box`; the corresp= onding memory will be - // freed by `Device::release` when the last reference to the `= struct auxiliary_device` - // is dropped. - let _ =3D KBox::into_raw(boxed); - - // SAFETY: - // - `adev` is guaranteed to be a valid pointer to a `struct a= uxiliary_device`, which - // has been initialized, - // - `modname.as_char_ptr()` is a NULL terminated string. - let ret =3D unsafe { bindings::__auxiliary_device_add(adev, mo= dname.as_char_ptr()) }; - if ret !=3D 0 { - // SAFETY: `adev` is guaranteed to be a valid pointer to a - // `struct auxiliary_device`, which has been initialized. - unsafe { bindings::auxiliary_device_uninit(adev) }; - - return Err(Error::from_errno(ret)); - } - - // INVARIANT: The device will remain registered until `auxilia= ry_device_delete()` is - // called, which happens in `Self::drop()`. - Ok(Devres::new( - parent, - // SAFETY: `adev` is guaranteed to be non-null, since the = `KBox` was allocated - // successfully. - Self(unsafe { NonNull::new_unchecked(adev) }), - )) - }) + modname: &CStr, + data: impl PinInit, + ) -> Result> + where + Error: From, + { + let data =3D KBox::pin_init::( + try_pin_init!(RegistrationData { + type_id: TypeId::of::(), + data <- data, + }), + GFP_KERNEL, + )?; + + let boxed: KBox> =3D KBox::zero= ed(GFP_KERNEL)?; + let adev =3D boxed.get(); + + // SAFETY: It's safe to set the fields of `struct auxiliary_device= ` on initialization. + unsafe { + (*adev).dev.parent =3D parent.as_raw(); + (*adev).dev.release =3D Some(Device::release); + (*adev).name =3D name.as_char_ptr(); + (*adev).id =3D id; + (*adev).registration_data_rust =3D data.into_foreign(); + } + + // SAFETY: `adev` is guaranteed to be a valid pointer to a `struct= auxiliary_device`, + // which has not been initialized yet. + unsafe { bindings::auxiliary_device_init(adev) }; + + // Now that `adev` is initialized, leak the `Box`; the correspondi= ng memory will be + // freed by `Device::release` when the last reference to the `stru= ct auxiliary_device` + // is dropped. + let _ =3D KBox::into_raw(boxed); + + // SAFETY: + // - `adev` is guaranteed to be a valid pointer to a `struct auxil= iary_device`, which + // has been initialized, + // - `modname.as_char_ptr()` is a NULL terminated string. + let ret =3D unsafe { bindings::__auxiliary_device_add(adev, modnam= e.as_char_ptr()) }; + if ret !=3D 0 { + // SAFETY: `registration_data` was set above via `into_foreign= ()`. + drop(unsafe { + Pin::>>::from_foreign((*adev).reg= istration_data_rust) + }); + + // SAFETY: `adev` is guaranteed to be a valid pointer to a + // `struct auxiliary_device`, which has been initialized. + unsafe { bindings::auxiliary_device_uninit(adev) }; + + return Err(Error::from_errno(ret)); + } + + // INVARIANT: The device will remain registered until `auxiliary_d= evice_delete()` is + // called, which happens in `Self::drop()`. + let reg =3D Self { + // SAFETY: `adev` is guaranteed to be non-null, since the `KBo= x` was allocated + // successfully. + adev: unsafe { NonNull::new_unchecked(adev) }, + _data: PhantomData, + }; + + Devres::new::(parent, reg) } } =20 -impl Drop for Registration { +impl Drop for Registration { fn drop(&mut self) { - // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a= valid registered + // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` i= s a valid registered // `struct auxiliary_device`. - unsafe { bindings::auxiliary_device_delete(self.0.as_ptr()) }; + unsafe { bindings::auxiliary_device_delete(self.adev.as_ptr()) }; + + // SAFETY: `registration_data` was set in `new()` via `into_foreig= n()`. + drop(unsafe { + Pin::>>::from_foreign( + (*self.adev.as_ptr()).registration_data_rust, + ) + }); =20 // This drops the reference we acquired through `auxiliary_device_= init()`. // - // SAFETY: By the type invariant of `Self`, `self.0.as_ptr()` is a= valid registered + // SAFETY: By the type invariant of `Self`, `self.adev.as_ptr()` i= s a valid registered // `struct auxiliary_device`. - unsafe { bindings::auxiliary_device_uninit(self.0.as_ptr()) }; + unsafe { bindings::auxiliary_device_uninit(self.adev.as_ptr()) }; } } =20 // SAFETY: A `Registration` of a `struct auxiliary_device` can be released= from any thread. -unsafe impl Send for Registration {} +unsafe impl Send for Registration {} =20 // SAFETY: `Registration` does not expose any methods or fields that need = synchronization. -unsafe impl Sync for Registration {} +unsafe impl Sync for Registration {} diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driv= er_auxiliary.rs index 5c5a5105a3ff..319ef734c02b 100644 --- a/samples/rust/rust_driver_auxiliary.rs +++ b/samples/rust/rust_driver_auxiliary.rs @@ -17,8 +17,6 @@ InPlaceModule, // }; =20 -use core::any::TypeId; - const MODULE_NAME: &CStr =3D ::NAME; const AUXILIARY_NAME: &CStr =3D c"auxiliary"; =20 @@ -49,13 +47,13 @@ fn probe(adev: &auxiliary::Device, _info: &Self::= IdInfo) -> impl PinInit, - #[pin] - _reg1: Devres, + _reg0: Devres>, + _reg1: Devres>, } =20 kernel::pci_device_table!( @@ -71,10 +69,21 @@ impl pci::Driver for ParentDriver { const ID_TABLE: pci::IdTable =3D &PCI_TABLE; =20 fn probe(pdev: &pci::Device, _info: &Self::IdInfo) -> impl PinIn= it { - try_pin_init!(Self { - private: TypeId::of::(), - _reg0 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY= _NAME, 0, MODULE_NAME), - _reg1 <- auxiliary::Registration::new(pdev.as_ref(), AUXILIARY= _NAME, 1, MODULE_NAME), + Ok(Self { + _reg0: auxiliary::Registration::new( + pdev.as_ref(), + AUXILIARY_NAME, + 0, + MODULE_NAME, + Data { index: 0 }, + )?, + _reg1: auxiliary::Registration::new( + pdev.as_ref(), + AUXILIARY_NAME, + 1, + MODULE_NAME, + Data { index: 1 }, + )?, }) } } @@ -83,7 +92,8 @@ impl ParentDriver { fn connect(adev: &auxiliary::Device) -> Result { let dev =3D adev.parent(); let pdev: &pci::Device =3D dev.try_into()?; - let drvdata =3D dev.drvdata::()?; + + let data =3D adev.registration_data::()?; =20 dev_info!( dev, @@ -95,8 +105,8 @@ fn connect(adev: &auxiliary::Device) -> Result { =20 dev_info!( dev, - "We have access to the private data of {:?}.\n", - drvdata.private + "Connected to auxiliary device with index {}.\n", + data.index ); =20 Ok(()) --=20 2.54.0 From nobody Sat Jun 13 20:19:42 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 07F1E481FAF; Tue, 5 May 2026 15:24:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777994660; cv=none; b=K+FDbrZXP/B9x0sc82LGPb0iJzTOj4+/m7INLDsZLGcw3rzmHq5HZhR6msJuzsww+izxSbtSK16rtxjmqsiv04ISxqr90IaaZdc2HTb4vZEGTiwBwTo1U/EcD81pnD32SSFXcgfDfQQVgyTBWiqfo8iQRH7O/B2WnfYP0w2Zcos= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777994660; c=relaxed/simple; bh=dC7AHxeF5HBFGmWhygEDRND5nAaKwuopbPHrGPWQa68=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RN+cYSEJ6zASaif1aV+BnykwkX8YX0Ncg2CB7lbV6wul+a3sxGO5ZszO3dtV2p7knM0DOCZndKlZJrir741vApk5C8Minvgu4RwWShVTmRnU1AfihetcI4gqe/+HSXrOhvnJgtVD/p0pZ/es9MLuDiZXEVs/egoLY2Ds++YVXrs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dEUvZKHJ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dEUvZKHJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EB21CC2BCF4; Tue, 5 May 2026 15:24:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1777994659; bh=dC7AHxeF5HBFGmWhygEDRND5nAaKwuopbPHrGPWQa68=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dEUvZKHJkYv36Vu8X9bDVLSXK2Bf79p4daOvLsDuQbiCBzpIa9oqYJvJDezD8t0B5 zBJskNfqg0dVPOfsE7xxi6ItfJfFWFcvCP0/7Amm60Pbgtx/fmemd8H3Y7thGGlgTJ GXeDwEeWXPgbyY9s+8a6PbwZCVrNpLBo9kNfnXyTjgvj2BOwZ4xx0nPrufbUYHK4ak 138zZUPa++ZJfrfUMCDeCrYRC+YLff3VPlSf2GWMK9Z8TyfaBLDC/zmhyxLi7CpF0V esjOANc+gHnFpDPSsZYd6NJEwR8GvjXGBTdXUb+3PTTlvFft1qw7Cz20s1uH0xi+WX NdI//19YYUDfA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, acourbot@nvidia.com, aliceryhl@google.com, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, ojeda@kernel.org, boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org, nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org, Danilo Krummrich Subject: [PATCH v2 3/3] rust: driver core: remove drvdata() and driver_type Date: Tue, 5 May 2026 17:23:09 +0200 Message-ID: <20260505152400.3905096-4-dakr@kernel.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505152400.3905096-1-dakr@kernel.org> References: <20260505152400.3905096-1-dakr@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When drvdata() was introduced in commit 6f61a2637abe ("rust: device: introduce Device::drvdata()"), its commit message already noted that a direct accessor to the driver's bus device private data is not commonly required -- bus callbacks provide access through &self, and other entry points (IRQs, workqueues, IOCTLs, etc.) carry their own private data. The sole motivation for drvdata() was inter-driver interaction -- an auxiliary driver deriving the parent's bus device private data from the parent device. However, drvdata() exposes the driver's bus device private data beyond the driver's own scope. This creates ordering constraints; for instance drvdata may not be set yet when the first caller of drvdata() can appear. It also forces the driver's bus device private data to outlive all registrations that access it, which causes unnecessary complications. Private data should be private to the entity that issues it, i.e. bus device private data belongs to bus callbacks, class device private data to class callbacks, IRQ private data to the IRQ handler, etc. With registration-private data now available through the auxiliary bus, there is no remaining user of drvdata(), thus remove it. Reviewed-by: Alice Ryhl Signed-off-by: Danilo Krummrich --- drivers/base/base.h | 16 ------------ rust/kernel/device.rs | 60 ------------------------------------------- 2 files changed, 76 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index 0ed1e278b957..483b99b4fa3d 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -86,18 +86,6 @@ struct driver_private { }; #define to_driver(obj) container_of(obj, struct driver_private, kobj) =20 -#ifdef CONFIG_RUST -/** - * struct driver_type - Representation of a Rust driver type. - */ -struct driver_type { - /** - * @id: Representation of core::any::TypeId. - */ - u8 id[16]; -} __packed; -#endif - /** * struct device_private - structure to hold the private to the driver core * portions of the device structure. @@ -115,7 +103,6 @@ struct driver_type { * dev_err_probe() for later retrieval via debugfs * @device: pointer back to the struct device that this structure is * associated with. - * @driver_type: The type of the bound Rust driver. * @dead: This device is currently either in the process of or has been * removed from the system. Any asynchronous events scheduled for this * device should exit without taking any action. @@ -132,9 +119,6 @@ struct device_private { const struct device_driver *async_driver; char *deferred_probe_reason; struct device *device; -#ifdef CONFIG_RUST - struct driver_type driver_type; -#endif u8 dead:1; }; #define to_device_private_parent(obj) \ diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 6d5396a43ebe..fd50399aadea 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -15,16 +15,12 @@ }, // }; use core::{ - any::TypeId, marker::PhantomData, ptr, // }; =20 pub mod property; =20 -// Assert that we can `read()` / `write()` a `TypeId` instance from / into= `struct driver_type`. -static_assert!(core::mem::size_of::() >=3D core::me= m::size_of::()); - /// The core representation of a device in the kernel's driver model. /// /// This structure represents the Rust abstraction for a C `struct device`= . A [`Device`] can either @@ -206,29 +202,12 @@ pub unsafe fn as_bound(&self) -> &Device { } =20 impl Device { - fn set_type_id(&self) { - // SAFETY: By the type invariants, `self.as_raw()` is a valid poin= ter to a `struct device`. - let private =3D unsafe { (*self.as_raw()).p }; - - // SAFETY: For a bound device (implied by the `CoreInternal` devic= e context), `private` is - // guaranteed to be a valid pointer to a `struct device_private`. - let driver_type =3D unsafe { &raw mut (*private).driver_type }; - - // SAFETY: `driver_type` is valid for (unaligned) writes of a `Typ= eId`. - unsafe { - driver_type - .cast::() - .write_unaligned(TypeId::of::()) - }; - } - /// Store a pointer to the bound driver's private data. pub fn set_drvdata(&self, data: impl PinInit) ->= Result { let data =3D KBox::pin_init(data, GFP_KERNEL)?; =20 // SAFETY: By the type invariants, `self.as_raw()` is a valid poin= ter to a `struct device`. unsafe { bindings::dev_set_drvdata(self.as_raw(), data.into_foreig= n().cast()) }; - self.set_type_id::(); =20 Ok(()) } @@ -292,45 +271,6 @@ unsafe fn drvdata_unchecked(&self) -> Pin<= &T> { // in `into_foreign()`. unsafe { Pin::>::borrow(ptr.cast()) } } - - fn match_type_id(&self) -> Result { - // SAFETY: By the type invariants, `self.as_raw()` is a valid poin= ter to a `struct device`. - let private =3D unsafe { (*self.as_raw()).p }; - - // SAFETY: For a bound device, `private` is guaranteed to be a val= id pointer to a - // `struct device_private`. - let driver_type =3D unsafe { &raw mut (*private).driver_type }; - - // SAFETY: - // - `driver_type` is valid for (unaligned) reads of a `TypeId`. - // - A bound device guarantees that `driver_type` contains a valid= `TypeId` value. - let type_id =3D unsafe { driver_type.cast::().read_unalign= ed() }; - - if type_id !=3D TypeId::of::() { - return Err(EINVAL); - } - - Ok(()) - } - - /// Access a driver's private data. - /// - /// Returns a pinned reference to the driver's private data or [`EINVA= L`] if it doesn't match - /// the asserted type `T`. - pub fn drvdata(&self) -> Result> { - // SAFETY: By the type invariants, `self.as_raw()` is a valid poin= ter to a `struct device`. - if unsafe { bindings::dev_get_drvdata(self.as_raw()) }.is_null() { - return Err(ENOENT); - } - - self.match_type_id::()?; - - // SAFETY: - // - The above check of `dev_get_drvdata()` guarantees that we are= called after - // `set_drvdata()`. - // - We've just checked that the type of the driver's private data= is in fact `T`. - Ok(unsafe { self.drvdata_unchecked() }) - } } =20 impl Device { --=20 2.54.0