[PATCH OLK-6.6 v1] sched/fair: Avoid overflow in place_entity()
From: Hui Su <sh_def@163.com> mainline inclusion from mainline-v7.3 commit 2f93bcb3f9aaf6ceee1aec0a97d4fe386d48e781 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/21059 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- place_entity() inflates an entity's virtual lag with lag * (load + weight) / load Commit 4823725d9d1d ("sched/fair: Increase weight bits for avg_vruntime") replaced the scaled-down weights used in this calculation with avg_vruntime_weight(), removing the arithmetic headroom provided by scale_load_down(). The multiplication can overflow s64 before the division even when the final quotient is representable. A task's hierarchical effective weight can be as small as 2 after avg_vruntime_weight() scaling under group scheduling, while entity_lag() bounds |vlag| by calc_delta_fair(cfs_rq_max_slice(cfs_rq) + TICK_NSEC, se) For example, with HZ=1000, NICE_0_LOAD=1048576, and the minimum scaled hierarchical weight scale_load(2)=2048, this bound is 891289600. With 114 maximum-weight entities, the runqueue load is 10361604096. The intermediate product is: 891289600 * (10361604096 + 2) = 9235189971864780800 > S64_MAX The signed overflow corrupts the entity's placement. Rewrite lag * (load + weight) / load as lag + lag * weight / load The two expressions are equivalent, but the latter avoids multiplying the virtual lag by the total runqueue weight. entity_lag() bounds vlag against the entity's effective weight, so the remaining lag * weight product stays bounded. rescale_entity() preserves this scale across h_load changes and already relies on the same product when rescaling vlag. Keep the original zero-load warning semantics by multiplying lag by weight after replacing the divisor with one. Fixes: 4823725d9d1d ("sched/fair: Increase weight bits for avg_vruntime") Signed-off-by: Hui Su <sh_def@163.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260928124754.1692077-1-sh_def@163.com Conflicts: kernel/sched/fair.c [ This commit Fixes 4823725d9d1d. Even though we don't have this commit merged, the issue also exist on this kernel. Because the issue is not introduced from 4823725d9d1d, it came from the very first commit of EEVDF. ] Signed-off-by: Yao Yiqi <yaoyiqi3@huawei.com> --- kernel/sched/fair.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 5cd79de18be4..69176c7134bb 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5617,7 +5617,7 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) */ if (sched_feat(PLACE_LAG) && cfs_rq->nr_running) { struct sched_entity *curr = cfs_rq->curr; - unsigned long load; + long load, weight; lag = se->vlag; @@ -5684,11 +5684,20 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) load = cfs_rq->sum_weight; if (curr && curr->on_rq) load += scale_load_down(curr->load.weight); - - lag *= load + scale_load_down(se->load.weight); if (WARN_ON_ONCE(!load)) load = 1; - lag = div_s64(lag, load); + + weight = scale_load_down(se->load.weight); + + /* + * Rewrite, because the product (W + w_i)*vl'_i might + * overflow s64: + * + * vl_i = (W + w_i)*vl'_i / W + * = (W*vl'_i + w_i*vl'_i) / W + * = vl'_i + w_i*vl'_i/W + */ + lag += div64_long(lag * weight, load); } skip_lag_scale: -- 2.34.1
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/30267 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/LOA... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/30267 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/LOA...
participants (2)
-
patchwork bot -
Yao Yiqi