From: Danilo Krummrich <dakr@kernel.org>
To: gregkh@linuxfoundation.org, rafael@kernel.org,
acourbot@nvidia.com, aliceryhl@google.com,
david.m.ertman@intel.com, ira.weiny@intel.com, leon@kernel.org,
viresh.kumar@linaro.org, m.wilczynski@samsung.com,
ukleinek@kernel.org, bhelgaas@google.com, kwilczynski@kernel.org,
abdiel.janulgue@gmail.com, robin.murphy@arm.com,
markus.probst@posteo.de, ojeda@kernel.org, boqun@kernel.org,
gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org,
a.hindborg@kernel.org, tmgross@umich.edu, igor.korotin@linux.dev,
daniel.almeida@collabora.com, pcolberg@redhat.com
Cc: driver-core@lists.linux.dev, linux-kernel@vger.kernel.org,
nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org,
linux-pm@vger.kernel.org, linux-pwm@vger.kernel.org,
linux-pci@vger.kernel.org, rust-for-linux@vger.kernel.org,
Danilo Krummrich <dakr@kernel.org>
Subject: [PATCH v4 00/27] rust: device: Higher-Ranked Lifetime Types for device drivers
Date: Fri, 22 May 2026 01:34:26 +0200 [thread overview]
Message-ID: <20260521233501.1191842-1-dakr@kernel.org> (raw)
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.
The series contains a few driver patches for reference, indicated by the REF
suffix.
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 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 (24):
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
gpu: nova-core: use lifetime for Bar
gpu: nova-core: unregister sysmem flush page from Drop
gpu: nova-core: replace ARef<Device> with &'bound Device in
SysmemFlush
gpu: drm: tyr: use lifetime for IoMem
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 | 23 ++-
drivers/gpu/drm/tyr/gpu.rs | 62 +++---
drivers/gpu/drm/tyr/regs.rs | 21 +-
drivers/gpu/nova-core/driver.rs | 52 ++---
drivers/gpu/nova-core/fb.rs | 31 ++-
drivers/gpu/nova-core/gpu.rs | 38 ++--
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 | 50 ++---
rust/kernel/platform.rs | 52 ++---
rust/kernel/types.rs | 12 +-
rust/kernel/types/for_lt.rs | 117 +++++++++++
rust/kernel/usb.rs | 61 +++---
rust/macros/for_lt.rs | 274 ++++++++++++++++++++++++++
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 | 17 +-
samples/rust/rust_i2c_client.rs | 14 +-
samples/rust/rust_soc.rs | 9 +-
40 files changed, 1095 insertions(+), 511 deletions(-)
create mode 100644 rust/kernel/types/for_lt.rs
create mode 100644 rust/macros/for_lt.rs
base-commit: 454257f6d124a92342dcbb7710c03dd6ef96c731
--
2.54.0
next reply other threads:[~2026-05-21 23:39 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-21 23:34 Danilo Krummrich [this message]
2026-05-21 23:34 ` [PATCH v4 01/27] rust: alloc: remove `'static` bound on `ForeignOwnable` Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 02/27] rust: driver: move 'static bounds to constructor Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 03/27] rust: driver: decouple driver private data from driver type Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 04/27] rust: driver core: drop drvdata before devres release Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 05/27] rust: pci: implement Sync for Device<Bound> Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 06/27] rust: platform: " Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 07/27] rust: auxiliary: " Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 08/27] rust: usb: " Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 09/27] rust: device: " Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 10/27] rust: device: make Core and CoreInternal lifetime-parameterized Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 11/27] rust: pci: make Driver trait lifetime-parameterized Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 12/27] rust: platform: " Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 13/27] rust: auxiliary: " Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 14/27] rust: usb: " Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 15/27] rust: i2c: " Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 16/27] rust: driver: update module documentation for GAT-based Data type Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 17/27] rust: pci: make Bar lifetime-parameterized Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 18/27] rust: io: make IoMem and ExclusiveIoMem lifetime-parameterized Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 19/27] samples: rust: rust_driver_pci: use HRT lifetime for Bar Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 20/27] gpu: nova-core: separate driver type from driver data Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 21/27] rust: types: add `ForLt` trait for higher-ranked lifetime support Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 22/27] rust: auxiliary: generalize Registration over ForLt Danilo Krummrich
2026-05-21 23:34 ` [PATCH v4 23/27] samples: rust: rust_driver_auxiliary: showcase lifetime-bound registration data Danilo Krummrich
2026-05-21 23:34 ` [PATCH REF v4 24/27] gpu: nova-core: use lifetime for Bar Danilo Krummrich
2026-05-21 23:34 ` [PATCH REF v4 25/27] gpu: nova-core: unregister sysmem flush page from Drop Danilo Krummrich
2026-05-21 23:34 ` [PATCH REF v4 26/27] gpu: nova-core: replace ARef<Device> with &'bound Device in SysmemFlush Danilo Krummrich
2026-05-21 23:34 ` [PATCH REF v4 27/27] gpu: drm: tyr: use lifetime for IoMem Danilo Krummrich
2026-05-22 10:14 ` [PATCH v4 00/27] rust: device: Higher-Ranked Lifetime Types for device drivers Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260521233501.1191842-1-dakr@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=abdiel.janulgue@gmail.com \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=david.m.ertman@intel.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=driver-core@lists.linux.dev \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=igor.korotin@linux.dev \
--cc=ira.weiny@intel.com \
--cc=kwilczynski@kernel.org \
--cc=leon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-pwm@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=m.wilczynski@samsung.com \
--cc=markus.probst@posteo.de \
--cc=nova-gpu@lists.linux.dev \
--cc=ojeda@kernel.org \
--cc=pcolberg@redhat.com \
--cc=rafael@kernel.org \
--cc=robin.murphy@arm.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=ukleinek@kernel.org \
--cc=viresh.kumar@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox