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: gem: Introduce shmem::Object::sg_table() Date: Fri, 05 Jun 2026 06:03:38 +1000 Message-ID: In-Reply-To: <20260604192740.659240-5-lyude@redhat.com> References: <20260604192740.659240-1-lyude@redhat.com> <20260604192740.659240-5-lyude@redhat.com> X-Mailer: Claude Code Patch Reviewer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Patch Review **Most complex patch =E2=80=94 warrants careful scrutiny.** **Drop ordering in `free_callback` is correct:** ```rust unsafe { ManuallyDrop::drop(&mut (*this).sgt_res) }; unsafe { bindings::drm_gem_shmem_release(base) }; let _ =3D unsafe { KBox::from_raw(this) }; ``` `sgt_res` must drop first because its `Drop` calls `__drm_gem_shmem_free_sg= t_locked` which needs the GEM object alive. Then `drm_gem_shmem_release` cl= eans up the C-side shmem state. Then `KBox::from_raw` drops the remaining R= ust fields. The `ManuallyDrop` pattern is the right choice here since `SetO= nce::reset()` was removed in v18. **Double-checked locking in `sg_table()` is correct:** ```rust if let Some(sgt_res) =3D self.sgt_res.as_ref() { break 'out sgt_res; } let _guard =3D self.sgt_lock.lock(); if let Some(sgt_res) =3D self.sgt_res.as_ref() { break 'out sgt_res; } self.sgt_res.populate(Devres::new(dev, SGTableMap::new(self))?); ``` This requires that `SetOnce::as_ref()` is safe to call without holding `sgt= _lock` (i.e., it provides atomic-like visibility). If `SetOnce` is implemen= ted with proper memory ordering (which kernel `SetOnce` should be), this is= correct. If not, there's a data race on the fast path. **`SGTableMap::new` uses `from_err_ptr` with a `?` inside an `Init` returni= ng closure:** ```rust fn new(obj: &Object) -> impl Init { from_err_ptr(unsafe { bindings::drm_gem_shmem_get_pages_sgt(obj.as_raw_= shmem()) })?; Ok(Self { obj: obj.into() }) } ``` This calls `drm_gem_shmem_get_pages_sgt` which acquires/releases `dma_resv`= internally (it uses `dma_resv_lock_interruptible`). The return value (an `= sg_table*`) is checked for errors via `from_err_ptr` but the actual pointer= is then discarded =E2=80=94 the implementation relies on the fact that `sh= mem->sgt` is set as a side effect. This is correct per the C implementation= , but the discarded return value deserves a comment explaining this pattern. **Device identity check:** ```rust if dev.as_raw() !=3D self.dev().as_ref().as_raw() { return Err(EINVAL); } ``` Good =E2=80=94 prevents creating a `Devres` bound to the wrong device, whic= h would cause the revocation to fire at the wrong time or not at all. **`SGTableMap` raw pointer storage:** ```rust pub struct SGTableMap { obj: NonNull>, } ``` This stores a non-refcounted pointer to the owning `Object`. The invariant = is that `SGTableMap` lives inside the `Object`'s `sgt_res` field, so the ob= ject outlives it. The `ManuallyDrop` ensures `sgt_res` is dropped before th= e object in `free_callback`. This is sound but not self-documenting =E2=80= =94 a `// INVARIANT:` comment on the `obj` field explaining the lifetime re= lationship would help future maintainers. **Test only covers the failure path:** ```rust fn fail_sg_table_on_wrong_dev() -> Result { ``` The TODO explains that testing the success path would require dummy DMA ops= . The failure test is useful =E2=80=94 it confirms the device check prevent= s `sgt_res` from being populated with a wrong device. Good defensive test. **`Send`/`Sync` for `SGTableMap`:** The safety justification references GEM= object thread-safety, which is established by the existing `Send`/`Sync` i= mpls on `Object`. This is correct. --- Generated by Claude Code Patch Reviewer