Skip to content

Commit b2250b4

Browse files
Yihao Wucasparant
authored andcommitted
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: 61e5885 ("alinux: sched: Introduce per-cgroup idle accounting") Signed-off-by: Yihao Wu <wuyihao@linux.alibaba.com> Acked-by: Shanpei Chen <shanpeic@linux.alibaba.com>
1 parent e0b245f commit b2250b4

1 file changed

Lines changed: 12 additions & 4 deletions

File tree

kernel/sched/cpuacct.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -599,14 +599,18 @@ void cgroup_idle_start(struct sched_entity *se)
599599

600600
clock = __rq_clock_broken(se->cfs_rq->rq);
601601

602+
local_irq_save(flags);
603+
602604
write_seqcount_begin(&se->idle_seqcount);
603605
__schedstat_set(se->cg_idle_start, clock);
604606
write_seqcount_end(&se->idle_seqcount);
605607

606-
spin_lock_irqsave(&se->iowait_lock, flags);
608+
spin_lock(&se->iowait_lock);
607609
if (schedstat_val(se->cg_nr_iowait))
608610
__schedstat_set(se->cg_iowait_start, clock);
609-
spin_unlock_irqrestore(&se->iowait_lock, flags);
611+
spin_unlock(&se->iowait_lock);
612+
613+
local_irq_restore(flags);
610614
}
611615

612616
void cgroup_idle_end(struct sched_entity *se)
@@ -620,19 +624,23 @@ void cgroup_idle_end(struct sched_entity *se)
620624

621625
clock = __rq_clock_broken(se->cfs_rq->rq);
622626

627+
local_irq_save(flags);
628+
623629
write_seqcount_begin(&se->idle_seqcount);
624630
idle_start = schedstat_val(se->cg_idle_start);
625631
__schedstat_add(se->cg_idle_sum, clock - idle_start);
626632
__schedstat_set(se->cg_idle_start, 0);
627633
write_seqcount_end(&se->idle_seqcount);
628634

629-
spin_lock_irqsave(&se->iowait_lock, flags);
635+
spin_lock(&se->iowait_lock);
630636
if (schedstat_val(se->cg_nr_iowait)) {
631637
iowait_start = schedstat_val(se->cg_iowait_start);
632638
__schedstat_add(se->cg_iowait_sum, clock - iowait_start);
633639
__schedstat_set(se->cg_iowait_start, 0);
634640
}
635-
spin_unlock_irqrestore(&se->iowait_lock, flags);
641+
spin_unlock(&se->iowait_lock);
642+
643+
local_irq_restore(flags);
636644
}
637645

638646
void cpuacct_cpuset_changed(struct cgroup *cgrp, struct cpumask *deleted,

0 commit comments

Comments
 (0)