Hi Emmanuel, I have been looking into what appears to be the same NULL dereference in nouveau_fence_sync(), and I found a path that may explain how prev->cli ends up NULL.
In the failure I traced, nouveau_fence_no_signaling() removes the fence from the pending list, but leaves fence->channel pointing to the channel. The fence itself can remain alive through a BO reservation. After the channel is torn down, the same fence can later be encountered again in nouveau_fence_sync() through that stale channel association. The normal nouveau_fence_signal() path clears fence->channel when removing the fence from the pending list, so the no-signaling path appears asymmetric here. I also did not find a normal path that explicitly sets channel->cli to NULL while keeping the channel valid. If this is the path leading to the crash, checking prev->cli here would prevent the dereference, but the stale fence->channel association would still remain. The existing fence/channel lifetime handling seems to rely on clearing fence->channel once the fence is detached from the channel. If that is the intended invariant, preserving it in the no-signaling path seems preferable to allowing a non-NULL fence->channel to refer to a torn-down channel. I sent a separate patch that clears fence->channel in nouveau_fence_no_signaling(): [PATCH] drm/nouveau: Clear fence channel in no-signaling path https://lore.kernel.org/r/[email protected] Thanks, Beomseok
