From d8932355f8c5673106eca49abd142f8fe0c1fe8b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 5 Dec 2025 01:06:39 +0900 Subject: rust: dma: add helpers for architectures without CONFIG_HAS_DMA Add dma_set_mask(), dma_set_coherent_mask(), dma_map_sgtable(), and dma_max_mapping_size() helpers to fix a build error when CONFIG_HAS_DMA is not enabled. Note that when CONFIG_HAS_DMA is enabled, they are included in both bindings_generated.rs and bindings_helpers_generated.rs. The former takes precedence so behavior remains unchanged in that case. This fixes the following build error on UML: error[E0425]: cannot find function `dma_set_mask` in crate `bindings` --> rust/kernel/dma.rs:46:38 | 46 | to_result(unsafe { bindings::dma_set_mask(self.as_ref().as_raw(), mask.value()) }) | ^^^^^^^^^^^^ help: a function with a similar name exists: `xa_set_mark` | ::: rust/bindings/bindings_generated.rs:24690:5 | 24690 | pub fn xa_set_mark(arg1: *mut xarray, index: ffi::c_ulong, arg2: xa_mark_t); | ---------------------------------------------------------------------------- similarly named function `xa_set_mark` defined here error[E0425]: cannot find function `dma_set_coherent_mask` in crate `bindings` --> rust/kernel/dma.rs:63:38 | 63 | to_result(unsafe { bindings::dma_set_coherent_mask(self.as_ref().as_raw(), mask.value()) }) | ^^^^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists: `dma_coherent_ok` | ::: rust/bindings/bindings_generated.rs:52745:5 | 52745 | pub fn dma_coherent_ok(dev: *mut device, phys: phys_addr_t, size: usize) -> bool_; | ---------------------------------------------------------------------------------- similarly named function `dma_coherent_ok` defined here error[E0425]: cannot find function `dma_map_sgtable` in crate `bindings` --> rust/kernel/scatterlist.rs:212:23 | 212 | bindings::dma_map_sgtable(dev.as_raw(), sgt.as_ptr(), dir.into(), 0) | ^^^^^^^^^^^^^^^ help: a function with a similar name exists: `dma_unmap_sgtable` | ::: rust/bindings/bindings_helpers_generated.rs:1351:5 | 1351 | / pub fn dma_unmap_sgtable( 1352 | | dev: *mut device, 1353 | | sgt: *mut sg_table, 1354 | | dir: dma_data_direction, 1355 | | attrs: ffi::c_ulong, 1356 | | ); | |______- similarly named function `dma_unmap_sgtable` defined here error[E0425]: cannot find function `dma_max_mapping_size` in crate `bindings` --> rust/kernel/scatterlist.rs:356:52 | 356 | let max_segment = match unsafe { bindings::dma_max_mapping_size(dev.as_raw()) } { | ^^^^^^^^^^^^^^^^^^^^ not found in `bindings` error: aborting due to 4 previous errors Cc: stable@vger.kernel.org # v6.17+ Fixes: 101d66828a4ee ("rust: dma: add DMA addressing capabilities") Signed-off-by: FUJITA Tomonori Reviewed-by: David Gow Reviewed-by: Alice Ryhl Link: https://patch.msgid.link/20251204160639.364936-1-fujita.tomonori@gmail.com [ Use relative paths in the error splat; add 'dma' prefix. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/helpers/dma.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'rust') diff --git a/rust/helpers/dma.c b/rust/helpers/dma.c index 6e741c197242..2afa32c21c94 100644 --- a/rust/helpers/dma.c +++ b/rust/helpers/dma.c @@ -19,3 +19,24 @@ int rust_helper_dma_set_mask_and_coherent(struct device *dev, u64 mask) { return dma_set_mask_and_coherent(dev, mask); } + +int rust_helper_dma_set_mask(struct device *dev, u64 mask) +{ + return dma_set_mask(dev, mask); +} + +int rust_helper_dma_set_coherent_mask(struct device *dev, u64 mask) +{ + return dma_set_coherent_mask(dev, mask); +} + +int rust_helper_dma_map_sgtable(struct device *dev, struct sg_table *sgt, + enum dma_data_direction dir, unsigned long attrs) +{ + return dma_map_sgtable(dev, sgt, dir, attrs); +} + +size_t rust_helper_dma_max_mapping_size(struct device *dev) +{ + return dma_max_mapping_size(dev); +} -- cgit v1.2.3 From 6558749ef3405c143711cbdc67ec88cbc1582d91 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 17 Dec 2025 13:10:37 +0000 Subject: rust: maple_tree: rcu_read_lock() in destructor to silence lockdep MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running the Rust maple tree kunit tests with lockdep, you may trigger a warning that looks like this: lib/maple_tree.c:780 suspicious rcu_dereference_check() usage! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 no locks held by kunit_try_catch/344. stack backtrace: CPU: 3 UID: 0 PID: 344 Comm: kunit_try_catch Tainted: G N 6.19.0-rc1+ #2 NONE Tainted: [N]=TEST Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/2014 Call Trace: dump_stack_lvl+0x71/0x90 lockdep_rcu_suspicious+0x150/0x190 mas_start+0x104/0x150 mas_find+0x179/0x240 _RINvNtCs5QSdWC790r4_4core3ptr13drop_in_placeINtNtCs1cdwasc6FUb_6kernel10maple_tree9MapleTreeINtNtNtBL_5alloc4kbox3BoxlNtNtB1x_9allocator7KmallocEEECsgxAQYCfdR72_25doctests_kernel_generated+0xaf/0x130 rust_doctest_kernel_maple_tree_rs_0+0x600/0x6b0 ? lock_release+0xeb/0x2a0 ? kunit_try_catch_run+0x210/0x210 kunit_try_run_case+0x74/0x160 ? kunit_try_catch_run+0x210/0x210 kunit_generic_run_threadfn_adapter+0x12/0x30 kthread+0x21c/0x230 ? __do_trace_sched_kthread_stop_ret+0x40/0x40 ret_from_fork+0x16c/0x270 ? __do_trace_sched_kthread_stop_ret+0x40/0x40 ret_from_fork_asm+0x11/0x20 This is because the destructor of maple tree calls mas_find() without taking rcu_read_lock() or the spinlock. Doing that is actually ok in this case since the destructor has exclusive access to the entire maple tree, but it triggers a lockdep warning. To fix that, take the rcu read lock. In the future, it's possible that memory reclaim could gain a feature where it reallocates entries in maple trees even if no user-code is touching it. If that feature is added, then this use of rcu read lock would become load-bearing, so I did not make it conditional on lockdep. We have to repeatedly take and release rcu because the destructor of T might perform operations that sleep. Link: https://lkml.kernel.org/r/20251217-maple-drop-rcu-v1-1-702af063573f@google.com Fixes: da939ef4c494 ("rust: maple_tree: add MapleTree") Signed-off-by: Alice Ryhl Reported-by: Andreas Hindborg Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/x/topic/x/near/564215108 Reviewed-by: Gary Guo Reviewed-by: Daniel Almeida Cc: Andrew Ballance Cc: Björn Roy Baron Cc: Boqun Feng Cc: Danilo Krummrich Cc: Liam Howlett Cc: Matthew Wilcox (Oracle) Cc: Miguel Ojeda Cc: Trevor Gross Cc: Signed-off-by: Andrew Morton --- rust/kernel/maple_tree.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/kernel/maple_tree.rs b/rust/kernel/maple_tree.rs index e72eec56bf57..265d6396a78a 100644 --- a/rust/kernel/maple_tree.rs +++ b/rust/kernel/maple_tree.rs @@ -265,7 +265,16 @@ impl MapleTree { loop { // This uses the raw accessor because we're destroying pointers without removing them // from the maple tree, which is only valid because this is the destructor. - let ptr = ma_state.mas_find_raw(usize::MAX); + // + // Take the rcu lock because mas_find_raw() requires that you hold either the spinlock + // or the rcu read lock. This is only really required if memory reclaim might + // reallocate entries in the tree, as we otherwise have exclusive access. That feature + // doesn't exist yet, so for now, taking the rcu lock only serves the purpose of + // silencing lockdep. + let ptr = { + let _rcu = kernel::sync::rcu::Guard::new(); + ma_state.mas_find_raw(usize::MAX) + }; if ptr.is_null() { break; } -- cgit v1.2.3 From 68ece1e2ce3a1cb0aac9f5af685cf18fa2fa31aa Mon Sep 17 00:00:00 2001 From: Yilin Chen <1479826151@qq.com> Date: Mon, 29 Dec 2025 00:52:34 +0800 Subject: rust: dma: remove incorrect safety documentation Removes a safety requirement that incorrectly states callers must ensure the device does not access memory while the returned slice is live, as this method doesn't return a slice. Fixes: d37a39f607c4 ("rust: dma: add as_slice/write functions for CoherentAllocation") Signed-off-by: Yilin Chen <1479826151@qq.com> Link: https://patch.msgid.link/tencent_5195C0324923A2B67DEF8AE4B8E139BCB105@qq.com Signed-off-by: Danilo Krummrich --- rust/kernel/dma.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'rust') diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 84d3c67269e8..2ac107d8f7b7 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -532,8 +532,6 @@ impl CoherentAllocation { /// /// # Safety /// - /// * Callers must ensure that the device does not read/write to/from memory while the returned - /// slice is live. /// * Callers must ensure that this call does not race with a read or write to the same region /// that overlaps with this write. /// -- cgit v1.2.3 From 3691fd19ccad4c1c0e3fc4888ef36edaa6e571be Mon Sep 17 00:00:00 2001 From: Yilin Chen <1479826151@qq.com> Date: Mon, 29 Dec 2025 00:53:44 +0800 Subject: rust: device_id: replace incorrect word in safety documentation The safety documentation incorrectly refers to `RawDeviceId` when transmuting to `RawType`. This fixes the documentation to correctly indicate that implementers must ensure layout compatibility with `RawType`, not `RawDeviceId`. Fixes: 9b90864bb42b ("rust: implement `IdArray`, `IdTable` and `RawDeviceId`") Signed-off-by: Yilin Chen <1479826151@qq.com> Link: https://patch.msgid.link/tencent_C18DD5047749311142ED455779C7CCCF3A08@qq.com Signed-off-by: Danilo Krummrich --- rust/kernel/device_id.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rust') diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs index 62c42da12e9d..8e9721446014 100644 --- a/rust/kernel/device_id.rs +++ b/rust/kernel/device_id.rs @@ -15,7 +15,7 @@ use core::mem::MaybeUninit; /// # Safety /// /// Implementers must ensure that `Self` is layout-compatible with [`RawDeviceId::RawType`]; -/// i.e. it's safe to transmute to `RawDeviceId`. +/// i.e. it's safe to transmute to `RawType`. /// /// This requirement is needed so `IdArray::new` can convert `Self` to `RawType` when building /// the ID table. -- cgit v1.2.3 From 4c9f6a782f6078dc94450fcb22e65d520bfa0775 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Sat, 27 Dec 2025 15:47:21 +0000 Subject: rust: driver: fix broken intra-doc links to example driver types The `auxiliary` and `pci` modules are conditional on `CONFIG_AUXILIARY_BUS` and `CONFIG_PCI` respectively. When these are disabled, the intra-doc links to `auxiliary::Driver` and `pci::Driver` break, causing rustdoc warnings (or errors with `-D warnings`). error: unresolved link to `kernel::auxiliary::Driver` --> rust/kernel/driver.rs:82:28 | 82 | //! [`auxiliary::Driver`]: kernel::auxiliary::Driver | ^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `auxiliary` in module `kernel` Fix this by making the documentation for these examples conditional on the corresponding configuration options. Fixes: 970a7c68788e ("driver: rust: expand documentation for driver infrastructure") Signed-off-by: Alice Ryhl Reported-by: FUJITA Tomonori Closes: https://lore.kernel.org/rust-for-linux/20251209.151817.744108529426448097.fujita.tomonori@gmail.com/ Link: https://patch.msgid.link/20251227-driver-types-v1-1-1916154fbe5e@google.com Signed-off-by: Danilo Krummrich --- rust/kernel/driver.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'rust') diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 9beae2e3d57e..649d06468f41 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -33,7 +33,14 @@ //! } //! ``` //! -//! For specific examples see [`auxiliary::Driver`], [`pci::Driver`] and [`platform::Driver`]. +//! For specific examples see: +//! +//! * [`platform::Driver`](kernel::platform::Driver) +#![cfg_attr( + CONFIG_AUXILIARY_BUS, + doc = "* [`auxiliary::Driver`](kernel::auxiliary::Driver)" +)] +#![cfg_attr(CONFIG_PCI, doc = "* [`pci::Driver`](kernel::pci::Driver)")] //! //! The `probe()` callback should return a `impl PinInit`, i.e. the driver's private //! data. The bus abstraction should store the pointer in the corresponding bus device. The generic @@ -79,7 +86,6 @@ //! //! For this purpose the generic infrastructure in [`device_id`] should be used. //! -//! [`auxiliary::Driver`]: kernel::auxiliary::Driver //! [`Core`]: device::Core //! [`Device`]: device::Device //! [`Device`]: device::Device @@ -87,8 +93,6 @@ //! [`DeviceContext`]: device::DeviceContext //! [`device_id`]: kernel::device_id //! [`module_driver`]: kernel::module_driver -//! [`pci::Driver`]: kernel::pci::Driver -//! [`platform::Driver`]: kernel::platform::Driver use crate::error::{Error, Result}; use crate::{acpi, device, of, str::CStr, try_pin_init, types::Opaque, ThisModule}; -- cgit v1.2.3 From 32cb3840386fd3684fbe8294cfc0a6684417139e Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 31 Dec 2025 13:57:27 +0900 Subject: rust: dma: fix broken intra-doc links The `pci` module is conditional on CONFIG_PCI. When it's disabled, the intra-doc link to `pci::Device` causes rustdoc warnings: warning: unresolved link to `::kernel::pci::Device` --> rust/kernel/dma.rs:30:70 | 30 | /// where the underlying bus is DMA capable, such as [`pci::Device`](::kernel::pci::Device) or | ^^^^^^^^^^^^^^^^^^^^^ no item named `pci` in module `kernel` Fix this by making the documentation conditional on CONFIG_PCI. Fixes: d06d5f66f549 ("rust: dma: implement `dma::Device` trait") Signed-off-by: FUJITA Tomonori Reviewed-by: Dirk Behme Link: https://patch.msgid.link/20251231045728.1912024-1-fujita.tomonori@gmail.com [ Keep the "such as" part indicating a list of examples; fix typos in commit message. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/dma.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'rust') diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs index 2ac107d8f7b7..acc65b1e0f24 100644 --- a/rust/kernel/dma.rs +++ b/rust/kernel/dma.rs @@ -27,8 +27,9 @@ pub type DmaAddress = bindings::dma_addr_t; /// Trait to be implemented by DMA capable bus devices. /// /// The [`dma::Device`](Device) trait should be implemented by bus specific device representations, -/// where the underlying bus is DMA capable, such as [`pci::Device`](::kernel::pci::Device) or -/// [`platform::Device`](::kernel::platform::Device). +/// where the underlying bus is DMA capable, such as: +#[cfg_attr(CONFIG_PCI, doc = "* [`pci::Device`](kernel::pci::Device)")] +/// * [`platform::Device`](::kernel::platform::Device) pub trait Device: AsRef> { /// Set up the device's DMA streaming addressing capabilities. /// -- cgit v1.2.3 From a9a42f0754b6c69525612d678b73da790e28b9fd Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 31 Dec 2025 13:57:28 +0900 Subject: rust: device: fix broken intra-doc links The `pci` module is conditional on CONFIG_PCI. When it's disabled, the intra-doc link to `pci::Device` causes rustdoc warnings: warning: unresolved link to `kernel::pci::Device` --> rust/kernel/device.rs:163:22 | 163 | /// [`pci::Device`]: kernel::pci::Device | ^^^^^^^^^^^^^^^^^^^ no item named `pci` in module `kernel` | = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default Fix this by making the documentation conditional on CONFIG_PCI. Fixes: d6e26c1ae4a6 ("device: rust: expand documentation for Device") Signed-off-by: FUJITA Tomonori Reviewed-by: Dirk Behme Link: https://patch.msgid.link/20251231045728.1912024-2-fujita.tomonori@gmail.com [ Keep the "such as" part indicating a list of examples; fix typos in commit message. - Danilo ] Signed-off-by: Danilo Krummrich --- rust/kernel/device.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rust') diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index c79be2e2bfe3..5c2e1e0369e9 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -67,8 +67,9 @@ static_assert!(core::mem::size_of::() >= core::mem::size_ /// /// # Implementing Bus Devices /// -/// This section provides a guideline to implement bus specific devices, such as [`pci::Device`] or -/// [`platform::Device`]. +/// This section provides a guideline to implement bus specific devices, such as: +#[cfg_attr(CONFIG_PCI, doc = "* [`pci::Device`](kernel::pci::Device)")] +/// * [`platform::Device`] /// /// A bus specific device should be defined as follows. /// @@ -160,7 +161,6 @@ static_assert!(core::mem::size_of::() >= core::mem::size_ /// /// [`AlwaysRefCounted`]: kernel::types::AlwaysRefCounted /// [`impl_device_context_deref`]: kernel::impl_device_context_deref -/// [`pci::Device`]: kernel::pci::Device /// [`platform::Device`]: kernel::platform::Device #[repr(transparent)] pub struct Device(Opaque, PhantomData); -- cgit v1.2.3 From 9f92d7d1cb9cccc6c703ca53d4f1d1acca79b598 Mon Sep 17 00:00:00 2001 From: Marko Turk Date: Mon, 5 Jan 2026 22:37:57 +0100 Subject: rust: pci: fix typos in Bar struct's comments Fix a typo in the doc-comment of the Bar structure: 'inststance -> instance'. Add also 'is' to the comment inside Bar's `new()` function (suggested by Dirk): // `pdev` is valid by the invariants of `Device`. Fixes: bf9651f84b4e ("rust: pci: implement I/O mappable `pci::Bar`") Suggested-by: Dirk Behme Signed-off-by: Marko Turk Reviewed-by: Dirk Behme Link: https://patch.msgid.link/20260105213726.73000-2-mt@markoturk.info Signed-off-by: Danilo Krummrich --- rust/kernel/pci/io.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rust') diff --git a/rust/kernel/pci/io.rs b/rust/kernel/pci/io.rs index 0d55c3139b6f..82a4f1eba2f5 100644 --- a/rust/kernel/pci/io.rs +++ b/rust/kernel/pci/io.rs @@ -20,7 +20,7 @@ use core::ops::Deref; /// /// # Invariants /// -/// `Bar` always holds an `IoRaw` inststance that holds a valid pointer to the start of the I/O +/// `Bar` always holds an `IoRaw` instance that holds a valid pointer to the start of the I/O /// memory mapped PCI BAR and its size. pub struct Bar { pdev: ARef, @@ -54,7 +54,7 @@ impl Bar { let ioptr: usize = unsafe { bindings::pci_iomap(pdev.as_raw(), num, 0) } as usize; if ioptr == 0 { // SAFETY: - // `pdev` valid by the invariants of `Device`. + // `pdev` is valid by the invariants of `Device`. // `num` is checked for validity by a previous call to `Device::resource_len`. unsafe { bindings::pci_release_region(pdev.as_raw(), num) }; return Err(ENOMEM); -- cgit v1.2.3 From 8510ef5e3cfbd7d59a16845f85cd0194a8689761 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Tue, 6 Jan 2026 09:03:20 +0900 Subject: rust: device: Remove explicit import of CStrExt Remove the explicit import of CStrExt. When CONFIG_PRINTK is disabled this import causes a build error: error: unused import: `crate::str::CStrExt` --> rust/kernel/device.rs:17:5 | 17 | use crate::str::CStrExt as _; | ^^^^^^^^^^^^^^^^^^^ | = note: `-D unused-imports` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(unused_imports)]` error: aborting due to 1 previous error CStrExt is covered by prelude::* so the explicit import is redundant. Signed-off-by: FUJITA Tomonori Fixes: 3b83f5d5e78a ("rust: replace `CStr` with `core::ffi::CStr`") Link: https://patch.msgid.link/20260106000320.2593800-1-fujita.tomonori@gmail.com Signed-off-by: Danilo Krummrich --- rust/kernel/device.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'rust') diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs index 5c2e1e0369e9..71b200df0f40 100644 --- a/rust/kernel/device.rs +++ b/rust/kernel/device.rs @@ -14,7 +14,6 @@ use core::{any::TypeId, marker::PhantomData, ptr}; #[cfg(CONFIG_PRINTK)] use crate::c_str; -use crate::str::CStrExt as _; pub mod property; -- cgit v1.2.3 From 6a069876eb1402478900ee0eb7d7fe276bb1f4e3 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 5 Jan 2026 10:44:06 +0000 Subject: rust: bitops: fix missing _find_* functions on 32-bit ARM On 32-bit ARM, you may encounter linker errors such as this one: ld.lld: error: undefined symbol: _find_next_zero_bit >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(::insert_or_update_handle) in archive vmlinux.a >>> referenced by rust_binder_main.43196037ba7bcee1-cgu.0 >>> drivers/android/binder/rust_binder_main.o:(::insert_or_update_handle) in archive vmlinux.a This error occurs because even though the functions are declared by include/linux/find.h, the definition is #ifdef'd out on 32-bit ARM. This is because arch/arm/include/asm/bitops.h contains: #define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off) And the underscore-prefixed function is conditional on #ifndef of the non-underscore-prefixed name, but the declaration in find.h is *not* conditional on that #ifndef. To fix the linker error, we ensure that the symbols in question exist when compiling Rust code. We do this by defining them in rust/helpers/ whenever the normal definition is #ifndef'd out. Note that these helpers are somewhat unusual in that they do not have the rust_helper_ prefix that most helpers have. Adding the rust_helper_ prefix does not compile, as 'bindings::_find_next_zero_bit()' will result in a call to a symbol called _find_next_zero_bit as defined by include/linux/find.h rather than a symbol with the rust_helper_ prefix. This is because when a symbol is present in both include/ and rust/helpers/, the one from include/ wins under the assumption that the current configuration is one where that helper is unnecessary. This heuristic fails for _find_next_zero_bit() because the header file always declares it even if the symbol does not exist. The functions still use the __rust_helper annotation. This lets the wrapper function be inlined into Rust code even if full kernel LTO is not used once the patch series for that feature lands. Yury: arches are free to implement they own find_bit() functions. Most rely on generic implementation, but arm32 and m86k - not; so they require custom handling. Alice confirmed it fixes the build for both. Cc: stable@vger.kernel.org Fixes: 6cf93a9ed39e ("rust: add bindings for bitops.h") Reported-by: Andreas Hindborg Closes: https://rust-for-linux.zulipchat.com/#narrow/channel/x/topic/x/near/561677301 Tested-by: Andreas Hindborg Reviewed-by: Dirk Behme Signed-off-by: Alice Ryhl Signed-off-by: Yury Norov (NVIDIA) --- rust/helpers/bitops.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'rust') diff --git a/rust/helpers/bitops.c b/rust/helpers/bitops.c index 5d0861d29d3f..e79ef9e6d98f 100644 --- a/rust/helpers/bitops.c +++ b/rust/helpers/bitops.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include void rust_helper___set_bit(unsigned long nr, unsigned long *addr) { @@ -21,3 +22,44 @@ void rust_helper_clear_bit(unsigned long nr, volatile unsigned long *addr) { clear_bit(nr, addr); } + +/* + * The rust_helper_ prefix is intentionally omitted below so that the + * declarations in include/linux/find.h are compatible with these helpers. + * + * Note that the below #ifdefs mean that the helper is only created if C does + * not provide a definition. + */ +#ifdef find_first_zero_bit +__rust_helper +unsigned long _find_first_zero_bit(const unsigned long *p, unsigned long size) +{ + return find_first_zero_bit(p, size); +} +#endif /* find_first_zero_bit */ + +#ifdef find_next_zero_bit +__rust_helper +unsigned long _find_next_zero_bit(const unsigned long *addr, + unsigned long size, unsigned long offset) +{ + return find_next_zero_bit(addr, size, offset); +} +#endif /* find_next_zero_bit */ + +#ifdef find_first_bit +__rust_helper +unsigned long _find_first_bit(const unsigned long *addr, unsigned long size) +{ + return find_first_bit(addr, size); +} +#endif /* find_first_bit */ + +#ifdef find_next_bit +__rust_helper +unsigned long _find_next_bit(const unsigned long *addr, unsigned long size, + unsigned long offset) +{ + return find_next_bit(addr, size, offset); +} +#endif /* find_next_bit */ -- cgit v1.2.3 From 33d19f621641de1b6ec6fe1bb2ac68a7d2c61f6a Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Mon, 8 Dec 2025 11:47:00 +0900 Subject: rust: io: always inline functions using build_assert with arguments `build_assert` relies on the compiler to optimize out its error path. Functions using it with its arguments must thus always be inlined, otherwise the error path of `build_assert` might not be optimized out, triggering a build error. Cc: stable@vger.kernel.org Fixes: ce30d94e6855 ("rust: add `io::{Io, IoRaw}` base types") Reviewed-by: Daniel Almeida Signed-off-by: Alexandre Courbot Tested-by: Timur Tabi Link: https://patch.msgid.link/20251208-io-build-assert-v3-2-98aded02c1ea@nvidia.com Signed-off-by: Danilo Krummrich --- rust/kernel/io.rs | 9 ++++++--- rust/kernel/io/resource.rs | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'rust') diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs index 98e8b84e68d1..b64b11f75a35 100644 --- a/rust/kernel/io.rs +++ b/rust/kernel/io.rs @@ -142,7 +142,8 @@ macro_rules! define_read { /// Bound checks are performed on compile time, hence if the offset is not known at compile /// time, the build will fail. $(#[$attr])* - #[inline] + // Always inline to optimize out error path of `io_addr_assert`. + #[inline(always)] pub fn $name(&self, offset: usize) -> $type_name { let addr = self.io_addr_assert::<$type_name>(offset); @@ -171,7 +172,8 @@ macro_rules! define_write { /// Bound checks are performed on compile time, hence if the offset is not known at compile /// time, the build will fail. $(#[$attr])* - #[inline] + // Always inline to optimize out error path of `io_addr_assert`. + #[inline(always)] pub fn $name(&self, value: $type_name, offset: usize) { let addr = self.io_addr_assert::<$type_name>(offset); @@ -239,7 +241,8 @@ impl Io { self.addr().checked_add(offset).ok_or(EINVAL) } - #[inline] + // Always inline to optimize out error path of `build_assert`. + #[inline(always)] fn io_addr_assert(&self, offset: usize) -> usize { build_assert!(Self::offset_valid::(offset, SIZE)); diff --git a/rust/kernel/io/resource.rs b/rust/kernel/io/resource.rs index 56cfde97ce87..b7ac9faf141d 100644 --- a/rust/kernel/io/resource.rs +++ b/rust/kernel/io/resource.rs @@ -226,6 +226,8 @@ impl Flags { /// Resource represents a memory region that must be ioremaped using `ioremap_np`. pub const IORESOURCE_MEM_NONPOSTED: Flags = Flags::new(bindings::IORESOURCE_MEM_NONPOSTED); + // Always inline to optimize out error path of `build_assert`. + #[inline(always)] const fn new(value: u32) -> Self { crate::build_assert!(value as u64 <= c_ulong::MAX as u64); Flags(value as c_ulong) -- cgit v1.2.3 From 5d9c4c272ba06055d19e05c2a02e16e58acc8943 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Mon, 8 Dec 2025 11:47:04 +0900 Subject: rust: irq: always inline functions using build_assert with arguments `build_assert` relies on the compiler to optimize out its error path. Functions using it with its arguments must thus always be inlined, otherwise the error path of `build_assert` might not be optimized out, triggering a build error. Cc: stable@vger.kernel.org Fixes: 746680ec6696 ("rust: irq: add flags module") Reviewed-by: Daniel Almeida Signed-off-by: Alexandre Courbot Link: https://patch.msgid.link/20251208-io-build-assert-v3-6-98aded02c1ea@nvidia.com Signed-off-by: Danilo Krummrich --- rust/kernel/irq/flags.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rust') diff --git a/rust/kernel/irq/flags.rs b/rust/kernel/irq/flags.rs index adfde96ec47c..d26e25af06ee 100644 --- a/rust/kernel/irq/flags.rs +++ b/rust/kernel/irq/flags.rs @@ -96,6 +96,8 @@ impl Flags { self.0 } + // Always inline to optimize out error path of `build_assert`. + #[inline(always)] const fn new(value: u32) -> Self { build_assert!(value as u64 <= c_ulong::MAX as u64); Self(value as c_ulong) -- cgit v1.2.3 From 4181aceb4af414bd6d2ce5eb9a22637bbb4f5f8c Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 7 Jan 2026 11:35:00 +0100 Subject: rust: i2c: do not drop device private data on shutdown() 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 abstractions") Acked-by: Alice Ryhl Acked-by: Igor Korotin Link: https://patch.msgid.link/20260107103511.570525-2-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/i2c.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rust') 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 @@ impl Adapter { // SAFETY: `shutdown_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin>`. - let data = unsafe { idev.as_ref().drvdata_obtain::() }; + let data = unsafe { idev.as_ref().drvdata_borrow::() }; - T::shutdown(idev, data.as_ref()); + T::shutdown(idev, data); } /// The [`i2c::IdTable`] of the corresponding driver. -- cgit v1.2.3 From 5f4476e98387618ce22bb93fb5c11142827458ec Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 7 Jan 2026 11:35:01 +0100 Subject: rust: auxiliary: add Driver::unbind() callback Add missing unbind() callback to auxiliary::Driver, since it will be needed by drivers eventually (e.g. the Nova DRM driver). Acked-by: Alice Ryhl Link: https://patch.msgid.link/20260107103511.570525-3-dakr@kernel.org Signed-off-by: Danilo Krummrich --- rust/kernel/auxiliary.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'rust') 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 @@ impl Adapter { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin>`. - drop(unsafe { adev.as_ref().drvdata_obtain::() }); + let data = unsafe { adev.as_ref().drvdata_obtain::() }; + + T::unbind(adev, data.as_ref()); } } @@ -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 PinInit; + + /// Auxiliary driver unbind. + /// + /// Called when a [`Device`] is unbound from its bound [`Driver`]. Implementing this callback + /// is optional. + /// + /// This callback serves as a place for drivers to perform teardown operations that require a + /// `&Device` or `&Device` reference. For instance, drivers may try to perform I/O + /// operations to gracefully tear down the device. + /// + /// Otherwise, release operations for driver resources should be performed in `Self::drop`. + fn unbind(dev: &Device, this: Pin<&Self>) { + let _ = (dev, this); + } } /// The auxiliary device representation. -- cgit v1.2.3 From 0af1a9e4629a85964a7eebe58ebd2ca37c8c21fc Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 7 Jan 2026 11:35:02 +0100 Subject: rust: driver: introduce a DriverLayout trait The DriverLayout 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 DriverLayout::DriverType associated type. Acked-by: Alice Ryhl Acked-by: Igor Korotin Link: https://patch.msgid.link/20260107103511.570525-4-dakr@kernel.org [ Rename driver::Driver to driver::DriverLayout, as it represents the layout of a driver structure rather than the driver structure itself. - Danilo ] Signed-off-by: Danilo Krummrich --- 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(-) (limited to 'rust') diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 6931f8a4267f..9922b9158d16 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -23,13 +23,17 @@ use core::{ /// An adapter for the registration of auxiliary drivers. pub struct Adapter(T); -// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if +// SAFETY: +// - `bindings::auxiliary_driver` is a C type declared as `repr(C)`. +unsafe impl driver::DriverLayout for Adapter { + type DriverType = 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 = bindings::auxiliary_driver; - unsafe fn register( - adrv: &Opaque, + adrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -41,14 +45,14 @@ unsafe impl driver::RegistrationOps for Adapter { (*adrv.get()).id_table = T::ID_TABLE.as_ptr(); } - // 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, name.as_char_ptr()) }) } - 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..73968b13d7dc 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -99,23 +99,33 @@ use crate::{acpi, device, of, str::CStr, try_pin_init, types::Opaque, ThisModule use core::pin::Pin; use pin_init::{pin_data, pinned_drop, PinInit}; +/// Trait describing the layout of a specific device driver. +/// +/// This trait describes the layout of a specific driver structure, such as `struct pci_driver` or +/// `struct platform_driver`. +/// +/// # Safety +/// +/// Implementors must guarantee that: +/// - `DriverType` is `repr(C)`. +pub unsafe trait DriverLayout { + /// The specific driver type embedding a `struct device_driver`. + type DriverType: Default; +} + /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, /// Amba, etc.) to provide the corresponding subsystem specific implementation 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::pci_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 `RegType` 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 typically a struct defined - /// by the C portion of the kernel. - type RegType: Default; - +/// A call to [`RegistrationOps::unregister`] for a given instance of `DriverType` is only valid if +/// a preceding call to [`RegistrationOps::register`] has been successful. +pub unsafe trait RegistrationOps: DriverLayout { /// 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 @@ pub unsafe trait RegistrationOps { /// /// Must only be called after a preceding successful call to [`RegistrationOps::register`] for /// the same `reg`. - unsafe fn unregister(reg: &Opaque); + unsafe fn unregister(reg: &Opaque); } /// A [`Registration`] is a generic type that represents the registration of some driver type (e.g. @@ -146,7 +156,7 @@ pub unsafe trait RegistrationOps { #[pin_data(PinnedDrop)] pub struct Registration { #[pin] - reg: Opaque, + reg: Opaque, } // SAFETY: `Registration` has no fields or methods accessible via `&Registration`, 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 PinInit { 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 for write. - unsafe { ptr.write(T::RegType::default()) }; + unsafe { ptr.write(T::DriverType::default()) }; // SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write, and it has // just been initialised above, so it's also valid for read. - let drv = unsafe { &*(ptr as *const Opaque) }; + let drv = unsafe { &*(ptr as *const Opaque) }; // SAFETY: `drv` is guaranteed to be pinned until `T::unregister`. unsafe { T::register(drv, name, module) } diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 35b678b78d91..8e80d8572e1a 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); -// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if +// SAFETY: +// - `bindings::i2c_driver` is a C type declared as `repr(C)`. +unsafe impl driver::DriverLayout for Adapter { + type DriverType = 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 = bindings::i2c_driver; - unsafe fn register( - idrv: &Opaque, + idrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -133,12 +137,12 @@ unsafe impl driver::RegistrationOps for Adapter { (*idrv.get()).driver.acpi_match_table = acpi_table; } - // 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.get()) }) } - 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..703ce5709f0c 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -50,13 +50,17 @@ pub use self::irq::{ /// An adapter for the registration of PCI drivers. pub struct Adapter(T); -// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if +// SAFETY: +// - `bindings::pci_driver` is a C type declared as `repr(C)`. +unsafe impl driver::DriverLayout for Adapter { + type DriverType = 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 = bindings::pci_driver; - unsafe fn register( - pdrv: &Opaque, + pdrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -68,14 +72,14 @@ unsafe impl driver::RegistrationOps for Adapter { (*pdrv.get()).id_table = T::ID_TABLE.as_ptr(); } - // 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()) }) } - 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..93a64cf86b76 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -26,13 +26,17 @@ use core::{ /// An adapter for the registration of platform drivers. pub struct Adapter(T); -// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if +// SAFETY: +// - `bindings::platform_driver` is a C type declared as `repr(C)`. +unsafe impl driver::DriverLayout for Adapter { + type DriverType = 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 = bindings::platform_driver; - unsafe fn register( - pdrv: &Opaque, + pdrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -55,12 +59,12 @@ unsafe impl driver::RegistrationOps for Adapter { (*pdrv.get()).driver.acpi_match_table = acpi_table; } - // 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) }) } - 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..60b761c06fbd 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -27,13 +27,17 @@ use core::{ /// An adapter for the registration of USB drivers. pub struct Adapter(T); -// SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if +// SAFETY: +// - `bindings::usb_driver` is a C type declared as `repr(C)`. +unsafe impl driver::DriverLayout for Adapter { + type DriverType = 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 = bindings::usb_driver; - unsafe fn register( - udrv: &Opaque, + udrv: &Opaque, name: &'static CStr, module: &'static ThisModule, ) -> Result { @@ -45,14 +49,14 @@ unsafe impl driver::RegistrationOps for Adapter { (*udrv.get()).id_table = T::ID_TABLE.as_ptr(); } - // 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_char_ptr()) }) } - 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()) }; } } -- cgit v1.2.3 From c1d4519e1c36ffa01973e23af4502e69dcd84f39 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 7 Jan 2026 11:35:03 +0100 Subject: rust: driver: add DEVICE_DRIVER_OFFSET to the DriverLayout trait Add an associated const DEVICE_DRIVER_OFFSET to the DriverLayout 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. Acked-by: Alice Ryhl Acked-by: Igor Korotin Link: https://patch.msgid.link/20260107103511.570525-5-dakr@kernel.org Signed-off-by: Danilo Krummrich --- 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(-) (limited to 'rust') diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 9922b9158d16..9b25af331ad5 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -25,8 +25,11 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::auxiliary_driver; + const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // 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 73968b13d7dc..4a96a07905d1 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -107,10 +107,16 @@ use pin_init::{pin_data, pinned_drop, PinInit}; /// # Safety /// /// Implementors must guarantee that: -/// - `DriverType` is `repr(C)`. +/// - `DriverType` is `repr(C)`, +/// - `DriverType` embeds a valid `struct device_driver` at byte offset `DEVICE_DRIVER_OFFSET`. pub unsafe trait DriverLayout { /// The specific driver type embedding a `struct device_driver`. type DriverType: Default; + + /// Byte offset of the embedded `struct device_driver` within `DriverType`. + /// + /// This must correspond exactly to the location of the embedded `struct device_driver` field. + const DEVICE_DRIVER_OFFSET: usize; } /// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index 8e80d8572e1a..d97e73282003 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -94,8 +94,11 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::i2c_driver; + const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // 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 703ce5709f0c..fe6f508b0cac 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -52,8 +52,11 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::pci_driver; + const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // 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 93a64cf86b76..716c9cc25aea 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -28,8 +28,11 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::platform_driver; + const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // 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 60b761c06fbd..eb1c9b9ef228 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -29,8 +29,11 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::usb_driver; + const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } // SAFETY: A call to `unregister` for a given instance of `DriverType` is guaranteed to be valid if -- cgit v1.2.3 From 2ad0f490c224283eb5b38f81e247000ce3c714d3 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 7 Jan 2026 11:35:04 +0100 Subject: rust: driver: add DriverData type to the DriverLayout trait Add an associated type DriverData to the DriverLayout trait indicating the type of the driver's device private data. Acked-by: Alice Ryhl Acked-by: Igor Korotin Link: https://patch.msgid.link/20260107103511.570525-6-dakr@kernel.org Signed-off-by: Danilo Krummrich --- 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(+) (limited to 'rust') diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 9b25af331ad5..17574aa5066f 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -25,10 +25,12 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::auxiliary_driver; + type DriverData = T; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs index 4a96a07905d1..ba1ca1f7a7e2 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -108,11 +108,15 @@ use pin_init::{pin_data, pinned_drop, PinInit}; /// /// 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 `DEVICE_DRIVER_OFFSET`. pub unsafe trait DriverLayout { /// The specific driver type embedding a `struct device_driver`. type DriverType: Default; + /// The type of the driver's device private data. + type DriverData; + /// Byte offset of the embedded `struct device_driver` within `DriverType`. /// /// This must correspond exactly to the location of the embedded `struct device_driver` field. diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index d97e73282003..e86242227081 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -94,10 +94,12 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::i2c_driver; + type DriverData = T; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index fe6f508b0cac..590723dcb5ae 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -52,10 +52,12 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::pci_driver; + type DriverData = T; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 716c9cc25aea..b8a681df9ddc 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -28,10 +28,12 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::platform_driver; + type DriverData = T; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index eb1c9b9ef228..4cf4bb1705b5 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -29,10 +29,12 @@ pub struct Adapter(T); // 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 `struct device_driver`. unsafe impl driver::DriverLayout for Adapter { type DriverType = bindings::usb_driver; + type DriverData = T; const DEVICE_DRIVER_OFFSET: usize = core::mem::offset_of!(Self::DriverType, driver); } -- cgit v1.2.3 From a995fe1a3aa78b7d06cc1cc7b6b8436c5e93b07f Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 7 Jan 2026 11:35:05 +0100 Subject: rust: driver: drop device private data post unbind 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()") Acked-by: Alice Ryhl Acked-by: Greg Kroah-Hartman Acked-by: Igor Korotin Link: https://patch.msgid.link/20260107103511.570525-7-dakr@kernel.org [ Remove #ifdef CONFIG_RUST, rename post_unbind() to post_unbind_rust(). - Danilo] Signed-off-by: Danilo Krummrich --- drivers/base/dd.c | 2 ++ include/linux/device/driver.h | 9 +++++++++ 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, 67 insertions(+), 20 deletions(-) (limited to 'rust') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 349f31bedfa1..bea8da5f8a3a 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -548,6 +548,8 @@ static DEVICE_ATTR_RW(state_synced); static void device_unbind_cleanup(struct device *dev) { devres_release_all(dev); + if (dev->driver->p_cb.post_unbind_rust) + dev->driver->p_cb.post_unbind_rust(dev); arch_teardown_dma_ops(dev); kfree(dev->dma_range_map); dev->dma_range_map = NULL; diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index cd8e0f0a634b..bbc67ec513ed 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,13 @@ struct device_driver { void (*coredump) (struct device *dev); struct driver_private *p; + struct { + /* + * Called after remove() and after all devres entries have been + * processed. This is a Rust only callback. + */ + void (*post_unbind_rust)(struct device *dev); + } p_cb; }; diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs index 17574aa5066f..be76f11aecb7 100644 --- a/rust/kernel/auxiliary.rs +++ b/rust/kernel/auxiliary.rs @@ -96,9 +96,9 @@ impl Adapter { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin>`. - let data = unsafe { adev.as_ref().drvdata_obtain::() }; + let data = unsafe { adev.as_ref().drvdata_borrow::() }; - T::unbind(adev, data.as_ref()); + T::unbind(adev, data); } } 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 @@ impl Device { /// /// # Safety /// - /// - Must only be called once after a preceding call to [`Device::set_drvdata`]. /// - The type `T` must match the type of the `ForeignOwnable` previously 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 pointer to a `struct device`. let ptr = unsafe { bindings::dev_get_drvdata(self.as_raw()) }; // SAFETY: By the type invariants, `self.as_raw()` is a valid pointer to a `struct device`. unsafe { bindings::dev_set_drvdata(self.as_raw(), core::ptr::null_mut()) }; + 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 given to `dev_set_drvdata()` // in `into_foreign()`. - unsafe { Pin::>::from_foreign(ptr.cast()) } + Some(unsafe { Pin::>::from_foreign(ptr.cast()) }) } /// Borrow the driver's private data bound to this [`Device`]. /// /// # Safety /// - /// - Must only be called after a preceding call to [`Device::set_drvdata`] and before - /// [`Device::drvdata_obtain`]. + /// - Must only be called after a preceding call to [`Device::set_drvdata`] and before the + /// device is fully unbound. /// - The type `T` must match the type of the `ForeignOwnable` previously 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_drvdata`] and before - /// [`Device::drvdata_obtain`]. + /// the device is fully unbound. /// - The type `T` must match the type of the `ForeignOwnable` previously stored by /// [`Device::set_drvdata`]. unsafe fn drvdata_unchecked(&self) -> Pin<&T> { @@ -320,7 +322,7 @@ impl Device { // 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 ba1ca1f7a7e2..bee3ae21a27b 100644 --- a/rust/kernel/driver.rs +++ b/rust/kernel/driver.rs @@ -177,7 +177,39 @@ unsafe impl Sync for Registration {} // any thread, so `Registration` is `Send`. unsafe impl Send for Registration {} -impl Registration { +impl Registration { + extern "C" fn post_unbind_callback(dev: *mut bindings::device) { + // SAFETY: The driver core only ever calls the post unbind callback with a valid pointer to + // a `struct device`. + // + // INVARIANT: `dev` is valid for the duration of the `post_unbind_callback()`. + let dev = 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::DriverData` is the + // driver's device private data type. + drop(unsafe { dev.drvdata_obtain::() }); + } + + /// Attach generic `struct device_driver` callbacks. + fn callbacks_attach(drv: &Opaque) { + let ptr = drv.get().cast::(); + + // SAFETY: + // - `drv.get()` yields a valid pointer to `Self::DriverType`. + // - Adding `DEVICE_DRIVER_OFFSET` yields the address of the embedded `struct device_driver` + // as guaranteed by the safety requirements of the `Driver` trait. + let base = unsafe { ptr.add(T::DEVICE_DRIVER_OFFSET) }; + + // CAST: `base` points to the offset of the embedded `struct device_driver`. + let base = base.cast::(); + + // SAFETY: It is safe to set the fields of `struct device_driver` on initialization. + unsafe { (*base).p_cb.post_unbind_rust = Some(Self::post_unbind_callback) }; + } + /// Creates a new instance of the registration object. pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit { try_pin_init!(Self { @@ -189,6 +221,8 @@ impl Registration { // just been initialised above, so it's also valid for read. let drv = unsafe { &*(ptr as *const Opaque) }; + Self::callbacks_attach(drv); + // SAFETY: `drv` is guaranteed to be pinned until `T::unregister`. unsafe { T::register(drv, name, module) } }), diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs index e86242227081..39b0a9a207fd 100644 --- a/rust/kernel/i2c.rs +++ b/rust/kernel/i2c.rs @@ -178,9 +178,9 @@ impl Adapter { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `I2cClient::set_drvdata()` has been called // and stored a `Pin>`. - let data = unsafe { idev.as_ref().drvdata_obtain::() }; + let data = unsafe { idev.as_ref().drvdata_borrow::() }; - T::unbind(idev, data.as_ref()); + T::unbind(idev, data); } extern "C" fn shutdown_callback(idev: *mut bindings::i2c_client) { diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index 590723dcb5ae..bea76ca9c3da 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -123,9 +123,9 @@ impl Adapter { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin>`. - let data = unsafe { pdev.as_ref().drvdata_obtain::() }; + let data = unsafe { pdev.as_ref().drvdata_borrow::() }; - T::unbind(pdev, data.as_ref()); + T::unbind(pdev, data); } } diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index b8a681df9ddc..35a5813ffb33 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -101,9 +101,9 @@ impl Adapter { // SAFETY: `remove_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin>`. - let data = unsafe { pdev.as_ref().drvdata_obtain::() }; + let data = unsafe { pdev.as_ref().drvdata_borrow::() }; - T::unbind(pdev, data.as_ref()); + T::unbind(pdev, data); } } diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs index 4cf4bb1705b5..67ce5c85c619 100644 --- a/rust/kernel/usb.rs +++ b/rust/kernel/usb.rs @@ -103,9 +103,9 @@ impl Adapter { // SAFETY: `disconnect_callback` is only ever called after a successful call to // `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called // and stored a `Pin>`. - let data = unsafe { dev.drvdata_obtain::() }; + let data = unsafe { dev.drvdata_borrow::() }; - T::disconnect(intf, data.as_ref()); + T::disconnect(intf, data); } } -- cgit v1.2.3