From b2250b442fa9758dbf4d9318a3ad20f204959e0a Mon Sep 17 00:00:00 2001 From: Yihao Wu Date: Thu, 20 Aug 2020 16:18:15 +0800 Subject: [PATCH] alinux: sched: Fix per-cgroup idle accounting deadlock fix #29692432 seqcount assumes that writers are already exclusive, so it saves extra locking. However this critial section protected by idle_seqcount can be entered twice if an interrupt tries to wake up a task on this cpu. Once race caused by interrupt is avoided, writers are exclusive. So seqlock is unnecessary, and local_irq_save + seqcount is enough. Fixes: 61e5885959be ("alinux: sched: Introduce per-cgroup idle accounting") Signed-off-by: Yihao Wu Acked-by: Shanpei Chen --- kernel/sched/cpuacct.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index b85b01d3d17b..b037fa9a3756 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -599,14 +599,18 @@ void cgroup_idle_start(struct sched_entity *se) clock = __rq_clock_broken(se->cfs_rq->rq); + local_irq_save(flags); + write_seqcount_begin(&se->idle_seqcount); __schedstat_set(se->cg_idle_start, clock); write_seqcount_end(&se->idle_seqcount); - spin_lock_irqsave(&se->iowait_lock, flags); + spin_lock(&se->iowait_lock); if (schedstat_val(se->cg_nr_iowait)) __schedstat_set(se->cg_iowait_start, clock); - spin_unlock_irqrestore(&se->iowait_lock, flags); + spin_unlock(&se->iowait_lock); + + local_irq_restore(flags); } void cgroup_idle_end(struct sched_entity *se) @@ -620,19 +624,23 @@ void cgroup_idle_end(struct sched_entity *se) clock = __rq_clock_broken(se->cfs_rq->rq); + local_irq_save(flags); + write_seqcount_begin(&se->idle_seqcount); idle_start = schedstat_val(se->cg_idle_start); __schedstat_add(se->cg_idle_sum, clock - idle_start); __schedstat_set(se->cg_idle_start, 0); write_seqcount_end(&se->idle_seqcount); - spin_lock_irqsave(&se->iowait_lock, flags); + spin_lock(&se->iowait_lock); if (schedstat_val(se->cg_nr_iowait)) { iowait_start = schedstat_val(se->cg_iowait_start); __schedstat_add(se->cg_iowait_sum, clock - iowait_start); __schedstat_set(se->cg_iowait_start, 0); } - spin_unlock_irqrestore(&se->iowait_lock, flags); + spin_unlock(&se->iowait_lock); + + local_irq_restore(flags); } void cpuacct_cpuset_changed(struct cgroup *cgrp, struct cpumask *deleted, -- GitLab