From mboxrd@z Thu Jan 1 00:00:00 1970 From: Claude Code Review Bot To: dri-devel-reviews@example.com Subject: Claude review: drm/pagemap_util: Ensure proper cache lock management on free Date: Sat, 21 Feb 2026 05:51:04 +1000 Message-ID: In-Reply-To: <20260220190943.66961-2-jonathan.cavitt@intel.com> References: <20260220190943.66961-2-jonathan.cavitt@intel.com> <20260220190943.66961-2-jonathan.cavitt@intel.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 The original code has three paths through `drm_pagemap_cache_fini`: 1. `dpagemap` is NULL =E2=86=92 unlock, goto out 2. `drm_pagemap_shrinker_cancel()` returns true =E2=86=92 set NULL, unlock,= destroy 3. `drm_pagemap_shrinker_cancel()` returns false =E2=86=92 **no unlock** (b= ug) The fix correctly ensures all three paths call `spin_unlock`. However: > + if (!dpagemap) > goto out; > > if (drm_pagemap_shrinker_cancel(dpagemap)) { > cache->dpagemap =3D NULL; > spin_unlock(&cache->lock); > drm_pagemap_destroy(dpagemap, false); > + } else { > +out: > + spin_unlock(&cache->lock); > } Placing a goto label inside an `else` block is valid C but unusual enough t= o make readers do a double-take. The `out:` label is jumped to when `dpagem= ap` is NULL (skipping the `if/else` condition entirely), while the `else` c= lause handles the cancel-failure case =E2=80=94 these are logically differe= nt situations that happen to share the same cleanup action. A slightly clea= ner alternative would be: ```c if (!dpagemap) goto out; if (drm_pagemap_shrinker_cancel(dpagemap)) { cache->dpagemap =3D NULL; spin_unlock(&cache->lock); drm_pagemap_destroy(dpagemap, false); goto done; } out: spin_unlock(&cache->lock); done: mutex_destroy(&cache->lookup_mutex); kfree(cache); ``` That said, the current approach does produce the correct behavior for all t= hree paths, so this is a readability preference, not a correctness issue. There is also a question about the cancel-failure path: when `drm_pagemap_s= hrinker_cancel()` returns false, the code unlocks but does not set `cache->= dpagemap =3D NULL` and does not call `drm_pagemap_destroy()`. This means th= e dpagemap is left dangling as the cache is immediately freed afterward. Lo= oking at `drm_pagemap_shrinker_scan()`, when the shrinker races and wins, i= t sets `cache->dpagemap =3D NULL` and calls `drm_pagemap_destroy()` itself,= so the dpagemap is handled by the shrinker. This is fine =E2=80=94 the rac= e is benign because by the time `drm_pagemap_cache_fini` sees `shrink_link`= as empty, the shrinker has already taken ownership. However, there's also = a window where `drm_pagemap_shrinker_scan` has called `list_del_init` on `s= hrink_link` but has not yet reached `cache->dpagemap =3D NULL`. In that nar= row window, `drm_pagemap_cache_fini` would see `dpagemap` as non-NULL and `= shrink_link` as empty, take the else/out path, and then `kfree(cache)`. The= n the shrinker would proceed to `spin_lock(&cache->lock)` on freed memory. = This race existed before this patch and is not introduced by it, but it may= be worth noting to the author since the Fixes tag suggests this is meant t= o be a complete fix for the function. The commit message says "Static analysis issue" and "Though probably unnece= ssary given the cache is being freed at this step." This is inaccurate =E2= =80=94 the spinlock leak is a real bug, not a cosmetic static analysis find= ing. Even though the cache is about to be freed, calling `kfree()` on a loc= ked spinlock is wrong and will trigger `CONFIG_DEBUG_LOCK_ALLOC` warnings. = The commit message should state the actual consequence more clearly. --- Generated by Claude Code Patch Reviewer