DRM ioctls run in process context without any guarantee that the parent bus device is still bound. This series solves the problem by introducing RegistrationGuard -- a guard representing a drm_dev_enter/exit SRCU critical section that proves the parent bus device is bound for the lifetime of the guard.
As initial plumbing for this, the DRM DeviceContext typestates are reworked: Uninit is renamed to Normal, defaults are adjusted, AlwaysRefCounted is restricted to Normal, and a Deref chain from Device<T, Registered> to Device<T, Normal> is established. This gives Device<T, Registered> the semantic that the device is currently registered and the parent bus device is bound, which makes the RegistrationGuard and ioctl dispatch much cleaner. An Ioctl context restricts registration_guard() to ioctl dispatch, where the DRM core guarantees prior registration. On top of that, add RegistrationData as a GAT (Generic Associated Type) on drm::Driver, allowing drivers to store data whose lifetime is tied to the parent bus device binding scope. The data is allocated in Registration::new(), lifetime-erased to 'static for storage, and made accessible through Device<T, Registered>::registration_data_with(). The closure's HRTB ties the lifetime to the closure scope; internally the 'static pointer is cast back to the closure-scoped lifetime. The reference is valid for the duration of the drm_dev_enter/exit critical section held by RegistrationGuard. Also update the ioctl dispatch macro to wrap every handler in a RegistrationGuard, returning ENODEV if the device has been unplugged, and pass the registration data to handlers. A branch with all patches can be found in [1]. [1] https://git.kernel.org/pub/scm/linux/kernel/git/dakr/linux.git/log/?h=drm-lifetime Changes in v5: - Replace __call_ioctl() helper with a simple for<'a> fn(...) coercion - Rebase onto latest drm-rust-next, which requires a faux::Device type with AsBusDevice impl and motivates the removal of the DeviceContext generic from shmem::Object entirely - Replace ForLt with a GAT type RegistrationData<'a> - Fix drm_dev_register() error path race on the C side - Add a few missing #[inline] annotations Changes in v4: - Fix pre-existing unbounded lifetimes in ioctl handler arguments. - Fix registration_guard() being callable on unregistered devices by introducing an Ioctl device context typestate; registration_guard() is now only available on Device<T, Ioctl>, which is exclusively constructed in ioctl dispatch context where the DRM core guarantees prior registration. - Fix type inference allowing handlers to obtain Device<Registered> before RegistrationGuard is acquired. - Make RegistrationGuard !Send via NotThreadSafe to prevent potential lockdep splats from cross-thread SRCU unlock. - Store &Device<T, Registered> directly in RegistrationGuard instead of calling assume_ctx() in Deref. Changes in v3: - Rename UnbindGuard to RegistrationGuard - RegistrationGuard no longer dereferences to &Device<Bound>; it dereferences to &drm::Device<T, Registered> instead - Drop Registration::new() and rename Registration::new_with_lt() to Registration::new() - Rework DeviceContext typestates: rename Uninit to Normal, restrict AlwaysRefCounted to Normal, establish Deref chain from Registered to Normal - Add AsRef<ParentDevice<Bound>> on Device<T, Registered> for parent device access - Move registration_data_with() from RegistrationGuard to drm::Device<T, Registered> - Ioctl handlers no longer receive &Device<Bound>, only registration data and drm::Device<T, Registered> - Use Device<Registered>::as_ref() to access parent device in nova-drm Changes in v2: - Replace unsafe direct registration data access in ioctl dispatch with safe UnbindGuard::registration_data_with() closure - Eliminate unbind_guard() free function; use type-inference anchor to enable direct dev.unbind_guard() method call in the ioctl macro - UnbindGuard::registration_data_with() provides both parent device and registration data to the closure - Add nova-drm conversion patch demonstrating lifetime-aware registration data with &'bound auxiliary::Device<Bound> - Various safety comment and documentation improvements Danilo Krummrich (19): rust: drm: ioctl: fix unbounded lifetimes in ioctl handler arguments rust: drm: rename Uninit DeviceContext to Normal rust: faux: add Device type with AsBusDevice support rust: drm: Add Driver::ParentDevice associated type rust: drm: change default DeviceContext to Normal rust: drm: restrict AlwaysRefCounted to Normal Device context rust: drm: restrict AlwaysRefCounted to Normal GEM Object context rust: drm/gem: remove DeviceContext from shmem::Object rust: drm: split Deref for Device context typestates rust: drm: pin ioctl Device reference to Normal context rust: drm: add Ioctl device context typestate rust: drm: Add RegistrationGuard for drm_dev_enter/exit critical sections rust: drm: Wrap ioctl dispatch in RegistrationGuard rust: drm: return ParentDevice from Device AsRef rust: drm: add AsRef<ParentDevice<Bound>> for Device<Registered> drm: fix race between partial drm_dev_register() failure and ioctl rust: drm: Add RegistrationData to drm::Driver rust: drm: Pass registration data to ioctl handlers drm: nova: Use drm::Device<Registered> to access the parent bus device drivers/gpu/drm/drm_drv.c | 34 +++- drivers/gpu/drm/nova/driver.rs | 38 ++-- drivers/gpu/drm/nova/file.rs | 22 ++- drivers/gpu/drm/nova/gem.rs | 18 +- drivers/gpu/drm/tyr/driver.rs | 25 ++- drivers/gpu/drm/tyr/file.rs | 8 +- drivers/gpu/drm/tyr/gem.rs | 11 +- rust/kernel/drm/device.rs | 293 +++++++++++++++++++++++-------- rust/kernel/drm/driver.rs | 111 +++++++----- rust/kernel/drm/gem/mod.rs | 98 +++++------ rust/kernel/drm/gem/shmem.rs | 257 +++++++++++++-------------- rust/kernel/drm/ioctl.rs | 56 +++++- rust/kernel/drm/mod.rs | 4 +- rust/kernel/faux.rs | 69 ++++++-- samples/rust/rust_driver_faux.rs | 3 +- 15 files changed, 660 insertions(+), 387 deletions(-) base-commit: fa8cc4e3067f958ea2057f37a8a6f9c6b10a9c03 -- 2.54.0
