Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sched: Fix potentially missing balancing with Proxy Exec

K Prateek pointed out that with Proxy Exec, we may have cases
where we context switch in __schedule(), while the donor remains
the same. This could cause balancing issues, since the
put_prev_set_next() logic short-cuts if (prev == next). With
proxy-exec prev is the previous donor, and next is the next
donor. Should the donor remain the same, but different tasks are
picked to actually run, the shortcut will have avoided enqueuing
the sched class balance callback.

So, if we are context switching, add logic to catch the
same-donor case, and trigger the put_prev/set_next calls to
ensure the balance callbacks get enqueued.

Closes: https://lore.kernel.org/lkml/20ea3670-c30a-433b-a07f-c4ff98ae2379@amd.com/
Reported-by: K Prateek Nayak <kprateek.nayak@amd.com>
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: John Stultz <jstultz@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20260324191337.1841376-4-jstultz@google.com

authored by

John Stultz and committed by
Peter Zijlstra
f4fe6be8 37341ec5

+23 -1
+23 -1
kernel/sched/core.c
··· 6826 6826 6827 6827 pick_again: 6828 6828 next = pick_next_task(rq, rq->donor, &rf); 6829 - rq_set_donor(rq, next); 6830 6829 rq->next_class = next->sched_class; 6831 6830 if (sched_proxy_exec()) { 6831 + struct task_struct *prev_donor = rq->donor; 6832 + 6833 + rq_set_donor(rq, next); 6832 6834 if (unlikely(next->blocked_on)) { 6833 6835 next = find_proxy_task(rq, next, &rf); 6834 6836 if (!next) ··· 6838 6836 if (next == rq->idle) 6839 6837 goto keep_resched; 6840 6838 } 6839 + if (rq->donor == prev_donor && prev != next) { 6840 + struct task_struct *donor = rq->donor; 6841 + /* 6842 + * When transitioning like: 6843 + * 6844 + * prev next 6845 + * donor: B B 6846 + * curr: A B or C 6847 + * 6848 + * then put_prev_set_next_task() will not have done 6849 + * anything, since B == B. However, A might have 6850 + * missed a RT/DL balance opportunity due to being 6851 + * on_cpu. 6852 + */ 6853 + donor->sched_class->put_prev_task(rq, donor, donor); 6854 + donor->sched_class->set_next_task(rq, donor, true); 6855 + } 6856 + } else { 6857 + rq_set_donor(rq, next); 6841 6858 } 6859 + 6842 6860 picked: 6843 6861 clear_tsk_need_resched(prev); 6844 6862 clear_preempt_need_resched();