sched/numa: Fix a possible divide-by-zero [Linux 5.1]

sched/numa: Fix a possible divide-by-zero [Linux 5.1]

This Linux kernel change "sched/numa: Fix a possible divide-by-zero" is included in the Linux 5.1 release. This change is authored by Xie XiuQi <xiexiuqi [at] huawei.com> on Sat Apr 20 16:34:16 2019 +0800. The commit for this change in Linux stable tree is a860fa7 (patch).

sched/numa: Fix a possible divide-by-zero

sched_clock_cpu() may not be consistent between CPUs. If a task
migrates to another CPU, then se.exec_start is set to that CPU's
rq_clock_task() by update_stats_curr_start(). Specifically, the new
value might be before the old value due to clock skew.

So then if in numa_get_avg_runtime() the expression:

  'now - p->last_task_numa_placement'

ends up as -1, then the divider '*period + 1' in task_numa_placement()
is 0 and things go bang. Similar to update_curr(), check if time goes
backwards to avoid this.

[ peterz: Wrote new changelog. ]
[ mingo: Tweaked the code comment. ]

Signed-off-by: Xie XiuQi <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Cc: <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>

There are 4 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 kernel/sched/fair.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index a4d9e14..35f3ea3 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2007,6 +2007,10 @@ static u64 numa_get_avg_runtime(struct task_struct *p, u64 *period)
    if (p->last_task_numa_placement) {
        delta = runtime - p->last_sum_exec_runtime;
        *period = now - p->last_task_numa_placement;
+
+       /* Avoid time going backwards, prevent potential divide error: */
+       if (unlikely((s64)*period < 0))
+           *period = 0;
    } else {
        delta = p->se.avg.load_sum;
        *period = LOAD_AVG_MAX;

Leave a Reply

Your email address will not be published. Required fields are marked *