Skip to content

Commit f301cb9

Browse files
author
Danilo Krummrich
committed
rust: devres: implement Devres::access()
Implement a direct accessor for the data stored within the Devres for cases where we can prove that we own a reference to a Device<Bound> (i.e. a bound device) of the same device that was used to create the corresponding Devres container. Usually, when accessing the data stored within a Devres container, it is not clear whether the data has been revoked already due to the device being unbound and, hence, we have to try whether the access is possible and subsequently keep holding the RCU read lock for the duration of the access. However, when we can prove that we hold a reference to Device<Bound> matching the device the Devres container has been created with, we can guarantee that the device is not unbound for the duration of the lifetime of the Device<Bound> reference and, hence, it is not possible for the data within the Devres container to be revoked. Therefore, in this case, we can bypass the atomic check and the RCU read lock, which is a great optimization and simplification for drivers. Reviewed-by: Christian Schrefl <chrisi.schrefl@gmail.com> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com> Acked-by: Boqun Feng <boqun.feng@gmail.com> Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com> Link: https://lore.kernel.org/r/20250428140137.468709-3-dakr@kernel.org Signed-off-by: Danilo Krummrich <dakr@kernel.org>
1 parent 46f91ad commit f301cb9

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

rust/kernel/devres.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,44 @@ impl<T> Devres<T> {
181181

182182
Ok(())
183183
}
184+
185+
/// Obtain `&'a T`, bypassing the [`Revocable`].
186+
///
187+
/// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting
188+
/// a `&'a Device<Bound>` of the same [`Device`] this [`Devres`] instance has been created with.
189+
///
190+
/// # Errors
191+
///
192+
/// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance
193+
/// has been created with.
194+
///
195+
/// # Example
196+
///
197+
/// ```no_run
198+
/// # use kernel::{device::Core, devres::Devres, pci};
199+
///
200+
/// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result {
201+
/// let bar = devres.access(dev.as_ref())?;
202+
///
203+
/// let _ = bar.read32(0x0);
204+
///
205+
/// // might_sleep()
206+
///
207+
/// bar.write32(0x42, 0x0);
208+
///
209+
/// Ok(())
210+
/// }
211+
/// ```
212+
pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> {
213+
if self.0.dev.as_raw() != dev.as_raw() {
214+
return Err(EINVAL);
215+
}
216+
217+
// SAFETY: `dev` being the same device as the device this `Devres` has been created for
218+
// proves that `self.0.data` hasn't been revoked and is guaranteed to not be revoked as
219+
// long as `dev` lives; `dev` lives at least as long as `self`.
220+
Ok(unsafe { self.deref().access() })
221+
}
184222
}
185223

186224
impl<T> Deref for Devres<T> {

0 commit comments

Comments
 (0)