sched/eevdf: Fix miscalculation in reweight_entity() when se is not curr
authorTianchen Ding <dtcccc@linux.alibaba.com>
Wed, 6 Mar 2024 02:21:33 +0000 (10:21 +0800)
committerPeter Zijlstra <peterz@infradead.org>
Mon, 22 Apr 2024 11:01:26 +0000 (13:01 +0200)
reweight_eevdf() only keeps V unchanged inside itself. When se !=
cfs_rq->curr, it would be dequeued from rb tree first. So that V is
changed and the result is wrong. Pass the original V to reweight_eevdf()
to fix this issue.

Fixes: eab03c23c2a1 ("sched/eevdf: Fix vruntime adjustment on reweight")
Signed-off-by: Tianchen Ding <dtcccc@linux.alibaba.com>
[peterz: flip if() condition for clarity]
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Abel Wu <wuyun.abel@bytedance.com>
Link: https://lkml.kernel.org/r/20240306022133.81008-3-dtcccc@linux.alibaba.com
kernel/sched/fair.c

index 5551ce2af73e7ed139017ae636ab1ab839e95fd7..6d266917d38d7fa0f4b87e2255f835b57ebf3e5a 100644 (file)
@@ -3676,11 +3676,10 @@ static inline void
 dequeue_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) { }
 #endif
 
-static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se,
+static void reweight_eevdf(struct sched_entity *se, u64 avruntime,
                           unsigned long weight)
 {
        unsigned long old_weight = se->load.weight;
-       u64 avruntime = avg_vruntime(cfs_rq);
        s64 vlag, vslice;
 
        /*
@@ -3787,24 +3786,26 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
                            unsigned long weight)
 {
        bool curr = cfs_rq->curr == se;
+       u64 avruntime;
 
        if (se->on_rq) {
                /* commit outstanding execution time */
                update_curr(cfs_rq);
+               avruntime = avg_vruntime(cfs_rq);
                if (!curr)
                        __dequeue_entity(cfs_rq, se);
                update_load_sub(&cfs_rq->load, se->load.weight);
        }
        dequeue_load_avg(cfs_rq, se);
 
-       if (!se->on_rq) {
+       if (se->on_rq) {
+               reweight_eevdf(se, avruntime, weight);
+       } else {
                /*
                 * Because we keep se->vlag = V - v_i, while: lag_i = w_i*(V - v_i),
                 * we need to scale se->vlag when w_i changes.
                 */
                se->vlag = div_s64(se->vlag * se->load.weight, weight);
-       } else {
-               reweight_eevdf(cfs_rq, se, weight);
        }
 
        update_load_set(&se->load, weight);