mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
drm/sched: Fix virtual runtime race
Prevent pushing a new job to an entity seeing it being the first in the
queue, and hence entering the drm_sched_rq_add_entity() path, if the pop
side in drm_sched_entity_pop_job() has just de-queued the job but not yet
updated the saved virtual time.
Restoring the unsaved virtual time, which is at this point not a delta but
still an absolute value, pushes the said entity to the rear of the run queue
for a potentially very long time.
We close this race by pulling the locked sections out to encompass both
the queue push/pop and corresponding rbtree management.
This is aligned with the future direction to replace the current lockless
job queue with one of the fully locked standard list primitives.
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
Fixes: 2fa4d8e2c1 ("drm/sched: Add fair scheduling policy")
Suggested-by: Luke.Wildhardt@proton.me # via Claude Opus
Tested-by: Luke.Wildhardt@proton.me
Cc: Christian König <christian.koenig@amd.com>
Cc: Danilo Krummrich <dakr@kernel.org>
Cc: Philipp Stanner <phasta@kernel.org>
Cc: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Vitaly Prosyak <vitaly.prosyak@amd.com>
Cc: stable@vger.kernel.org # v7.2+
[phasta: commit title]
Signed-off-by: Philipp Stanner <phasta@kernel.org>
Link: https://patch.msgid.link/20260915150557.62847-1-tvrtko.ursulin@igalia.com
This commit is contained in:
parent
3ed11c671f
commit
2ab510e631
|
|
@ -559,9 +559,10 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
|
|||
*/
|
||||
smp_wmb();
|
||||
|
||||
spin_lock(&entity->lock);
|
||||
spsc_queue_pop(&entity->job_queue);
|
||||
|
||||
drm_sched_rq_pop_entity(entity);
|
||||
spin_unlock(&entity->lock);
|
||||
|
||||
/* Jobs and entities might have different lifecycles. Since we're
|
||||
* removing the job from the entities queue, set the jobs entity pointer
|
||||
|
|
@ -647,6 +648,9 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
|
|||
* Make sure to set the submit_ts first, to avoid a race.
|
||||
*/
|
||||
sched_job->submit_ts = submit_ts = ktime_get();
|
||||
|
||||
spin_lock(&entity->lock);
|
||||
|
||||
first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node);
|
||||
|
||||
/* first job wakes up scheduler */
|
||||
|
|
@ -657,5 +661,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
|
|||
if (sched)
|
||||
drm_sched_wakeup(sched);
|
||||
}
|
||||
|
||||
spin_unlock(&entity->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_sched_entity_push_job);
|
||||
|
|
|
|||
|
|
@ -257,19 +257,17 @@ static ktime_t drm_sched_entity_get_job_ts(struct drm_sched_entity *entity)
|
|||
struct drm_gpu_scheduler *
|
||||
drm_sched_rq_add_entity(struct drm_sched_entity *entity, ktime_t ts)
|
||||
{
|
||||
struct drm_sched_rq *rq = entity->rq;
|
||||
struct drm_gpu_scheduler *sched;
|
||||
struct drm_sched_rq *rq;
|
||||
|
||||
/* Add the entity to the run queue */
|
||||
spin_lock(&entity->lock);
|
||||
if (entity->stopped) {
|
||||
spin_unlock(&entity->lock);
|
||||
lockdep_assert_held(&entity->lock);
|
||||
|
||||
if (entity->stopped) {
|
||||
DRM_ERROR("Trying to push to a killed entity\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rq = entity->rq;
|
||||
spin_lock(&rq->lock);
|
||||
sched = rq->sched;
|
||||
|
||||
|
|
@ -289,7 +287,6 @@ drm_sched_rq_add_entity(struct drm_sched_entity *entity, ktime_t ts)
|
|||
drm_sched_rq_update_fifo_locked(entity, rq, ts);
|
||||
|
||||
spin_unlock(&rq->lock);
|
||||
spin_unlock(&entity->lock);
|
||||
|
||||
return sched;
|
||||
}
|
||||
|
|
@ -343,16 +340,17 @@ drm_sched_rq_next_rr_ts(struct drm_sched_rq *rq,
|
|||
*/
|
||||
void drm_sched_rq_pop_entity(struct drm_sched_entity *entity)
|
||||
{
|
||||
struct drm_sched_rq *rq = entity->rq;
|
||||
struct drm_sched_job *next_job;
|
||||
struct drm_sched_rq *rq;
|
||||
|
||||
lockdep_assert_held(&entity->lock);
|
||||
|
||||
spin_lock(&rq->lock);
|
||||
|
||||
/*
|
||||
* Update the entity's location in the min heap according to
|
||||
* the timestamp of the next job, if any.
|
||||
*/
|
||||
spin_lock(&entity->lock);
|
||||
rq = entity->rq;
|
||||
spin_lock(&rq->lock);
|
||||
next_job = drm_sched_entity_queue_peek(entity);
|
||||
if (next_job) {
|
||||
ktime_t ts;
|
||||
|
|
@ -375,8 +373,8 @@ void drm_sched_rq_pop_entity(struct drm_sched_entity *entity)
|
|||
drm_sched_entity_save_vruntime(entity, min_vruntime);
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&rq->lock);
|
||||
spin_unlock(&entity->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user