]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
rust: driver core: drop drvdata before devres release
authorDanilo Krummrich <dakr@kernel.org>
Mon, 25 May 2026 20:20:52 +0000 (22:20 +0200)
committerDanilo Krummrich <dakr@kernel.org>
Wed, 27 May 2026 14:22:41 +0000 (16:22 +0200)
Move the post_unbind_rust callback before devres_release_all() in
device_unbind_cleanup().

With drvdata() removed, the driver's bus device private data is only
accessible by the owning driver itself. It is hence safe to drop the
driver's bus device private data before devres actions are released.

This reordering is the key enabler for Higher-Ranked Lifetime Types
(HRT) in Rust device drivers -- it allows driver structs to hold direct
references to devres-managed resources, because the bus device private
data (and with it all such references) is guaranteed to be dropped while
the underlying devres resources are still alive.

Without this change, devres resources would be freed first, leaving the
driver's bus device private data with dangling references during its
destructor.

Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Link: https://patch.msgid.link/20260525202921.124698-6-dakr@kernel.org
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
drivers/base/dd.c
include/linux/device/driver.h
rust/kernel/driver.rs

index 1dc1e3528043c3f44985b36c3392a689a00873ee..73801b40a416e6e99edd41ea010f1b99cef26fb5 100644 (file)
@@ -595,9 +595,9 @@ 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);
+       devres_release_all(dev);
        arch_teardown_dma_ops(dev);
        kfree(dev->dma_range_map);
        dev->dma_range_map = NULL;
index bbc67ec513edf689ac6db9343b33df830d48b886..38e9a4679447b4000277e268a71095e5e8a2b0b9 100644 (file)
@@ -123,8 +123,8 @@ struct device_driver {
        struct driver_private *p;
        struct {
                /*
-                * Called after remove() and after all devres entries have been
-                * processed. This is a Rust only callback.
+                * Called after remove() but before devres entries are released.
+                * This is a Rust only callback.
                 */
                void (*post_unbind_rust)(struct device *dev);
        } p_cb;
index 5fd1cfd64e9344c1708cca123347c2c25b54656a..a95dafaa9d686e9fbe45e2f4eaa9fed71da86b5a 100644 (file)
@@ -193,8 +193,8 @@ impl<T: RegistrationOps> Registration<T> {
         // INVARIANT: `dev` is valid for the duration of the `post_unbind_callback()`.
         let dev = unsafe { &*dev.cast::<device::Device<device::CoreInternal>>() };
 
-        // `remove()` and all devres callbacks have been completed at this point, hence drop the
-        // driver's device private data.
+        // `remove()` has been completed at this point; devres resources are still valid and will
+        // be released after the driver's bus device private data is dropped.
         //
         // SAFETY: By the safety requirements of the `Driver` trait, `T::DriverData` is the
         // driver's bus device private data type.