On 10/16/26 09:44, Jesse Zhang wrote:
> Every job of a gang except the leader holds a reference to the
> scheduled fence of the leader in job->gang_submit. Only
> amdgpu_job_free(), used for jobs which never ran, drops it, so for every
> gang submission which completes the scheduler fence of the leader, and
> with it its hardware fence, is leaked. amdgpu_job_free() in turn checks
> for the leader only after drm_sched_job_cleanup() cleared the scheduler
> fence, so a leader freed there drops a reference it never took.
> 
> On navi31, 100 submissions of a GFX + COMPUTE gang grow the slab cache
> drm_sched_fence is merged into by 60 to 180 objects each time, while
> 100 GFX only submissions don't.
> 
> Drop the reference when the scheduler frees the job as well, and check
> for the leader before the scheduler fence is cleared in both places.
> 
> Fixes: 68ce8b242242 ("drm/amdgpu: add gang submit backend v2")
> Fixes: f7d66fb2ea43 ("drm/amdgpu: cleanup scheduler job initialization v2")
> Signed-off-by: Jesse Zhang <[email protected]>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_job.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> index 0056a93c400a..f8e67c1b5a4c 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
> @@ -311,10 +311,19 @@ void amdgpu_job_free_resources(struct amdgpu_job *job)
>               amdgpu_ib_free(&job->ibs[i], f);
>  }
>  
> +/* Must be called before drm_sched_job_cleanup() clears the scheduler fence 
> */
> +static void amdgpu_job_put_gang(struct amdgpu_job *job)
> +{
> +     /* The gang leader doesn't hold a reference to itself */
> +     if (job->gang_submit != &job->base.s_fence->scheduled)
> +             dma_fence_put(job->gang_submit);
> +}
> +

Good catch, but I think we should just unify amdgpu_job_free(), 
amdgpu_job_free_cb().

As far as I can see the call to amdgpu_job_free_resources() is incorrectly 
placed after drm_sched_job_cleanup() as well.

Regards,
Christian.

>  static void amdgpu_job_free_cb(struct drm_sched_job *s_job)
>  {
>       struct amdgpu_job *job = to_amdgpu_job(s_job);
>  
> +     amdgpu_job_put_gang(job);
>       drm_sched_job_cleanup(s_job);
>  
>       amdgpu_sync_free(&job->explicit_sync);
> @@ -349,13 +358,12 @@ void amdgpu_job_set_gang_leader(struct amdgpu_job *job,
>  
>  void amdgpu_job_free(struct amdgpu_job *job)
>  {
> +     amdgpu_job_put_gang(job);
>       if (job->base.entity)
>               drm_sched_job_cleanup(&job->base);
>  
>       amdgpu_job_free_resources(job);
>       amdgpu_sync_free(&job->explicit_sync);
> -     if (job->gang_submit != &job->base.s_fence->scheduled)
> -             dma_fence_put(job->gang_submit);
>  
>       if (dma_fence_was_initialized(&job->hw_fence->base))
>               dma_fence_put(&job->hw_fence->base);

Reply via email to