Skip to content

Commit eb67ab2

Browse files
hoshinolinajannau
authored andcommitted
drm/scheduler: Clean up jobs when the scheduler is torn down.
drm_sched_fini() currently leaves any pending jobs dangling, which causes segfaults and other badness when job completion fences are signaled after the scheduler is torn down. Explicitly detach all jobs from their completion callbacks and free them. This makes it possible to write a sensible safe abstraction for drm_sched, without having to externally duplicate the tracking of in-flight jobs. This shouldn't regress any existing drivers, since calling drm_sched_fini() with any pending jobs is broken and this change should be a no-op if there are no pending jobs. Signed-off-by: Asahi Lina <lina@asahilina.net>
1 parent 3531fe2 commit eb67ab2

1 file changed

Lines changed: 25 additions & 0 deletions

File tree

drivers/gpu/drm/scheduler/sched_main.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,8 +1334,33 @@ EXPORT_SYMBOL(drm_sched_init);
13341334
void drm_sched_fini(struct drm_gpu_scheduler *sched)
13351335
{
13361336
struct drm_sched_entity *s_entity;
1337+
struct drm_sched_job *s_job, *tmp;
13371338
int i;
13381339

1340+
/*
1341+
* Stop the scheduler, detaching all jobs from their hardware callbacks
1342+
* and cleaning up complete jobs.
1343+
*/
1344+
drm_sched_stop(sched, NULL);
1345+
1346+
/*
1347+
* Iterate through the pending job list and free all jobs.
1348+
* This assumes the driver has either guaranteed jobs are already stopped, or that
1349+
* otherwise it is responsible for keeping any necessary data structures for
1350+
* in-progress jobs alive even when the free_job() callback is called early (e.g. by
1351+
* putting them in its own queue or doing its own refcounting).
1352+
*/
1353+
list_for_each_entry_safe(s_job, tmp, &sched->pending_list, list) {
1354+
spin_lock(&sched->job_list_lock);
1355+
list_del_init(&s_job->list);
1356+
spin_unlock(&sched->job_list_lock);
1357+
1358+
drm_sched_fence_finished(s_job->s_fence, -ESRCH);
1359+
1360+
WARN_ON(s_job->s_fence->parent);
1361+
sched->ops->free_job(s_job);
1362+
}
1363+
13391364
drm_sched_wqueue_stop(sched);
13401365

13411366
for (i = DRM_SCHED_PRIORITY_KERNEL; i < sched->num_rqs; i++) {

0 commit comments

Comments
 (0)