rust: device: Higher-Ranked Lifetime Types for device drivers
Status from this message: Applied, thanks!
Get series with b4
b4 am [email protected]Versions newest first · linked by author and title
- v5 Latest24 patches 20 repliesApplied
- v427 patches 20 repliesSuperseded
- v327 patches 52 repliesSuperseded
Earlier versions · 2
| Version | Posted | Patches | Replies | Status |
|---|---|---|---|---|
| v2 | 25 patches | 7 replies | Superseded | |
| v1 | 24 patches | 14 replies | Superseded |
Changes in v5 from the cover letter
- Fix Bar name parameter to &'static CStr
- ForLt: handle macro_rules! invocations in covariance/WF checks by conservatively assuming they may contain lifetimes; fix typos in commit message and doc comments
- Update stale SAFETY comments from T::Data to T::Data<'_> in bus driver callbacks
- Fix USB commit message: unbind() -> disconnect()
- Clarify Bar commit message on why Devres is no longer needed
- Drop REF patches (nova-core, tyr); will be revisited and sent separately to be routed through drm-rust
Patches in v5 Applied
| # | Subject and files | Size | Replies | Applied |
|---|---|---|---|---|
| 1/24 | rust: pci: use 'static lifetime for PCI BAR resource namesrust/ | +3 | 3 replies | |
| 2/24 | rust: alloc: remove `'static` bound on `ForeignOwnable`rust/ rust/ | +24 | 1 reply | |
| 3/24 | rust: driver: move 'static bounds to constructorrust/ rust/ rust/ +4 more | +26 | 0 replies | |
| 4/24 | rust: driver: decouple driver private data from driver typedrivers/ drivers/ drivers/ +19 more | +98 | 0 replies | |
| 5/24 | rust: driver core: drop drvdata before devres releasedrivers/ include/ rust/ | +5 | 0 replies | |
| 6/24 | rust: pci: implement Sync for Device<Bound>rust/ | +4 | 0 replies | |
| 7/24 | rust: platform: implement Sync for Device<Bound>rust/ | +4 | 0 replies | |
| 8/24 | rust: auxiliary: implement Sync for Device<Bound>rust/ | +4 | 0 replies | |
| 9/24 | rust: usb: implement Sync for Device<Bound>rust/ | +4 | 0 replies | |
| 10/24 | rust: device: implement Sync for Device<Bound>rust/ | +4 | 0 replies | |
| 11/24 | rust: device: make Core and CoreInternal lifetime-parameterizeddrivers/ drivers/ drivers/ +24 more | +118 | 1 reply | |
| 12/24 | rust: pci: make Driver trait lifetime-parameterizeddrivers/ rust/ samples/ +2 more | +35 | 1 reply | |
| 13/24 | rust: platform: make Driver trait lifetime-parameterizeddrivers/ drivers/ drivers/ +7 more | +68 | 1 reply | |
| 14/24 | rust: auxiliary: make Driver trait lifetime-parameterizeddrivers/ rust/ samples/ | +19 | 1 reply | |
| 15/24 | rust: usb: make Driver trait lifetime-parameterizedrust/ samples/ | +28 | 2 replies | |
| 16/24 | rust: i2c: make Driver trait lifetime-parameterizedrust/ samples/ | +28 | 1 reply | |
| 17/24 | rust: driver: update module documentation for GAT-based Data typerust/ | +13 | 1 reply | |
| 18/24 | rust: pci: make Bar lifetime-parameterizeddrivers/ rust/ rust/ +1 more | +38 | 1 reply | |
| 19/24 | rust: io: make IoMem and ExclusiveIoMem lifetime-parameterizeddrivers/ drivers/ rust/ | +56 | 1 reply | |
| 20/24 | samples: rust: rust_driver_pci: use HRT lifetime for Barsamples/ | +40 | 1 reply | |
| 21/24 | gpu: nova-core: separate driver type from driver datadrivers/ drivers/ | +9 | 1 reply | |
| 22/24 | rust: types: add `ForLt` trait for higher-ranked lifetime supportrust/ rust/ rust/ +2 more | +382 | 2 replies | |
| 23/24 | rust: auxiliary: generalize Registration over ForLtdrivers/ rust/ samples/ | +96 | 1 reply | |
| 24/24 | samples: rust: rust_driver_auxiliary: showcase lifetime-bound registration datasamples/ | +35 | 0 replies |
Reviews trailers per patch
All 24 patches have a Reviewed-by or Acked-by.
| Patch | Alexandre Courbot | Greg Kroah-Hartman | Gary Guo | Eliot Courtney | Uwe Kleine-König | Igor Korotin | Miguel Ojeda | Daniel Almeida |
|---|---|---|---|---|---|---|---|---|
| 1/24 | R-b | R-b | R-b | |||||
| 2/24 | R-b | R-b | A-b | |||||
| 3/24 | R-b | R-b | ||||||
| 4/24 | R-b | R-b | R-b | |||||
| 5/24 | R-b | R-b | R-b | |||||
| 6/24 | R-b | R-b | R-b | |||||
| 7/24 | R-b | R-b | R-b | |||||
| 8/24 | R-b | R-b | R-b | |||||
| 9/24 | R-b | R-b | R-b | |||||
| 10/24 | R-b | R-b | R-b | |||||
| 11/24 | R-b | R-b | R-b | R-b | ||||
| 12/24 | R-b | R-b | R-b | |||||
| 13/24 | R-b | R-b | R-b | A-b | ||||
| 14/24 | R-b | R-b | R-b | |||||
| 15/24 | R-b | R-b | R-b | R-b | R-b | |||
| 16/24 | R-b | R-b | R-b | A-b | ||||
| 17/24 | R-b | R-b | R-b | |||||
| 18/24 | R-b | R-b | R-b | R-b | ||||
| 19/24 | R-b | R-b | R-b | R-b | A-b | |||
| 20/24 | R-b | R-b | R-b | R-b | ||||
| 21/24 | R-b | R-b | R-b | R-b | ||||
| 22/24 | R-b | R-b | R-b | A-b | ||||
| 23/24 | R-b | R-b | R-b | |||||
| 24/24 | R-b | R-b | R-b | R-b |
Trailers given in replies are filled; those carried in the patches from earlier versions are outlined with dashes. Scroll the table sideways for all 8 reviewers.
Cover letter [PATCH v5 00/24] rust: device: Higher-Ranked Lifetime Types for device drivers
Currently, Rust device drivers access device resources such as PCI BAR mappings and I/O memory regions through Devres<T>.
Devres::access() provides zero-overhead access by taking a &Device<Bound> reference as proof that the device is still bound. Since a &Device<Bound> is available in almost all contexts by design, Devres is mostly a type-system level proof that the resource is valid, but it can also be used from scopes without this guarantee through its try_access() accessor.
This works well in general, but has a few limitations:
- Every access to a device resource goes through Devres::access(), which despite zero cost, adds boilerplate to every access site.
- Destructors do not receive a &Device<Bound>, so they must use try_access(), which can fail. In practice the access succeeds if teardown ordering is correct, but the type system can't express this, forcing drivers to handle a failure path that should never be taken.
- Sharing a resource across components (e.g. passing a BAR to a sub-component) requires Arc<Devres<T>>.
- Device references must be stored as ARef<Device> rather than plain &Device borrows.
These limitations stem from the driver's bus device private data being 'static -- the driver struct cannot borrow from the device reference it receives in probe(), even though it structurally cannot outlive the device binding.
This series introduces Higher-Ranked Lifetime Types (HRT) for Rust device drivers. An HRT is a type that is generic over a lifetime -- it does not have a fixed lifetime, but can be instantiated with any lifetime chosen by the caller.
Bus driver traits use a Generic Associated Type (GAT) type Data<'bound> to introduce the lifetime on the private data, rather than parameterizing the Driver trait itself. This avoids a driver trait global lifetime and avoids the need for ForLt for bus device private data, making the bus implementations much simpler. ForLt is only needed for auxiliary registration data, where the lifetime is not introduced by a trait callback but must be threaded through Registration.
With HRT, driver structs carry a lifetime parameter tied to the device binding scope -- the interval of a bus device being bound to a driver. Device resources like pci::Bar<'bound> and IoMem<'bound> are handed out with this lifetime, so the compiler enforces at build time that they do not escape the binding scope.
Before:
struct MyDriver {
pdev: ARef<pci::Device>,
bar: Devres<pci::Bar<BAR_SIZE>>,
}
let io = self.bar.access(dev)?;
io.read32(OFFSET);After:
struct MyDriver<'bound> {
pdev: &'bound pci::Device,
bar: pci::Bar<'bound, BAR_SIZE>,
}
self.bar.read32(OFFSET);Lifetime-parameterized device resources can be put into a Devres at any point via Bar::into_devres() / IoMem::into_devres(), providing the exact same semantics as before. This is useful for resources shared across subsystem boundaries where revocation is needed.
This also synergizes with the upcoming self-referential initialization support in pin-init, which allows one field of the driver struct to borrow another during initialization without unsafe code.
The same pattern is applied to auxiliary device registration data as a first example beyond bus device private data. Registration<F: ForLt> can hold lifetime-parameterized data tied to the parent driver's binding scope. Since the auxiliary bus guarantees that the parent remains bound while the auxiliary device is registered, the registration data can safely borrow the parent's device resources.
More generally, binding resource lifetimes to a registration scope applies to every registration that is scoped to a driver binding -- auxiliary devices, class devices, IRQ handlers, workqueues.
A follow-up series extends this to class device registrations, starting with DRM, so that class device callbacks (IOCTLs, etc.) can safely access device resources through the separate registration data bound to the registration's lifetime without Devres indirection.
Thanks to Gary for coming up with the ForLt implementation; thanks to Alice for the early discussions around lifetime-parameterized private data that helped shape the direction of this work.
Changes in v5:
- Fix Bar name parameter to &'static CStr
- ForLt: handle macro_rules! invocations in covariance/WF checks by conservatively assuming they may contain lifetimes; fix typos in commit message and doc comments
- Update stale SAFETY comments from T::Data to T::Data<'_> in bus driver callbacks
- Fix USB commit message: unbind() -> disconnect()
- Clarify Bar commit message on why Devres is no longer needed
- Drop REF patches (nova-core, tyr); will be revisited and sent separately to be routed through drm-rust
Changes in v4:
- Use 'bound only for lifetimes that represent the full duration of a device being bound to a driver
- Make Core and CoreInternal lifetime-parameterized
- Split auxiliary::Registration constructor into unsafe fn new_with_lt (borrowed data) and safe fn new ('static data) to close mem::forget() soundness hole
- Use TypeId::of::<F>() instead of TypeId::of::<F::Of<'static>>() in auxiliary registration_data()
- Handle Type::Macro in ForLt! covariance and WF checks; proc macros cannot expand macro_rules invocations, so use WithLt trait projection for lifetime substitution
- Fix missing Send bound in type Data: Send
Changes in v3:
- Rework all bus "make Driver trait lifetime-parameterized" patches to use a GAT (type Data<'bound>); in the context of adding a 'bound lifetime, this avoids a driver trait global lifetime and avoids ForLt for bus device private data making the bus implementations much simpler
Changes in v2:
- Add 'a bound to ForLt::Of<'a> and WithLt::Of, making the lifetime bound inherent to the trait; remove all F::Of<'static>: 'static where clauses
- Drop "rust: devres: add ForLt support to Devres"; Devres itself stays unchanged -- ForLt-aware access is introduced later through DevresLt in a separate series
- Use 'bound instead of 'a; add patches to consistently use 'bound for pre-existing 'a
Danilo Krummrich (21):
rust: pci: use 'static lifetime for PCI BAR resource names
rust: driver: decouple driver private data from driver type
rust: driver core: drop drvdata before devres release
rust: pci: implement Sync for Device<Bound>
rust: platform: implement Sync for Device<Bound>
rust: auxiliary: implement Sync for Device<Bound>
rust: usb: implement Sync for Device<Bound>
rust: device: implement Sync for Device<Bound>
rust: device: make Core and CoreInternal lifetime-parameterized
rust: pci: make Driver trait lifetime-parameterized
rust: platform: make Driver trait lifetime-parameterized
rust: auxiliary: make Driver trait lifetime-parameterized
rust: usb: make Driver trait lifetime-parameterized
rust: i2c: make Driver trait lifetime-parameterized
rust: driver: update module documentation for GAT-based Data type
rust: pci: make Bar lifetime-parameterized
rust: io: make IoMem and ExclusiveIoMem lifetime-parameterized
samples: rust: rust_driver_pci: use HRT lifetime for Bar
gpu: nova-core: separate driver type from driver data
rust: auxiliary: generalize Registration over ForLt
samples: rust: rust_driver_auxiliary: showcase lifetime-bound
registration data
Gary Guo (3):
rust: alloc: remove 'static bound on ForeignOwnable
rust: driver: move 'static bounds to constructor
rust: types: add ForLt trait for higher-ranked lifetime support
drivers/base/dd.c | 2 +- drivers/cpufreq/rcpufreq_dt.rs | 9 +- drivers/gpu/drm/nova/driver.rs | 6 +- drivers/gpu/drm/tyr/driver.rs | 13 +- drivers/gpu/nova-core/driver.rs | 30 ++-- drivers/gpu/nova-core/gpu.rs | 2 +- drivers/gpu/nova-core/nova_core.rs | 2 +- drivers/pwm/pwm_th1520.rs | 13 +- include/linux/device/driver.h | 4 +- rust/Makefile | 1 + rust/kernel/alloc/kbox.rs | 24 ++- rust/kernel/auxiliary.rs | 142 ++++++++++----- rust/kernel/cpufreq.rs | 9 +- rust/kernel/device.rs | 61 +++++-- rust/kernel/devres.rs | 2 +- rust/kernel/dma.rs | 2 +- rust/kernel/driver.rs | 41 +++-- rust/kernel/i2c.rs | 61 ++++--- rust/kernel/io/mem.rs | 121 +++++++------ rust/kernel/pci.rs | 51 +++--- rust/kernel/pci/id.rs | 2 +- rust/kernel/pci/io.rs | 54 +++--- rust/kernel/platform.rs | 52 +++--- rust/kernel/types.rs | 12 +- rust/kernel/types/for_lt.rs | 117 ++++++++++++ rust/kernel/usb.rs | 57 +++--- rust/macros/for_lt.rs | 248 ++++++++++++++++++++++++++ rust/macros/lib.rs | 12 ++ samples/rust/rust_debugfs.rs | 11 +- samples/rust/rust_dma.rs | 6 +- samples/rust/rust_driver_auxiliary.rs | 79 +++++--- samples/rust/rust_driver_i2c.rs | 13 +- samples/rust/rust_driver_pci.rs | 90 +++++----- samples/rust/rust_driver_platform.rs | 9 +- samples/rust/rust_driver_usb.rs | 15 +- samples/rust/rust_i2c_client.rs | 14 +- samples/rust/rust_soc.rs | 9 +- 37 files changed, 998 insertions(+), 398 deletions(-) create mode 100644 rust/kernel/types/for_lt.rs create mode 100644 rust/macros/for_lt.rs
base-commit: 95ade775c4ab9b9b3d7cfa2d45283e93fbfa4e7a
Signature · 1 line
2.54.0