From nobody Mon Feb 9 04:28:48 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 B1FB51A256E; Wed, 7 Jan 2026 10:35:32 +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=1767782134; cv=none; b=pc4i0MvlFMZYdONRpV4d7cUnnt9thFTJOiR2PXXVaUfUdDZdtpwbtJW8hc3t50hx+F6k4uqWZcFOhKBFrupUZ83rZ7NBhYtTScWlisvmR669eTFUmmHkl7QMDjQ3rmF/QPbRhNfRVJuBJS2KdCW6ah7T+WzjIKVOb3uPYImXpeE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767782134; c=relaxed/simple; bh=X8ZIdLz52lID4KcbD2/RyqCVe4O73zttkiWiiUuQlI4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=r4lkX2zEoLIIpZoMSClWHzhpUX1RSiVbZSqF8hre11G6uoXgdPPC4wUSj+fiGzHmB0VdqYR5qzEF2HzxXrwPF1mKJWQm/9O2NIXpSJcsUGwvMmlKtvhiLgLyvsA1GaGhAyBTK5po4Y0NTKILkRuHG+5E8Wh0n6J/8CftZlk0+dU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=m7uzCv0i; 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="m7uzCv0i" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C8031C16AAE; Wed, 7 Jan 2026 10:35:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767782132; bh=X8ZIdLz52lID4KcbD2/RyqCVe4O73zttkiWiiUuQlI4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=m7uzCv0ilkIpGVoWfccHm9ouZSYQ0Ud9DNjiURW1b48jsQ3MY+nicCNFbt17gUq+J M5Sd3iuORE86hDIXi++h+yIL7vADY8MTngD2ii0IGFJ/lqpvsUtGG27T13ZVBCkQey m3Jj0AoEc0Bsu2SQTUkCbJ9hXYhZvt2EUaHPfO7f8NuamXuOT6EG5wlJaQVmTmygQI JbJTntMc+/Zahwp40E9iPTzNGXzYI1jGBfRRhTENJO8uMf8akzK1hDYAl1TqpLbtwt tkrnCxkouGRXB1bQqPyn0AxlTDAJVC9A28C8+6D7RHMJFKDJZdhqOpYL1ax/0LO6+u hTcYqqre2t60A== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, igor.korotin.linux@gmail.com, ojeda@kernel.org, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, wsa+renesas@sang-engineering.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-pci@vger.kernel.org, linux-usb@vger.kernel.org, linux-i2c@vger.kernel.org, Danilo Krummrich Subject: [PATCH 1/6] rust: i2c: do not drop device private data on shutdown() Date: Wed, 7 Jan 2026 11:35:00 +0100 Message-ID: <20260107103511.570525-2-dakr@kernel.org> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260107103511.570525-1-dakr@kernel.org> References: <20260107103511.570525-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" We must not drop the device private data on shutdown(); none of the registrations attached to devres that might access the device private data are released before shutdown() is called. Hence, freeing the device private data on shutdown() can cause UAF bugs. Fixes: 57c5bd9aee94 ("rust: i2c: add basic I2C device and driver abstractio= ns") Signed-off-by: Danilo Krummrich Acked-by: Alice Ryhl --- rust/kernel/i2c.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 491e6cc25cf4..35b678b78d91 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -181,9 +181,9 @@ extern "C" fn shutdown_callback(idev: *mut bindings::i2= c_client) { // SAFETY: `shutdown_callback` is only ever called after a success= ful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { idev.as_ref().drvdata_obtain::() }; + let data =3D unsafe { idev.as_ref().drvdata_borrow::() }; =20 - T::shutdown(idev, data.as_ref()); + T::shutdown(idev, data); } =20 /// The [`i2c::IdTable`] of the corresponding driver. --=20 2.52.0 From nobody Mon Feb 9 04:28:48 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 7E071301037; Wed, 7 Jan 2026 10:35:37 +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=1767782137; cv=none; b=gp0ZERn8CJ9sAKJ9uc4fUGUFeaSadZ4bjVHuTqVeFTdhCCQgGrIAojKnlCW08VTPTm8QdGhQbQRQBS59SUINpdgx8ctRmQoZodrEjZRmtLT/CvkNN4HfBdiyd7wZ5atl2FJ3uiYSOyOSXWhs+shZU2RGYyTDH732lJjPMUNQX9I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767782137; c=relaxed/simple; bh=UrLC3ImC0rFV+2liGhx/jCiQxmj7gIB4UnCVUnC/S1M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Fdtn4WHdmPlw/bjMmZyO/mdp6H5mnzCh/N7syvbTf6NBIo6Xldlwn04BrOQApWL82Sr82b3SdknnlzwthLEifpnw26miyNIoUKA/tA7S/QZcPOsyspjIkmNbxaaxH6IbBEGWoTtVerbUYVH/GZYI6/SFiAihNrDmYOZfLcpaJB0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JSQ50ZwX; 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="JSQ50ZwX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A74A9C4CEF7; Wed, 7 Jan 2026 10:35:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767782137; bh=UrLC3ImC0rFV+2liGhx/jCiQxmj7gIB4UnCVUnC/S1M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JSQ50ZwXMKZcLWiBQQtmKoFnSudxMxgQ9mNHoxA9dU/xiN9qTIqrDkBLbWPNXkKxz fuahCVkdHnmPljBGfVc+PkIG2Vyept8vzUaPl7Go+xta5cxde/azhgwn2JEak2Hom+ 1S0WV0pRfagA59n+Q8fvkdRgyUIzBjOId02IAO0+BbWF2FjGfrG4JLFRd+V1JIfxwa hwMhzlQ5K4psogXzeAO5aPYjDso4G1xi/NNIn2QkmXOlZIwC07jzYLcSsU6BbrK1qz DmUn0avEpXTNfG5wMIY3znKgX98gpykFvA+IlCb741n6RITWDGY//EXKwRNnjJeErs mh6CPdl0xZbfw== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, igor.korotin.linux@gmail.com, ojeda@kernel.org, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, wsa+renesas@sang-engineering.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-pci@vger.kernel.org, linux-usb@vger.kernel.org, linux-i2c@vger.kernel.org, Danilo Krummrich Subject: [PATCH 2/6] rust: auxiliary: add Driver::unbind() callback Date: Wed, 7 Jan 2026 11:35:01 +0100 Message-ID: <20260107103511.570525-3-dakr@kernel.org> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260107103511.570525-1-dakr@kernel.org> References: <20260107103511.570525-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 missing unbind() callback to auxiliary::Driver, since it will be needed by drivers eventually (e.g. the Nova DRM driver). Signed-off-by: Danilo Krummrich Acked-by: Alice Ryhl --- Strictly speaking, this is not a dependency, but without this patch the ma= in fix of this series leaves the remove() callback of the auxiliary bus abstraction with either dead code or quite some code removed; code that we would otherwise add back immediately afterwards. --- rust/kernel/auxiliary.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 56f3c180e8f6..6931f8a4267f 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -87,7 +87,9 @@ extern "C" fn remove_callback(adev: *mut bindings::auxili= ary_device) { // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - drop(unsafe { adev.as_ref().drvdata_obtain::() }); + let data =3D unsafe { adev.as_ref().drvdata_obtain::() }; + + T::unbind(adev, data.as_ref()); } } =20 @@ -187,6 +189,20 @@ pub trait Driver { /// /// Called when an auxiliary device is matches a corresponding driver. fn probe(dev: &Device, id_info: &Self::IdInfo) -> impl P= inInit; + + /// Auxiliary driver unbind. + /// + /// Called when a [`Device`] is unbound from its bound [`Driver`]. Imp= lementing this callback + /// is optional. + /// + /// This callback serves as a place for drivers to perform teardown op= erations that require a + /// `&Device` or `&Device` reference. For instance, drive= rs may try to perform I/O + /// operations to gracefully tear down the device. + /// + /// Otherwise, release operations for driver resources should be perfo= rmed in `Self::drop`. + fn unbind(dev: &Device, this: Pin<&Self>) { + let _ =3D (dev, this); + } } =20 /// The auxiliary device representation. --=20 2.52.0 From nobody Mon Feb 9 04:28:48 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 1A32A2FE598; Wed, 7 Jan 2026 10:35:42 +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=1767782142; cv=none; b=l21RDWiZVqySSwg4iQ7xfQI9X4la+TpWK2S02DZ0ASunMDG4cvEgfbI3JxVz7fiZRrAGvhkD2cnsY8bhDD9BXOekfYdyPWR2TeD1Qh6m8t/L4SDHL3QwLDRw998lHW+tVxuKNdzZRncSqXgBJoDTWZWgSeMQMpZsPwhHPJ9kE/Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767782142; c=relaxed/simple; bh=B+z322KMnYbfcjFFuMw+36goZ+N9VTbu195hG8ORH7k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bZHV3CXuGBb48aXfdoPhTld/d6fkJFJ61UO9movT605vkwdPmlInZsWiZTQIXTkiOE0fAcL//2buJkMOe6ThIeCt7L9KlJcs0xMQ/9oaMMNZZDroNRUrvj9K/K7+f2T5yN7SEVpWyqelaoUaI65bdiIaypFm4fvPfiJXHG5EBzQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=HqbPkeK8; 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="HqbPkeK8" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 88046C16AAE; Wed, 7 Jan 2026 10:35:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767782142; bh=B+z322KMnYbfcjFFuMw+36goZ+N9VTbu195hG8ORH7k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HqbPkeK8as/8q01IVmbG8HOxHoN607JQA5xaM7yCKLoHNlK9rMH1gVTARWEQfzhwN dvHoH8Q19PzIZJyfw9ZLD91g3JYZf2614USJgp74NTaiICIhUGNjX5NywXRg9O8rXl Sg4M+5tHl2bXObgN9mFMqkU1t3ZRSWPdDZMKehb7IBBxabhKgIywK+iYyRyj3WGumS Kw/yS1MfYp48lpqDJkMZAiBw96mIp4gQY2zQ+DTsfZ3eVzR2CEoIgwWSFtLl0pdfXb w43F96e/F+nFQqmU8DbUmOD6Zm8ysxbViKnVIbOmAHXNCS4dqf9VZC/tTNUTAu+sQY zgMJKY530NZsA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, igor.korotin.linux@gmail.com, ojeda@kernel.org, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, wsa+renesas@sang-engineering.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-pci@vger.kernel.org, linux-usb@vger.kernel.org, linux-i2c@vger.kernel.org, Danilo Krummrich Subject: [PATCH 3/6] rust: driver: introduce a common Driver trait Date: Wed, 7 Jan 2026 11:35:02 +0100 Message-ID: <20260107103511.570525-4-dakr@kernel.org> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260107103511.570525-1-dakr@kernel.org> References: <20260107103511.570525-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" The Driver trait describes the layout of a specific driver structure, such as `struct pci_driver` or `struct platform_driver`. In a first step, this replaces the associated type RegType of the RegistrationOps with the Driver::DriverType associated type. Signed-off-by: Danilo Krummrich Acked-by: Alice Ryhl Acked-by: Igor Korotin --- rust/kernel/auxiliary.rs | 18 +++++++++++------- rust/kernel/driver.rs | 40 +++++++++++++++++++++++++--------------- rust/kernel/i2c.rs | 18 +++++++++++------- rust/kernel/pci.rs | 18 +++++++++++------- rust/kernel/platform.rs | 18 +++++++++++------- rust/kernel/usb.rs | 18 +++++++++++------- 6 files changed, 80 insertions(+), 50 deletions(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 6931f8a4267f..4636b6f41195 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -23,13 +23,17 @@ /// An adapter for the registration of auxiliary drivers. pub struct Adapter(T); =20 -// SAFETY: A call to `unregister` for a given instance of `RegType` is gua= ranteed to be valid if +// SAFETY: +// - `bindings::auxiliary_driver` is a C type declared as `repr(C)`. +unsafe impl driver::Driver for Adapter { + type DriverType =3D bindings::auxiliary_driver; +} + +// SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. unsafe impl driver::RegistrationOps for Adapter { - type RegType =3D bindings::auxiliary_driver; - unsafe fn register( - adrv: &Opaque, + adrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -41,14 +45,14 @@ unsafe fn register( (*adrv.get()).id_table =3D T::ID_TABLE.as_ptr(); } =20 - // SAFETY: `adrv` is guaranteed to be a valid `RegType`. + // SAFETY: `adrv` is guaranteed to be a valid `DriverType`. to_result(unsafe { bindings::__auxiliary_driver_register(adrv.get(), module.0, na= me.as_char_ptr()) }) } =20 - unsafe fn unregister(adrv: &Opaque) { - // SAFETY: `adrv` is guaranteed to be a valid `RegType`. + unsafe fn unregister(adrv: &Opaque) { + // SAFETY: `adrv` is guaranteed to be a valid `DriverType`. unsafe { bindings::auxiliary_driver_unregister(adrv.get()) } } } diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 649d06468f41..cd1d36c313e1 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -99,23 +99,33 @@ use core::pin::Pin; use pin_init::{pin_data, pinned_drop, PinInit}; =20 +/// Trait describing the layout of a specific device driver. +/// +/// This trait describes the layout of a specific driver structure, such a= s `struct pci_driver` or +/// `struct platform_driver`. +/// +/// # Safety +/// +/// Implementors must guarantee that: +/// - `DriverType` is `repr(C)`. +pub unsafe trait Driver { + /// The specific driver type embedding a `struct device_driver`. + type DriverType: Default; +} + /// The [`RegistrationOps`] trait serves as generic interface for subsyste= ms (e.g., PCI, Platform, /// Amba, etc.) to provide the corresponding subsystem specific implementa= tion to register / -/// unregister a driver of the particular type (`RegType`). +/// unregister a driver of the particular type (`DriverType`). /// -/// For instance, the PCI subsystem would set `RegType` to `bindings::pci_= driver` and call +/// For instance, the PCI subsystem would set `DriverType` to `bindings::p= ci_driver` and call /// `bindings::__pci_register_driver` from `RegistrationOps::register` and /// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. /// /// # Safety /// -/// A call to [`RegistrationOps::unregister`] for a given instance of `Reg= Type` is only valid if a -/// preceding call to [`RegistrationOps::register`] has been successful. -pub unsafe trait RegistrationOps { - /// The type that holds information about the registration. This is ty= pically a struct defined - /// by the C portion of the kernel. - type RegType: Default; - +/// A call to [`RegistrationOps::unregister`] for a given instance of `Dri= verType` is only valid if +/// a preceding call to [`RegistrationOps::register`] has been successful. +pub unsafe trait RegistrationOps: Driver { /// Registers a driver. /// /// # Safety @@ -123,7 +133,7 @@ pub unsafe trait RegistrationOps { /// On success, `reg` must remain pinned and valid until the matching = call to /// [`RegistrationOps::unregister`]. unsafe fn register( - reg: &Opaque, + reg: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result; @@ -134,7 +144,7 @@ unsafe fn register( /// /// Must only be called after a preceding successful call to [`Registr= ationOps::register`] for /// the same `reg`. - unsafe fn unregister(reg: &Opaque); + unsafe fn unregister(reg: &Opaque); } =20 /// A [`Registration`] is a generic type that represents the registration = of some driver type (e.g. @@ -146,7 +156,7 @@ unsafe fn register( #[pin_data(PinnedDrop)] pub struct Registration { #[pin] - reg: Opaque, + reg: Opaque, } =20 // SAFETY: `Registration` has no fields or methods accessible via `&Regist= ration`, so it is safe to @@ -161,13 +171,13 @@ impl Registration { /// Creates a new instance of the registration object. pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl P= inInit { try_pin_init!(Self { - reg <- Opaque::try_ffi_init(|ptr: *mut T::RegType| { + reg <- Opaque::try_ffi_init(|ptr: *mut T::DriverType| { // SAFETY: `try_ffi_init` guarantees that `ptr` is valid f= or write. - unsafe { ptr.write(T::RegType::default()) }; + unsafe { ptr.write(T::DriverType::default()) }; =20 // SAFETY: `try_ffi_init` guarantees that `ptr` is valid f= or write, and it has // just been initialised above, so it's also valid for rea= d. - let drv =3D unsafe { &*(ptr as *const Opaque) = }; + let drv =3D unsafe { &*(ptr as *const Opaque) }; =20 // SAFETY: `drv` is guaranteed to be pinned until `T::unre= gister`. unsafe { T::register(drv, name, module) } diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 35b678b78d91..de35961c6903 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -92,13 +92,17 @@ macro_rules! i2c_device_table { /// An adapter for the registration of I2C drivers. pub struct Adapter(T); =20 -// SAFETY: A call to `unregister` for a given instance of `RegType` is gua= ranteed to be valid if +// SAFETY: +// - `bindings::i2c_driver` is a C type declared as `repr(C)`. +unsafe impl driver::Driver for Adapter { + type DriverType =3D bindings::i2c_driver; +} + +// SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. unsafe impl driver::RegistrationOps for Adapter { - type RegType =3D bindings::i2c_driver; - unsafe fn register( - idrv: &Opaque, + idrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -133,12 +137,12 @@ unsafe fn register( (*idrv.get()).driver.acpi_match_table =3D acpi_table; } =20 - // SAFETY: `idrv` is guaranteed to be a valid `RegType`. + // SAFETY: `idrv` is guaranteed to be a valid `DriverType`. to_result(unsafe { bindings::i2c_register_driver(module.0, idrv.ge= t()) }) } =20 - unsafe fn unregister(idrv: &Opaque) { - // SAFETY: `idrv` is guaranteed to be a valid `RegType`. + unsafe fn unregister(idrv: &Opaque) { + // SAFETY: `idrv` is guaranteed to be a valid `DriverType`. unsafe { bindings::i2c_del_driver(idrv.get()) } } } diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 82e128431f08..f58ce35d9c60 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -50,13 +50,17 @@ /// An adapter for the registration of PCI drivers. pub struct Adapter(T); =20 -// SAFETY: A call to `unregister` for a given instance of `RegType` is gua= ranteed to be valid if +// SAFETY: +// - `bindings::pci_driver` is a C type declared as `repr(C)`. +unsafe impl driver::Driver for Adapter { + type DriverType =3D bindings::pci_driver; +} + +// SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. unsafe impl driver::RegistrationOps for Adapter { - type RegType =3D bindings::pci_driver; - unsafe fn register( - pdrv: &Opaque, + pdrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -68,14 +72,14 @@ unsafe fn register( (*pdrv.get()).id_table =3D T::ID_TABLE.as_ptr(); } =20 - // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. + // SAFETY: `pdrv` is guaranteed to be a valid `DriverType`. to_result(unsafe { bindings::__pci_register_driver(pdrv.get(), module.0, name.as_= char_ptr()) }) } =20 - unsafe fn unregister(pdrv: &Opaque) { - // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. + unsafe fn unregister(pdrv: &Opaque) { + // SAFETY: `pdrv` is guaranteed to be a valid `DriverType`. unsafe { bindings::pci_unregister_driver(pdrv.get()) } } } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index ed889f079cab..e48d055fdc8a 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -26,13 +26,17 @@ /// An adapter for the registration of platform drivers. pub struct Adapter(T); =20 -// SAFETY: A call to `unregister` for a given instance of `RegType` is gua= ranteed to be valid if +// SAFETY: +// - `bindings::platform_driver` is a C type declared as `repr(C)`. +unsafe impl driver::Driver for Adapter { + type DriverType =3D bindings::platform_driver; +} + +// SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. unsafe impl driver::RegistrationOps for Adapter { - type RegType =3D bindings::platform_driver; - unsafe fn register( - pdrv: &Opaque, + pdrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -55,12 +59,12 @@ unsafe fn register( (*pdrv.get()).driver.acpi_match_table =3D acpi_table; } =20 - // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. + // SAFETY: `pdrv` is guaranteed to be a valid `DriverType`. to_result(unsafe { bindings::__platform_driver_register(pdrv.get()= , module.0) }) } =20 - unsafe fn unregister(pdrv: &Opaque) { - // SAFETY: `pdrv` is guaranteed to be a valid `RegType`. + unsafe fn unregister(pdrv: &Opaque) { + // SAFETY: `pdrv` is guaranteed to be a valid `DriverType`. unsafe { bindings::platform_driver_unregister(pdrv.get()) }; } } diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index d10b65e9fb6a..32f4b2d55dfb 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -27,13 +27,17 @@ /// An adapter for the registration of USB drivers. pub struct Adapter(T); =20 -// SAFETY: A call to `unregister` for a given instance of `RegType` is gua= ranteed to be valid if +// SAFETY: +// - `bindings::usb_driver` is a C type declared as `repr(C)`. +unsafe impl driver::Driver for Adapter { + type DriverType =3D bindings::usb_driver; +} + +// SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if // a preceding call to `register` has been successful. unsafe impl driver::RegistrationOps for Adapter { - type RegType =3D bindings::usb_driver; - unsafe fn register( - udrv: &Opaque, + udrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -45,14 +49,14 @@ unsafe fn register( (*udrv.get()).id_table =3D T::ID_TABLE.as_ptr(); } =20 - // SAFETY: `udrv` is guaranteed to be a valid `RegType`. + // SAFETY: `udrv` is guaranteed to be a valid `DriverType`. to_result(unsafe { bindings::usb_register_driver(udrv.get(), module.0, name.as_ch= ar_ptr()) }) } =20 - unsafe fn unregister(udrv: &Opaque) { - // SAFETY: `udrv` is guaranteed to be a valid `RegType`. + unsafe fn unregister(udrv: &Opaque) { + // SAFETY: `udrv` is guaranteed to be a valid `DriverType`. unsafe { bindings::usb_deregister(udrv.get()) }; } } --=20 2.52.0 From nobody Mon Feb 9 04:28:48 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 41C8430CDAE; Wed, 7 Jan 2026 10:35:46 +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=1767782147; cv=none; b=oQ5RmDw0FBkXrwA8tvC/HVW3sN8h95MknfCVBzzhtMYL3s6EElpLbDLAifuZK0neekTU0ElLQn7ZAYew9MlPxtEDAH9J4ZXHwdH/nFK6FvkZ40xdKHvg5gIwaK7SY4bAaeoQH/T+XKJyKKe9fRf0KELfnYer5iYA0swtVc960MA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767782147; c=relaxed/simple; bh=nKi5JZBd4Qk8YIPjid5tlqj4dzXK6qTcsyr69Qf6nDA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=l/3bvHZVH74IbOiedYlVF1gWqaDhLzjLHrzwmif8ZqZhxh7+4k013CWeqYez1x/3eNh9dlsTreAGMas4GcABvGNSF5kBiiaWgmZtykc8kraRIY+q+Pt6btii9yUyzaPx1qmRSFbxjmTSPT4u+ZYnlXrbw7qmfNMK0i4uZQ4HrsU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=r+mBiSsk; 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="r+mBiSsk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 67854C4CEF7; Wed, 7 Jan 2026 10:35:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767782146; bh=nKi5JZBd4Qk8YIPjid5tlqj4dzXK6qTcsyr69Qf6nDA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=r+mBiSsk5pT2PDoez9jdXvUDuOz5SBSzJa4x+uu+vPQbLAZt/W1ILE2h92MagbJau r5A01hhBHIBeUcotbR0EDJsl6W2Xb0IYKDgxP3yVglfwqvQTaXXih4zXqJ5NY8VbWS 1aUQGUg7zSuYJa9VbkcfIp/LtcQNOpThMie4L+xoMHeY+QmmDf8+lVva2DPAXnPcdd 1tImBwGh/TLZHUdaoBTwlfAJwOtAUv/9/6Vu53kMybQIW2b6NDLWZeIglTIyztUoTj TOUblttDkuAPqIN+s55lJK00oBEfYP0qdOP8YOk3yNRu7jnJRtMsGtxekTkMrBYKuO 4H0ElNJy5YUrA== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, igor.korotin.linux@gmail.com, ojeda@kernel.org, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, wsa+renesas@sang-engineering.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-pci@vger.kernel.org, linux-usb@vger.kernel.org, linux-i2c@vger.kernel.org, Danilo Krummrich Subject: [PATCH 4/6] rust: driver: add DEVICE_DRIVER_OFFSET to the Driver trait Date: Wed, 7 Jan 2026 11:35:03 +0100 Message-ID: <20260107103511.570525-5-dakr@kernel.org> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260107103511.570525-1-dakr@kernel.org> References: <20260107103511.570525-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 an associated const DEVICE_DRIVER_OFFSET to the Driver trait indicating the offset of the embedded struct device_driver within Self::DriverType, i.e. the specific driver structs, such as struct pci_driver or struct platform_driver. Signed-off-by: Danilo Krummrich Acked-by: Alice Ryhl --- rust/kernel/auxiliary.rs | 3 +++ rust/kernel/driver.rs | 8 +++++++- rust/kernel/i2c.rs | 3 +++ rust/kernel/pci.rs | 3 +++ rust/kernel/platform.rs | 3 +++ rust/kernel/usb.rs | 3 +++ 6 files changed, 22 insertions(+), 1 deletion(-) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 4636b6f41195..e712d1b89dc3 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -25,8 +25,11 @@ =20 // SAFETY: // - `bindings::auxiliary_driver` is a C type declared as `repr(C)`. +// - `struct auxiliary_driver` embeds a `struct device_driver`. +// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::auxiliary_driver; + const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index cd1d36c313e1..4b0c53b7d22a 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -107,10 +107,16 @@ /// # Safety /// /// Implementors must guarantee that: -/// - `DriverType` is `repr(C)`. +/// - `DriverType` is `repr(C)`, +/// - `DriverType` embeds a valid `struct device_driver` at byte offset `D= EVICE_DRIVER_OFFSET`. pub unsafe trait Driver { /// The specific driver type embedding a `struct device_driver`. type DriverType: Default; + + /// Byte offset of the embedded `struct device_driver` within `DriverT= ype`. + /// + /// This must correspond exactly to the location of the embedded `stru= ct device_driver` field. + const DEVICE_DRIVER_OFFSET: usize; } =20 /// The [`RegistrationOps`] trait serves as generic interface for subsyste= ms (e.g., PCI, Platform, diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index de35961c6903..56f1ed8163a0 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -94,8 +94,11 @@ macro_rules! i2c_device_table { =20 // SAFETY: // - `bindings::i2c_driver` is a C type declared as `repr(C)`. +// - `struct i2c_driver` embeds a `struct device_driver`. +// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::i2c_driver; + const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index f58ce35d9c60..68466150ef20 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -52,8 +52,11 @@ =20 // SAFETY: // - `bindings::pci_driver` is a C type declared as `repr(C)`. +// - `struct pci_driver` embeds a `struct device_driver`. +// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::pci_driver; + const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index e48d055fdc8a..56d9e968634e 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -28,8 +28,11 @@ =20 // SAFETY: // - `bindings::platform_driver` is a C type declared as `repr(C)`. +// - `struct platform_driver` embeds a `struct device_driver`. +// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::platform_driver; + const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 32f4b2d55dfb..a9a9d2298d87 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -29,8 +29,11 @@ =20 // SAFETY: // - `bindings::usb_driver` is a C type declared as `repr(C)`. +// - `struct usb_driver` embeds a `struct device_driver`. +// - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::usb_driver; + const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 // SAFETY: A call to `unregister` for a given instance of `DriverType` is = guaranteed to be valid if --=20 2.52.0 From nobody Mon Feb 9 04:28:48 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 2C47330F53B; Wed, 7 Jan 2026 10:35:51 +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=1767782152; cv=none; b=YpwDsa+mkGgXqC9omsqsHjpng8/1i2dWgqgwpxp8omM1c030RxKGjZifseQLRQNTqSWOfz9AejPqtPa5RpealSgGWUHDtzgaLNNuLwqoXHE2QSjYuOV+NGtCmNceQDw9k2IJTIKNQ9mHArtrlV7KP5y3BFAskXL8Si78Ci1qvDo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767782152; c=relaxed/simple; bh=OABHPQQlfV11ZUpM0ZvmkayXerwyi+tSxR6IpM/FE2I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rkpwvxBgLm6wsqHHHIK3H9hylUHOKkD0N1hVn1Xfjot+fWOGZAXRrMDX3Fj5OxCfresQdZj1ZrgtCm4qcKhDgEeZ8ewy6tSW+/4eU9hPXikxvUdI3OO3Voq1I4aLegBIBdrZK7dM1GBNP9BxjdlAqWQVjdpe8OvmcwIYNGbY17A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iFFGYRPa; 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="iFFGYRPa" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46DB8C16AAE; Wed, 7 Jan 2026 10:35:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767782151; bh=OABHPQQlfV11ZUpM0ZvmkayXerwyi+tSxR6IpM/FE2I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iFFGYRPaXJz8BmGlymkAz/+ywO+rmGRdvutVFoK1d5DSMszcfg7IjbZn8w7+MUUZk 33/9fLLuLZ9qzcbd/SyEUQRVb9boXqrIIoJxAQ5xr3xRVVuR8da5lil3icSxsqK6zi WO41N/VRmO0vgaDaZ5/tfcGEXp7xzbrDxsoLvaw0KNj0eXQaFvzn8RVDxai9ROhxYp 3lnRP7GSGXJOvG8m+b4RP1qNnIOlh1ftr4uxmCyHf0+KYcCA/9vpLWpzOIPSMxdL5n DEJE0hWBHiQh/MSxjbqpXJHl+gnhg0gCiM1aPeQ3jCRzkn4/el1zm8Sw147UdGW99W glVNKOBRGuzLQ== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, igor.korotin.linux@gmail.com, ojeda@kernel.org, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, wsa+renesas@sang-engineering.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-pci@vger.kernel.org, linux-usb@vger.kernel.org, linux-i2c@vger.kernel.org, Danilo Krummrich Subject: [PATCH 5/6] rust: driver: add DriverData type to the generic Driver trait Date: Wed, 7 Jan 2026 11:35:04 +0100 Message-ID: <20260107103511.570525-6-dakr@kernel.org> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260107103511.570525-1-dakr@kernel.org> References: <20260107103511.570525-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 an associated type DriverData to the Driver trait indicating the type of the driver's device private data. Signed-off-by: Danilo Krummrich Acked-by: Alice Ryhl --- rust/kernel/auxiliary.rs | 2 ++ rust/kernel/driver.rs | 4 ++++ rust/kernel/i2c.rs | 2 ++ rust/kernel/pci.rs | 2 ++ rust/kernel/platform.rs | 2 ++ rust/kernel/usb.rs | 2 ++ 6 files changed, 14 insertions(+) diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index e712d1b89dc3..cb26238e95b0 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -25,10 +25,12 @@ =20 // SAFETY: // - `bindings::auxiliary_driver` is a C type declared as `repr(C)`. +// - `T` is the type of the driver's device private data. // - `struct auxiliary_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::auxiliary_driver; + type DriverData =3D T; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 4b0c53b7d22a..77c1f7434897 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -108,11 +108,15 @@ /// /// Implementors must guarantee that: /// - `DriverType` is `repr(C)`, +/// - `DriverData` is the type of the driver's device private data. /// - `DriverType` embeds a valid `struct device_driver` at byte offset `D= EVICE_DRIVER_OFFSET`. pub unsafe trait Driver { /// The specific driver type embedding a `struct device_driver`. type DriverType: Default; =20 + /// The type of the driver's device private data. + type DriverData; + /// Byte offset of the embedded `struct device_driver` within `DriverT= ype`. /// /// This must correspond exactly to the location of the embedded `stru= ct device_driver` field. diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 56f1ed8163a0..6a3923a8b8a7 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -94,10 +94,12 @@ macro_rules! i2c_device_table { =20 // SAFETY: // - `bindings::i2c_driver` is a C type declared as `repr(C)`. +// - `T` is the type of the driver's device private data. // - `struct i2c_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::i2c_driver; + type DriverData =3D T; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 68466150ef20..fe63b53d55d6 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -52,10 +52,12 @@ =20 // SAFETY: // - `bindings::pci_driver` is a C type declared as `repr(C)`. +// - `T` is the type of the driver's device private data. // - `struct pci_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::pci_driver; + type DriverData =3D T; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 56d9e968634e..af94fb58aafb 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -28,10 +28,12 @@ =20 // SAFETY: // - `bindings::platform_driver` is a C type declared as `repr(C)`. +// - `T` is the type of the driver's device private data. // - `struct platform_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::platform_driver; + type DriverData =3D T; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index a9a9d2298d87..b09fe8bcca13 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -29,10 +29,12 @@ =20 // SAFETY: // - `bindings::usb_driver` is a C type declared as `repr(C)`. +// - `T` is the type of the driver's device private data. // - `struct usb_driver` embeds a `struct device_driver`. // - `DEVICE_DRIVER_OFFSET` is the correct byte offset to the embedded `st= ruct device_driver`. unsafe impl driver::Driver for Adapter { type DriverType =3D bindings::usb_driver; + type DriverData =3D T; const DEVICE_DRIVER_OFFSET: usize =3D core::mem::offset_of!(Self::Driv= erType, driver); } =20 --=20 2.52.0 From nobody Mon Feb 9 04:28:48 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 1244730DED4; Wed, 7 Jan 2026 10:35:56 +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=1767782157; cv=none; b=t5cNMiu9cv2chSx81SWGtTeZM8XYd2unm84MhBXBlMrJaU7u31cPhOUg6Uvk5znWg8GAtmmE3FtOZwbhX0pIbWP+w++mkjQ4/YLQqYGZ+qmYtteTc0HOEqo/EbbWp3QNAAm7u9ZAK8Rt44uLFaNtSj6W2pl0V2X/jNS8hUdUSUQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767782157; c=relaxed/simple; bh=N18NZ3MvjG11zo05vBY5H6zEWihoOHUn/jN+IusSagk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Wnfu79ptwS4W6bih3FLO9lRYE3Wjq2KfJZYCxOyzsvzPNBKQOW/h6XHCdfOfNJYpgojTWlG5XkxIqaqvnI10v9lBfvlgZlbiOxleH0uFJojVqyPAhYYF1JaxXGJzVWIG1XudHug6Xi/CYhKB5cMhl5Dc++pTnkyRlZp5S+0i+qY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=X70SgUj/; 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="X70SgUj/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2EF8AC2BC9E; Wed, 7 Jan 2026 10:35:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1767782156; bh=N18NZ3MvjG11zo05vBY5H6zEWihoOHUn/jN+IusSagk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=X70SgUj/DeYJ+TJzCQraKyNYXN/wVdOJb0fKPYuP8NfuvTZUmihzX/Bv7IB44HN6x n5TV+eRigt4iqq8X7WSGfE655xrVHEc60tPaPF2dCzocScNAfpP/s12O4igs/lbdR0 yrWYPU8nS7z6qIM3tpPiI3Fo84DdFZr5cyYsqBZCesWDG3zmcbZQbRjlswrBEqefgj 596hamNn6eURii26t9rKWUx9WMpCNA/QLdPpXDwpYSQN6InXv5K8G1PCNRHRdeh9sq HH7c2HtRc7dq0T+2luWFdlKQbkY8P2G9qZq86DsrCICLAhbhq0Bj6v/R0hDb8Mcwb6 Vv9Sgzoo7Zr6Q== From: Danilo Krummrich To: gregkh@linuxfoundation.org, rafael@kernel.org, igor.korotin.linux@gmail.com, ojeda@kernel.org, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org, a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu, david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org, wsa+renesas@sang-engineering.com Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-pci@vger.kernel.org, linux-usb@vger.kernel.org, linux-i2c@vger.kernel.org, Danilo Krummrich Subject: [PATCH 6/6] rust: driver: drop device private data post unbind Date: Wed, 7 Jan 2026 11:35:05 +0100 Message-ID: <20260107103511.570525-7-dakr@kernel.org> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260107103511.570525-1-dakr@kernel.org> References: <20260107103511.570525-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" Currently, the driver's device private data is allocated and initialized from driver core code called from bus abstractions after the driver's probe() callback returned the corresponding initializer. Similarly, the driver's device private data is dropped within the remove() callback of bus abstractions after calling the remove() callback of the corresponding driver. However, commit 6f61a2637abe ("rust: device: introduce Device::drvdata()") introduced an accessor for the driver's device private data for a Device, i.e. a device that is currently bound to a driver. Obviously, this is in conflict with dropping the driver's device private data in remove(), since a device can not be considered to be fully unbound after remove() has finished: We also have to consider registrations guarded by devres - such as IRQ or class device registrations - which are torn down after remove() in devres_release_all(). Thus, it can happen that, for instance, a class device or IRQ callback still calls Device::drvdata(), which then runs concurrently to remove() (which sets dev->driver_data to NULL and drops the driver's device private data), before devres_release_all() started to tear down the corresponding registration. This is because devres guarded registrations can, as expected, access the corresponding Device that defines their scope. In C it simply is the driver's responsibility to ensure that its device private data is freed after e.g. an IRQ registration is unregistered. Typically, C drivers achieve this by allocating their device private data with e.g. devm_kzalloc() before doing anything else, i.e. before e.g. registering an IRQ with devm_request_threaded_irq(), relying on the reverse order cleanup of devres. Technically, we could do something similar in Rust. However, the resulting code would be pretty messy: In Rust we have to differentiate between allocated but uninitialized memory and initialized memory in the type system. Thus, we would need to somehow keep track of whether the driver's device private data object has been initialized (i.e. probe() was successful and returned a valid initializer for this memory) and conditionally call the destructor of the corresponding object when it is freed. This is because we'd need to allocate and register the memory of the driver's device private data *before* it is initialized by the initializer returned by the driver's probe() callback, because the driver could already register devres guarded registrations within probe() outside of the driver's device private data initializer. Luckily there is a much simpler solution: Instead of dropping the driver's device private data at the end of remove(), we just drop it after the device has been fully unbound, i.e. after all devres callbacks have been processed. For this, we introduce a new post_unbind() callback private to the driver-core, i.e. the callback is neither exposed to drivers, nor to bus abstractions. This way, the driver-core code can simply continue to conditionally allocate the memory for the driver's device private data when the driver's initializer is returned from probe() - no change needed - and drop it when the driver-core code receives the post_unbind() callback. Closes: https://lore.kernel.org/all/DEZMS6Y4A7XE.XE7EUBT5SJFJ@kernel.org/ Fixes: 6f61a2637abe ("rust: device: introduce Device::drvdata()") Signed-off-by: Danilo Krummrich Acked-by: Alice Ryhl --- drivers/base/dd.c | 4 ++++ include/linux/device/driver.h | 11 +++++++++++ rust/kernel/auxiliary.rs | 4 ++-- rust/kernel/device.rs | 20 ++++++++++--------- rust/kernel/driver.rs | 36 ++++++++++++++++++++++++++++++++++- rust/kernel/i2c.rs | 4 ++-- rust/kernel/pci.rs | 4 ++-- rust/kernel/platform.rs | 4 ++-- rust/kernel/usb.rs | 4 ++-- 9 files changed, 71 insertions(+), 20 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 349f31bedfa1..2d9871503614 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -548,6 +548,10 @@ static DEVICE_ATTR_RW(state_synced); static void device_unbind_cleanup(struct device *dev) { devres_release_all(dev); +#ifdef CONFIG_RUST + if (dev->driver->p_cb.post_unbind) + dev->driver->p_cb.post_unbind(dev); +#endif arch_teardown_dma_ops(dev); kfree(dev->dma_range_map); dev->dma_range_map =3D NULL; diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index cd8e0f0a634b..51a9ebdd8a2d 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -85,6 +85,8 @@ enum probe_type { * uevent. * @p: Driver core's private data, no one other than the driver * core can touch this. + * @p_cb: Callbacks private to the driver core; no one other than the + * driver core is allowed to touch this. * * The device driver-model tracks all of the drivers known to the system. * The main reason for this tracking is to enable the driver core to match @@ -119,6 +121,15 @@ struct device_driver { void (*coredump) (struct device *dev); =20 struct driver_private *p; +#ifdef CONFIG_RUST + struct { + /* + * Called after remove() and after all devres entries have been + * processed. + */ + void (*post_unbind)(struct device *dev); + } p_cb; +#endif }; =20 =20 diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index cb26238e95b0..2b4a9aaabb65 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -96,9 +96,9 @@ extern "C" fn remove_callback(adev: *mut bindings::auxili= ary_device) { // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { adev.as_ref().drvdata_obtain::() }; + let data =3D unsafe { adev.as_ref().drvdata_borrow::() }; =20 - T::unbind(adev, data.as_ref()); + T::unbind(adev, data); } } =20 diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 71b200df0f40..031720bf5d8c 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -232,30 +232,32 @@ pub fn set_drvdata(&self, data: impl PinI= nit) -> Result { /// /// # Safety /// - /// - Must only be called once after a preceding call to [`Device::set= _drvdata`]. /// - The type `T` must match the type of the `ForeignOwnable` previou= sly stored by /// [`Device::set_drvdata`]. - pub unsafe fn drvdata_obtain(&self) -> Pin> { + pub(crate) unsafe fn drvdata_obtain(&self) -> Option>> { // SAFETY: By the type invariants, `self.as_raw()` is a valid poin= ter to a `struct device`. let ptr =3D unsafe { bindings::dev_get_drvdata(self.as_raw()) }; =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(), core::ptr::null_= mut()) }; =20 + if ptr.is_null() { + return None; + } + // SAFETY: - // - By the safety requirements of this function, `ptr` comes from= a previous call to - // `into_foreign()`. + // - If `ptr` is not NULL, it comes from a previous call to `into_= foreign()`. // - `dev_get_drvdata()` guarantees to return the same pointer giv= en to `dev_set_drvdata()` // in `into_foreign()`. - unsafe { Pin::>::from_foreign(ptr.cast()) } + Some(unsafe { Pin::>::from_foreign(ptr.cast()) }) } =20 /// Borrow the driver's private data bound to this [`Device`]. /// /// # Safety /// - /// - Must only be called after a preceding call to [`Device::set_drvd= ata`] and before - /// [`Device::drvdata_obtain`]. + /// - Must only be called after a preceding call to [`Device::set_drvd= ata`] and before the + /// device is fully unbound. /// - The type `T` must match the type of the `ForeignOwnable` previou= sly stored by /// [`Device::set_drvdata`]. pub unsafe fn drvdata_borrow(&self) -> Pin<&T> { @@ -271,7 +273,7 @@ impl Device { /// # Safety /// /// - Must only be called after a preceding call to [`Device::set_drvd= ata`] and before - /// [`Device::drvdata_obtain`]. + /// the device is fully unbound. /// - The type `T` must match the type of the `ForeignOwnable` previou= sly stored by /// [`Device::set_drvdata`]. unsafe fn drvdata_unchecked(&self) -> Pin<&T> { @@ -320,7 +322,7 @@ pub fn drvdata(&self) -> Result> { =20 // SAFETY: // - The above check of `dev_get_drvdata()` guarantees that we are= called after - // `set_drvdata()` and before `drvdata_obtain()`. + // `set_drvdata()`. // - We've just checked that the type of the driver's private data= is in fact `T`. Ok(unsafe { self.drvdata_unchecked() }) } diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 77c1f7434897..6e32376d4c7c 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -177,7 +177,39 @@ unsafe impl Sync for Registration<= T> {} // any thread, so `Registration` is `Send`. unsafe impl Send for Registration {} =20 -impl Registration { +impl Registration { + extern "C" fn post_unbind_callback(dev: *mut bindings::device) { + // SAFETY: The driver core only ever calls the post unbind callbac= k with a valid pointer to + // a `struct device`. + // + // INVARIANT: `dev` is valid for the duration of the `post_unbind_= callback()`. + let dev =3D unsafe { &*dev.cast::>() }; + + // `remove()` and all devres callbacks have been completed at this= point, hence drop the + // driver's device private data. + // + // SAFETY: By the safety requirements of the `Driver` trait, `T::D= riverData` is the + // driver's device private data. + drop(unsafe { dev.drvdata_obtain::() }); + } + + /// Attach generic `struct device_driver` callbacks. + fn callbacks_attach(drv: &Opaque) { + let ptr =3D drv.get().cast::(); + + // SAFETY: + // - `drv.get()` yields a valid pointer to `Self::DriverType`. + // - Adding `DEVICE_DRIVER_OFFSET` yields the address of the embed= ded `struct device_driver` + // as guaranteed by the safety requirements of the `Driver` trai= t. + let base =3D unsafe { ptr.add(T::DEVICE_DRIVER_OFFSET) }; + + // CAST: `base` points to the offset of the embedded `struct devic= e_driver`. + let base =3D base.cast::(); + + // SAFETY: It is safe to set the fields of `struct device_driver` = on initialization. + unsafe { (*base).p_cb.post_unbind =3D Some(Self::post_unbind_callb= ack) }; + } + /// Creates a new instance of the registration object. pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl P= inInit { try_pin_init!(Self { @@ -189,6 +221,8 @@ pub fn new(name: &'static CStr, module: &'static ThisMo= dule) -> impl PinInit) }; =20 + Self::callbacks_attach(drv); + // SAFETY: `drv` is guaranteed to be pinned until `T::unre= gister`. unsafe { T::register(drv, name, module) } }), diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 6a3923a8b8a7..c1813f94da7a 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -178,9 +178,9 @@ extern "C" fn remove_callback(idev: *mut bindings::i2c_= client) { // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `I2cClient::set_dr= vdata()` has been called // and stored a `Pin>`. - let data =3D unsafe { idev.as_ref().drvdata_obtain::() }; + let data =3D unsafe { idev.as_ref().drvdata_borrow::() }; =20 - T::unbind(idev, data.as_ref()); + T::unbind(idev, data); } =20 extern "C" fn shutdown_callback(idev: *mut bindings::i2c_client) { diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index fe63b53d55d6..8fdc18faeb4c 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -123,9 +123,9 @@ extern "C" fn remove_callback(pdev: *mut bindings::pci_= dev) { // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { pdev.as_ref().drvdata_obtain::() }; + let data =3D unsafe { pdev.as_ref().drvdata_borrow::() }; =20 - T::unbind(pdev, data.as_ref()); + T::unbind(pdev, data); } } =20 diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index af94fb58aafb..6f81186a7919 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -101,9 +101,9 @@ extern "C" fn remove_callback(pdev: *mut bindings::plat= form_device) { // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { pdev.as_ref().drvdata_obtain::() }; + let data =3D unsafe { pdev.as_ref().drvdata_borrow::() }; =20 - T::unbind(pdev, data.as_ref()); + T::unbind(pdev, data); } } =20 diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index b09fe8bcca13..e6080955f742 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -103,9 +103,9 @@ extern "C" fn disconnect_callback(intf: *mut bindings::= usb_interface) { // SAFETY: `disconnect_callback` is only ever called after a succe= ssful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvda= ta()` has been called // and stored a `Pin>`. - let data =3D unsafe { dev.drvdata_obtain::() }; + let data =3D unsafe { dev.drvdata_borrow::() }; =20 - T::disconnect(intf, data.as_ref()); + T::disconnect(intf, data); } } =20 --=20 2.52.0