[PATCH 1/3] drm/amdgpu: Avoid accessing job->entity after the job is scheduled.

Andres Rodriguez andresx7 at gmail.com
Fri Oct 20 19:31:19 UTC 2017



On 2017-10-20 02:24 PM, Christian König wrote:
> Am 20.10.2017 um 18:51 schrieb Andrey Grodzovsky:
>>
>>
>> On 2017-10-20 12:26 PM, Andres Rodriguez wrote:
>>>
>>>
>>> On 2017-10-20 12:19 PM, Andrey Grodzovsky wrote:
>>>>
>>>>
>>>> On 2017-10-20 11:59 AM, Andres Rodriguez wrote:
>>>>>
>>>>>
>>>>> On 2017-10-20 09:32 AM, Andrey Grodzovsky wrote:
>>>>>> Bug: amdgpu_job_free_cb was accessing s_job->s_entity when the 
>>>>>> allocated
>>>>>> amdgpu_ctx (and the entity inside it) were already deallocated from
>>>>>> amdgpu_cs_parser_fini.
>>>>>>
>>>>>> Fix: Save job's priority on it's creation instead of accessing it 
>>>>>> from
>>>>>> s_entity later on.
>>>>>
>>>>> I'm not sure if this is the correct approach for a fix.
>>>>>
>>>>> Keeping s_entity as a dangling pointer could result in a similar 
>>>>> bugs being reintroduced. For example, there would still be a race 
>>>>> condition between amdgpu_cs_parser_fini() and amdgpu_job_dependency().
>>>>
>>>> .dependency hook is called only in once place 
>>>> amd_sched_entity_pop_job, amdgpu_cs_parser_fini will wait (from 
>>>> amd_sched_entity_fini) for wake_up(&sched->job_scheduled) from 
>>>> amd_sched_main so I don't see a race here.
>>>>
>>>>>
>>>>>
>>>>> Instead, it might be better for the job to grab a reference to the 
>>>>> context during job_init(), and put that reference on job free.
>>>>
>>>> Originally it was my thinkimg to, but I consulted Christian and he 
>>>> advised that quote - "it's not the best idea since
>>>> the problem is that when we terminate a process we need to make sure 
>>>> that all resources are released or at least not hold for much 
>>>> longer. When we keep the ctx alive with the job we need to also keep 
>>>> the VM alive and that means we need to keep all the VM page tables 
>>>> alive".
>>>>
>>>
>>> That makes sense.
>>>
>>> Since s_entity is tied to the context reference held by the parser, 
>>> can you set it to NULL when you drop the context reference there?
>>
>> O am not sure i understand - you want to send s_job->s_entity to NULL 
>> in amd_sched_entity_fini for each remaining job in the queue ? But all 
>> the jobs remaining in the queue are destroyed there anyway.
> 
> I think what Andres means here is exactly what we planned to do anyway. 
> Set job->s_entity to NULL as soon as we know that the entity is not used 
> any more and might be released.

Yeah this is what I would like to see. If you already have discussed it 
and have a plan to address it, then this patch looks good to me for 
static and dynamic priorities.

Feel free to add:
Reviewed-by: Andres Rodriguez <andresx7 at gmail.com>

> 
> In the long term we should target towards making s_job->s_entity as well 
> as job->vm superfluous. This way we could even push remaining jobs on a 
> graveyard entity when we destroy one and timeout.
> 
> Alternatively we could look into why wait_event_killable is sometimes 
> not killable as the name says :)
> 
> Maybe we can get to a point where we can finally reboot the system 
> cleanly even when the GPU is stuck.
> 
> Regards,
> Christian.
> 
>>
>> Thanks,
>> Andrey
>>
>>>
>>> At least that way we can easily detect misuse of s_entity after it 
>>> enters a "possibly deleted" state.
>>>
>>> Regards,
>>> Andres
>>>
>>>> Thanks,
>>>> Andrey
>>>>
>>>>>
>>>>> Regards,
>>>>> Andres
>>>>>
>>>>>>
>>>>>> Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky at amd.com>
>>>>>> ---
>>>>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c        |  3 +--
>>>>>>   drivers/gpu/drm/amd/amdgpu/amdgpu_job.c       |  5 ++---
>>>>>>   drivers/gpu/drm/amd/scheduler/gpu_scheduler.c |  1 +
>>>>>>   drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 32 
>>>>>> ++++++++++++---------------
>>>>>>   4 files changed, 18 insertions(+), 23 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c 
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
>>>>>> index f7fceb6..a760b6e 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
>>>>>> @@ -1192,8 +1192,7 @@ static int amdgpu_cs_submit(struct 
>>>>>> amdgpu_cs_parser *p,
>>>>>>       job->uf_sequence = seq;
>>>>>>         amdgpu_job_free_resources(job);
>>>>>> -    amdgpu_ring_priority_get(job->ring,
>>>>>> - amd_sched_get_job_priority(&job->base));
>>>>>> +    amdgpu_ring_priority_get(job->ring, job->base.s_priority);
>>>>>>         trace_amdgpu_cs_ioctl(job);
>>>>>>       amd_sched_entity_push_job(&job->base);
>>>>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c 
>>>>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
>>>>>> index 0cfc68d..a58e3c5 100644
>>>>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
>>>>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c
>>>>>> @@ -104,7 +104,7 @@ static void amdgpu_job_free_cb(struct 
>>>>>> amd_sched_job *s_job)
>>>>>>   {
>>>>>>       struct amdgpu_job *job = container_of(s_job, struct 
>>>>>> amdgpu_job, base);
>>>>>>   -    amdgpu_ring_priority_put(job->ring, 
>>>>>> amd_sched_get_job_priority(s_job));
>>>>>> +    amdgpu_ring_priority_put(job->ring, s_job->s_priority);
>>>>>>       dma_fence_put(job->fence);
>>>>>>       amdgpu_sync_free(&job->sync);
>>>>>>       amdgpu_sync_free(&job->dep_sync);
>>>>>> @@ -141,8 +141,7 @@ int amdgpu_job_submit(struct amdgpu_job *job, 
>>>>>> struct amdgpu_ring *ring,
>>>>>>       job->fence_ctx = entity->fence_context;
>>>>>>       *f = dma_fence_get(&job->base.s_fence->finished);
>>>>>>       amdgpu_job_free_resources(job);
>>>>>> -    amdgpu_ring_priority_get(job->ring,
>>>>>> - amd_sched_get_job_priority(&job->base));
>>>>>> +    amdgpu_ring_priority_get(job->ring, job->base.s_priority);
>>>>>>       amd_sched_entity_push_job(&job->base);
>>>>>>         return 0;
>>>>>> diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c 
>>>>>> b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
>>>>>> index e4d3b4e..1bbbce2 100644
>>>>>> --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
>>>>>> +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
>>>>>> @@ -529,6 +529,7 @@ int amd_sched_job_init(struct amd_sched_job *job,
>>>>>>   {
>>>>>>       job->sched = sched;
>>>>>>       job->s_entity = entity;
>>>>>> +    job->s_priority = entity->rq - sched->sched_rq;
>>>>>>       job->s_fence = amd_sched_fence_create(entity, owner);
>>>>>>       if (!job->s_fence)
>>>>>>           return -ENOMEM;
>>>>>> diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h 
>>>>>> b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
>>>>>> index 52c8e54..3f75b45 100644
>>>>>> --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
>>>>>> +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
>>>>>> @@ -30,6 +30,19 @@
>>>>>>   struct amd_gpu_scheduler;
>>>>>>   struct amd_sched_rq;
>>>>>>   +enum amd_sched_priority {
>>>>>> +    AMD_SCHED_PRIORITY_MIN,
>>>>>> +    AMD_SCHED_PRIORITY_LOW = AMD_SCHED_PRIORITY_MIN,
>>>>>> +    AMD_SCHED_PRIORITY_NORMAL,
>>>>>> +    AMD_SCHED_PRIORITY_HIGH_SW,
>>>>>> +    AMD_SCHED_PRIORITY_HIGH_HW,
>>>>>> +    AMD_SCHED_PRIORITY_KERNEL,
>>>>>> +    AMD_SCHED_PRIORITY_MAX,
>>>>>> +    AMD_SCHED_PRIORITY_INVALID = -1,
>>>>>> +    AMD_SCHED_PRIORITY_UNSET = -2
>>>>>> +};
>>>>>> +
>>>>>> +
>>>>>>   /**
>>>>>>    * A scheduler entity is a wrapper around a job queue or a group
>>>>>>    * of other entities. Entities take turns emitting jobs from their
>>>>>> @@ -83,6 +96,7 @@ struct amd_sched_job {
>>>>>>       struct delayed_work        work_tdr;
>>>>>>       uint64_t            id;
>>>>>>       atomic_t karma;
>>>>>> +    enum amd_sched_priority s_priority;
>>>>>>   };
>>>>>>     extern const struct dma_fence_ops amd_sched_fence_ops_scheduled;
>>>>>> @@ -114,18 +128,6 @@ struct amd_sched_backend_ops {
>>>>>>       void (*free_job)(struct amd_sched_job *sched_job);
>>>>>>   };
>>>>>>   -enum amd_sched_priority {
>>>>>> -    AMD_SCHED_PRIORITY_MIN,
>>>>>> -    AMD_SCHED_PRIORITY_LOW = AMD_SCHED_PRIORITY_MIN,
>>>>>> -    AMD_SCHED_PRIORITY_NORMAL,
>>>>>> -    AMD_SCHED_PRIORITY_HIGH_SW,
>>>>>> -    AMD_SCHED_PRIORITY_HIGH_HW,
>>>>>> -    AMD_SCHED_PRIORITY_KERNEL,
>>>>>> -    AMD_SCHED_PRIORITY_MAX,
>>>>>> -    AMD_SCHED_PRIORITY_INVALID = -1,
>>>>>> -    AMD_SCHED_PRIORITY_UNSET = -2
>>>>>> -};
>>>>>> -
>>>>>>   /**
>>>>>>    * One scheduler is implemented for each hardware ring
>>>>>>   */
>>>>>> @@ -176,10 +178,4 @@ bool amd_sched_dependency_optimized(struct 
>>>>>> dma_fence* fence,
>>>>>>                       struct amd_sched_entity *entity);
>>>>>>   void amd_sched_job_kickout(struct amd_sched_job *s_job);
>>>>>>   -static inline enum amd_sched_priority
>>>>>> -amd_sched_get_job_priority(struct amd_sched_job *job)
>>>>>> -{
>>>>>> -    return (job->s_entity->rq - job->sched->sched_rq);
>>>>>> -}
>>>>>> -
>>>>>>   #endif
>>>>>>
>>>>
>>
>> _______________________________________________
>> amd-gfx mailing list
>> amd-gfx at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/amd-gfx
> 
> 


More information about the amd-gfx mailing list