Skip to content

Commit 5324953

Browse files
author
Peter Zijlstra
committed
sched/core: Fix wakeup_preempt's next_class tracking
Kernel test robot reported that tools/testing/selftests/kvm/hardware_disable_test was failing due to commit 7040696 ("sched/core: Rework sched_class::wakeup_preempt() and rq_modified_*()") It turns out there were two related problems that could lead to a missed preemption: - when hitting newidle balance from the idle thread, it would elevate rb->next_class from &idle_sched_class to &fair_sched_class, causing later wakeup_preempt() calls to not hit the sched_class_above() case, and not issue resched_curr(). Notably, this modification pattern should only lower the next_class, and never raise it. Create two new helper functions to wrap this. - when doing schedule_idle(), it was possible to miss (re)setting rq->next_class to &idle_sched_class, leading to the very same problem. Cc: Sean Christopherson <seanjc@google.com> Fixes: 7040696 ("sched/core: Rework sched_class::wakeup_preempt() and rq_modified_*()") Reported-by: kernel test robot <oliver.sang@intel.com> Closes: https://lore.kernel.org/oe-lkp/202602122157.4e861298-lkp@intel.com Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260218163329.GQ1395416@noisy.programming.kicks-ass.net
1 parent 4c652a4 commit 5324953

4 files changed

Lines changed: 16 additions & 4 deletions

File tree

kernel/sched/core.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6830,6 +6830,7 @@ static void __sched notrace __schedule(int sched_mode)
68306830
/* SCX must consult the BPF scheduler to tell if rq is empty */
68316831
if (!rq->nr_running && !scx_enabled()) {
68326832
next = prev;
6833+
rq->next_class = &idle_sched_class;
68336834
goto picked;
68346835
}
68356836
} else if (!preempt && prev_state) {

kernel/sched/ext.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,7 +2460,7 @@ do_pick_task_scx(struct rq *rq, struct rq_flags *rf, bool force_scx)
24602460
/* see kick_cpus_irq_workfn() */
24612461
smp_store_release(&rq->scx.kick_sync, rq->scx.kick_sync + 1);
24622462

2463-
rq->next_class = &ext_sched_class;
2463+
rq_modified_begin(rq, &ext_sched_class);
24642464

24652465
rq_unpin_lock(rq, rf);
24662466
balance_one(rq, prev);
@@ -2475,7 +2475,7 @@ do_pick_task_scx(struct rq *rq, struct rq_flags *rf, bool force_scx)
24752475
* If @force_scx is true, always try to pick a SCHED_EXT task,
24762476
* regardless of any higher-priority sched classes activity.
24772477
*/
2478-
if (!force_scx && sched_class_above(rq->next_class, &ext_sched_class))
2478+
if (!force_scx && rq_modified_above(rq, &ext_sched_class))
24792479
return RETRY_TASK;
24802480

24812481
keep_prev = rq->scx.flags & SCX_RQ_BAL_KEEP;

kernel/sched/fair.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12982,7 +12982,7 @@ static int sched_balance_newidle(struct rq *this_rq, struct rq_flags *rf)
1298212982
t0 = sched_clock_cpu(this_cpu);
1298312983
__sched_balance_update_blocked_averages(this_rq);
1298412984

12985-
this_rq->next_class = &fair_sched_class;
12985+
rq_modified_begin(this_rq, &fair_sched_class);
1298612986
raw_spin_rq_unlock(this_rq);
1298712987

1298812988
for_each_domain(this_cpu, sd) {
@@ -13049,7 +13049,7 @@ static int sched_balance_newidle(struct rq *this_rq, struct rq_flags *rf)
1304913049
pulled_task = 1;
1305013050

1305113051
/* If a higher prio class was modified, restart the pick */
13052-
if (sched_class_above(this_rq->next_class, &fair_sched_class))
13052+
if (rq_modified_above(this_rq, &fair_sched_class))
1305313053
pulled_task = -1;
1305413054

1305513055
out:

kernel/sched/sched.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2748,6 +2748,17 @@ static inline const struct sched_class *next_active_class(const struct sched_cla
27482748

27492749
#define sched_class_above(_a, _b) ((_a) < (_b))
27502750

2751+
static inline void rq_modified_begin(struct rq *rq, const struct sched_class *class)
2752+
{
2753+
if (sched_class_above(rq->next_class, class))
2754+
rq->next_class = class;
2755+
}
2756+
2757+
static inline bool rq_modified_above(struct rq *rq, const struct sched_class *class)
2758+
{
2759+
return sched_class_above(rq->next_class, class);
2760+
}
2761+
27512762
static inline bool sched_stop_runnable(struct rq *rq)
27522763
{
27532764
return rq->stop && task_on_rq_queued(rq->stop);

0 commit comments

Comments
 (0)