[PATCH v2] sched/eevdf: Fix vprot across reweighting

From: Kayra Cizmeci

Date: Wed Oct 14 2026 - 11:08:29 EST


Currently in reweighting, while a tasks vruntime changes dead protection
could go alive, or alive protection could decrease, increase and go dead.
Fix it.

Fixes: 80390ead2080 ("sched/fair: Separate se->vlag from se->vprot")
Fixes: bcd74b2ffdd0 ("sched/fair: Only set slice protection at pick time")
Suggested-by: Vincent Guittot <vincent.guittot@xxxxxxxxxx>
Signed-off-by: Kayra Cizmeci <kayracizmeci@xxxxxxxxx>
---
v1: https://lore.kernel.org/lkml/20261003114656.105721-1-kayracizmeci@xxxxxxxxx/

Changes v1->v2:
* Throw away the idea of rel_vprot (K Prateek Nayak & Vincent)
* Simplify on_rq path in reweight_eevdf(), as Vincent suggested.
* Reweight the entity locally in enqueue_task_fair()

In my tests (not the same test as the v1 tho)
all of the issues in the base were not present in
the patched version. There were 1 issue or not a issue tho.
In both the base, and the patched version 3 (2 patched) out of 1500
tasks vprot slips more than 5 percent. I tried to reproduce it
but it got back to 0 as I tried. I don't know the cause tho.
And other things aside this was fine. My v1 test wasn't looking
to the on_rq path, so I think that's why I didn't discovered
this in the other tests.

I wanna speak more but, this is getting too bulky.
So so so so... I need to make 1 joke. The joke
is that there is no joke.

kernel/sched/fair.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b42a0ca2a69e..31e226e8f52c 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -4746,12 +4746,15 @@ static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
update_load_set(&se->h_load, weight);

if (on_rq) {
- if (rel_vprot)
- se->vprot += avruntime;
se->deadline += avruntime;
se->rel_deadline = 0;
se->vruntime = avruntime - se->vlag;

+ if (rel_vprot)
+ se->vprot += avruntime;
+ else if (curr)
+ se->vprot = se->vruntime;
+
if (!curr)
__enqueue_entity(cfs_rq, se);
cfs_rq->h_nr_queued++;
@@ -7990,7 +7993,9 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
int task_new = !(flags & ENQUEUE_WAKEUP);
struct sched_entity *se = &p->se;
struct cfs_rq *cfs_rq = &rq->cfs;
- unsigned long weight;
+ unsigned long weight, old_weight;
+ bool live, running;
+ s64 dist;

if (task_is_throttled(p) && enqueue_throttled_task(p))
return;
@@ -8024,8 +8029,24 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
requeue_delayed_entity(cfs_rq, se);

weight = enqueue_hierarchy(p, flags);
+ running = task_current_donor(rq, p);
+ live = protect_slice(se) && running;
+
+ if (live) {
+ old_weight = se->h_load.weight;
+ dist = se->vprot - se->vruntime;
+ }
reweight_eevdf(cfs_rq, se, weight, false);
place_entity(cfs_rq, se, flags | ENQUEUE_QUEUED);
+
+ if (live) {
+ if (weight != old_weight)
+ dist = div64_long(dist * old_weight, weight);
+ se->vprot = se->vruntime + dist;
+ } else if (running) {
+ cancel_protect_slice(se);
+ }
+
__enqueue_entity(cfs_rq, se);

if (!rq_h_nr_queued && rq->cfs.h_nr_queued)
--
2.53.0