From mboxrd@z Thu Jan 1 00:00:00 1970 From: Claude Code Review Bot To: dri-devel-reviews@example.com Subject: Claude review: rust: drm: Add RegistrationData to drm::Driver Date: Thu, 04 Jun 2026 12:03:17 +1000 Message-ID: In-Reply-To: <20260603011711.2077361-4-dakr@kernel.org> References: <20260603011711.2077361-1-dakr@kernel.org> <20260603011711.2077361-4-dakr@kernel.org> X-Mailer: Claude Code Patch Reviewer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Patch Review This is the most complex and safety-critical patch. Several observations: **`registration_data` field in `Device`**: ```rust pub(super) registration_data: UnsafeCell::Of<'static>>>, ``` Using `UnsafeCell>` is the right choice =E2=80=94 it's interio= r-mutable and non-null. The `'static` lifetime here is the erased form that= gets shortened via `ForLt::cast_ref_unchecked`. **Initialization with `NonNull::dangling()`**: ```rust unsafe { (*raw_drm.as_ptr()).registration_data =3D UnsafeCell::new(NonNull:= :dangling()) }; ``` This is set in `UnregisteredDevice::new()` before the device is registered.= It's later overwritten in `Registration::new_with_lt()` before `drm_dev_re= gister()`. The dangling pointer is never dereferenced because `UnbindGuard`= is only available on `Device`, and registration only succee= ds after the real pointer is written. This is correct. **`Registration::new_with_lt()` =E2=80=94 the `mem::transmute`**: ```rust let ptr: NonNull<::Of<'static>> =3D unsafe { mem::transmute(NonNull::from(Pin::get_ref(reg_data.as_ref())))= }; ``` The safety comment says "Lifetimes do not affect layout, so the pointer cas= t is sound." This is true =E2=80=94 `NonNull>` and `NonNull>` have identical layout. The transmute is used to erase the lifetime for = storage. The data remains valid because `_reg_data` is owned by `Registrati= on` and only dropped after `drm_dev_unplug()`. **Error path in `new_with_lt()`**: ```rust if let Err(e) =3D to_result(ret) { unsafe { *drm.registration_data.get() =3D NonNull::dangling() }; return Err(e); } ``` Good =E2=80=94 on `drm_dev_register()` failure, the pointer is reset to dan= gling. Since registration failed, no ioctls can arrive, so the dangling poi= nter is safe. **`registration_data_unchecked()`**: ```rust unsafe fn registration_data_unchecked(&self) -> &::Of<'_> { ``` The returned lifetime is `'_` (elided to the borrow of `self`), but the act= ual data lives in `Registration`. The caller must ensure the parent device = is bound (via UnbindGuard), which transitively guarantees `Registration` ha= sn't been dropped yet. The HRTB requirement prevents concrete lifetime sele= ction. This is sound. **`registration_data_with()` on `UnbindGuard`**: ```rust pub fn registration_data_with(&self, f: F) -> R where F: for<'a> FnOnce( &'a T::ParentDevice, &'a ::Of<'a>, ) -> R, ``` The `for<'a>` HRTB is the key safety mechanism. The closure cannot choose a= concrete lifetime, so it cannot smuggle out a reference with a chosen life= time. The `'a` tying `ParentDevice` and `RegistrationData::Of<'a>` together= means both live exactly as long as the closure scope. This is the correct = pattern for invariant-over-lifetime types. **Potential concern =E2=80=94 `dev` vs `dev.as_ref()` check in `new_with_lt= ()`**: ```rust if drm.as_ref().as_raw() !=3D dev.as_raw() { ``` This checks that the DRM device's parent device matches `dev`. The `drm.as_= ref()` gets the `device::Device` from the DRM device (via `AsRef`), and com= pares raw pointers. This is correct =E2=80=94 it prevents registering a DRM= device with the wrong parent. **`Registration` no longer uses `devres`** =E2=80=94 the old `new_foreign_o= wned()` used `devres::register()` for device-resource-managed lifetime. The= new approach has `Registration` owned directly by the driver's `Data<'boun= d>`, which ties it to the bus binding scope. This is a deliberate API chang= e and is fine. **Send/Sync bounds**: ```rust unsafe impl Sync for Registration<'_, T> where for<'a> ::Of<'a>: Send ``` The `for<'a> ... Send` bound is correct =E2=80=94 since the data can be acc= essed from any thread (via ioctl dispatch), the `Of<'a>` must be `Send` for= all lifetimes. --- Generated by Claude Code Patch Reviewer