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

This Linux kernel change "sched/numa: Fix a possible divide-by-zero" is included in the Linux 3.16.72 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 f007a3d (patch) which is from upstream commit a860fa7. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream a860fa7.

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

commit a860fa7b96e1a1c974556327aa1aee852d434c21 upstream.

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 <peterz[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
Signed-off-by: Ben Hutchings <[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 7dfaf3c..f967ff7 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -1503,6 +1503,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.runnable_avg_sum;
        *period = p->se.avg.runnable_avg_period;

Leave a Reply

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