delayacct_add_tsk() adds each task's statistics to the accumulated TGID statistics, but overwrites the delay maxima, minima and peak timestamps. Consequently, the last task determines these fields, and a task with no recorded delay can erase an earlier task's peak despite a nonzero total. Keep the largest maximum and its associated timestamp, and combine the minima with min_not_zero() since zero denotes an unrecorded delay. Apply this to CPU delay and the seven delay types handled by UPDATE_DELAY(). Single-task queries still start with zeroed statistics and retain the task's values. Fixes: 658eb5ab916d ("delayacct: add delay max to record delay peak") Fixes: f65c64f311ee ("delayacct: add delay min to record delay peak") Cc: stable@vger.kernel.org Signed-off-by: Hungyu Lin --- kernel/delayacct.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 479e860aff70..ea1424524654 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -12,14 +12,18 @@ #include #include #include +#include #include #define UPDATE_DELAY(type) \ do { \ - d->type##_delay_max = tsk->delays->type##_delay_max; \ - d->type##_delay_min = tsk->delays->type##_delay_min; \ - d->type##_delay_max_ts.tv_sec = tsk->delays->type##_delay_max_ts.tv_sec; \ - d->type##_delay_max_ts.tv_nsec = tsk->delays->type##_delay_max_ts.tv_nsec; \ + if (tsk->delays->type##_delay_max > d->type##_delay_max) { \ + d->type##_delay_max = tsk->delays->type##_delay_max; \ + d->type##_delay_max_ts.tv_sec = tsk->delays->type##_delay_max_ts.tv_sec; \ + d->type##_delay_max_ts.tv_nsec = tsk->delays->type##_delay_max_ts.tv_nsec; \ + } \ + d->type##_delay_min = min_not_zero(d->type##_delay_min, \ + tsk->delays->type##_delay_min); \ tmp = d->type##_delay_total + tsk->delays->type##_delay; \ d->type##_delay_total = (tmp < d->type##_delay_total) ? 0 : tmp; \ d->type##_count += tsk->delays->type##_count; \ @@ -174,10 +178,13 @@ int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) d->cpu_count += t1; - d->cpu_delay_max = tsk->sched_info.max_run_delay; - d->cpu_delay_min = tsk->sched_info.min_run_delay; - d->cpu_delay_max_ts.tv_sec = tsk->sched_info.max_run_delay_ts.tv_sec; - d->cpu_delay_max_ts.tv_nsec = tsk->sched_info.max_run_delay_ts.tv_nsec; + if (tsk->sched_info.max_run_delay > d->cpu_delay_max) { + d->cpu_delay_max = tsk->sched_info.max_run_delay; + d->cpu_delay_max_ts.tv_sec = tsk->sched_info.max_run_delay_ts.tv_sec; + d->cpu_delay_max_ts.tv_nsec = tsk->sched_info.max_run_delay_ts.tv_nsec; + } + d->cpu_delay_min = min_not_zero(d->cpu_delay_min, + tsk->sched_info.min_run_delay); tmp = (s64)d->cpu_delay_total + t2; d->cpu_delay_total = (tmp < (s64)d->cpu_delay_total) ? 0 : tmp; tmp = (s64)d->cpu_run_virtual_total + t3; -- 2.43.0