[PATCH v2] sched/fair: Sanity check 'best' in pick_eevdf()

From: Tiwei Bie
Date: Wed Jan 31 2024 - 07:04:14 EST


Before commit 2227a957e1d5 ("sched/eevdf: Sort the rbtree by virtual
deadline"), there was a sanity check to catch unexpected failures in the
EEVDF scheduling, which was helpful in identifying problems. It would
be better to restore its previous capability.

Signed-off-by: Tiwei Bie <tiwei.btw@xxxxxxxxxxxx>
---
Refer:
https://lore.kernel.org/lkml/23cbb613-c8a2-4f07-b83b-fa3104bef642@xxxxxxxxxxxxx/

v1 -> v2:
- improve commit log and error message;

kernel/sched/fair.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 533547e3c90a..aeb3b8fee641 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -878,7 +878,7 @@ struct sched_entity *__pick_first_entity(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 *se = __pick_first_entity(cfs_rq);
+ struct sched_entity *first = __pick_first_entity(cfs_rq);
struct sched_entity *curr = cfs_rq->curr;
struct sched_entity *best = NULL;

@@ -887,7 +887,7 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
* in this cfs_rq, saving some cycles.
*/
if (cfs_rq->nr_running == 1)
- return curr && curr->on_rq ? curr : se;
+ return curr && curr->on_rq ? curr : first;

if (curr && (!curr->on_rq || !entity_eligible(cfs_rq, curr)))
curr = NULL;
@@ -900,14 +900,15 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
return curr;

/* Pick the leftmost entity if it's eligible */
- if (se && entity_eligible(cfs_rq, se)) {
- best = se;
+ if (first && entity_eligible(cfs_rq, first)) {
+ best = first;
goto found;
}

/* Heap search for the EEVD entity */
while (node) {
struct rb_node *left = node->rb_left;
+ struct sched_entity *se;

/*
* Eligible entities in left subtree are always better
@@ -937,6 +938,16 @@ static struct sched_entity *pick_eevdf(struct cfs_rq *cfs_rq)
if (!best || (curr && entity_before(curr, best)))
best = curr;

+ /* This is not expected to happen. */
+ if (unlikely(!best)) {
+ if (printk_ratelimit()) {
+ printk_deferred(KERN_ERR
+ "EEVDF scheduling failed on CPU%d, picking leftmost\n",
+ cpu_of(rq_of(cfs_rq)));
+ }
+ best = first;
+ }
+
return best;
}

--
2.34.1