Skip to content

Commit

Permalink
Merge tag 'sched-urgent-2023-10-14' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/tip/tip

Pull scheduler fixes from Ingo Molnar:
 "Two EEVDF fixes"

* tag 'sched-urgent-2023-10-14' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  sched/eevdf: Fix pick_eevdf()
  sched/eevdf: Fix min_deadline heap integrity
  • Loading branch information
torvalds committed Oct 14, 2023
2 parents 23931d9 + b01db23 commit 42578c7
Showing 1 changed file with 59 additions and 14 deletions.
73 changes: 59 additions & 14 deletions kernel/sched/fair.c
Original file line number Diff line number Diff line change
Expand Up @@ -872,14 +872,16 @@ struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq)
*
* Which allows an EDF like search on (sub)trees.
*/
static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
static struct sched_entity *__pick_eevdf(struct cfs_rq *cfs_rq)
{
struct rb_node *node = cfs_rq->tasks_timeline.rb_root.rb_node;
struct sched_entity *curr = cfs_rq->curr;
struct sched_entity *best = NULL;
struct sched_entity *best_left = NULL;

if (curr && (!curr->on_rq || !entity_eligible(cfs_rq, curr)))
curr = NULL;
best = curr;

/*
* Once selected, run a task until it either becomes non-eligible or
Expand All @@ -900,41 +902,83 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
}

/*
* If this entity has an earlier deadline than the previous
* best, take this one. If it also has the earliest deadline
* of its subtree, we're done.
* Now we heap search eligible trees for the best (min_)deadline
*/
if (!best || deadline_gt(deadline, best, se)) {
if (!best || deadline_gt(deadline, best, se))
best = se;
if (best->deadline == best->min_deadline)
break;
}

/*
* If the earlest deadline in this subtree is in the fully
* eligible left half of our space, go there.
* Every se in a left branch is eligible, keep track of the
* branch with the best min_deadline
*/
if (node->rb_left) {
struct sched_entity *left = __node_2_se(node->rb_left);

if (!best_left || deadline_gt(min_deadline, best_left, left))
best_left = left;

/*
* min_deadline is in the left branch. rb_left and all
* descendants are eligible, so immediately switch to the second
* loop.
*/
if (left->min_deadline == se->min_deadline)
break;
}

/* min_deadline is at this node, no need to look right */
if (se->deadline == se->min_deadline)
break;

/* else min_deadline is in the right branch. */
node = node->rb_right;
}

/*
* We ran into an eligible node which is itself the best.
* (Or nr_running == 0 and both are NULL)
*/
if (!best_left || (s64)(best_left->min_deadline - best->deadline) > 0)
return best;

/*
* Now best_left and all of its children are eligible, and we are just
* looking for deadline == min_deadline
*/
node = &best_left->run_node;
while (node) {
struct sched_entity *se = __node_2_se(node);

/* min_deadline is the current node */
if (se->deadline == se->min_deadline)
return se;

/* min_deadline is in the left branch */
if (node->rb_left &&
__node_2_se(node->rb_left)->min_deadline == se->min_deadline) {
node = node->rb_left;
continue;
}

/* else min_deadline is in the right branch */
node = node->rb_right;
}
return NULL;
}

if (!best || (curr && deadline_gt(deadline, best, curr)))
best = curr;
static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
{
struct sched_entity *se = __pick_eevdf(cfs_rq);

if (unlikely(!best)) {
if (!se) {
struct sched_entity *left = __pick_first_entity(cfs_rq);
if (left) {
pr_err("EEVDF scheduling fail, picking leftmost\n");
return left;
}
}

return best;
return se;
}

#ifdef CONFIG_SCHED_DEBUG
Expand Down Expand Up @@ -3613,6 +3657,7 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
*/
deadline = div_s64(deadline * old_weight, weight);
se->deadline = se->vruntime + deadline;
min_deadline_cb_propagate(&se->run_node, NULL);
}

#ifdef CONFIG_SMP
Expand Down

0 comments on commit 42578c7

Please sign in to comment.