diff options
author | Pavankumar Kondeti <pkondeti@codeaurora.org> | 2015-10-30 22:01:39 +0530 |
---|---|---|
committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:02:39 -0700 |
commit | 516b19042cd88cfd28bb053ebf33e02bc65c98ad (patch) | |
tree | 0b54f15c01b273188eff4c7a8f14d91b5bf6fe38 /kernel | |
parent | 280b8668481d732d7e2602cb719b517f23f329b7 (diff) |
sched/cputime: fix a deadlock on 32bit systems
cpu_hardirq_time and cpu_softirq_time are protected with
seqlock on 32bit systems. There is a potential deadlock
with this seqlock and rq->lock.
CPU 1 CPU0
========================== ========================
--> acquire CPU0 rq->lock --> __irq_enter()
----> task enqueue/dequeue ----> irqtime_account_irq()
------> update_rq_clock() ------> irq_time_write_begin()
--------> irq_time_read() --------> sched_account_irqtime()
(waiting for the seqlock (waiting for the CPU0 rq->lock)
held in irq_time_write_begin()
Fix this issue by dropping the seqlock before calling
sched_account_irqtime()
Change-Id: I29a33876e372f99435a57cc11eada9c8cfd59a3f
Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sched/cputime.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index ec3e99076941..930d3ce4f34e 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -50,6 +50,7 @@ void irqtime_account_irq(struct task_struct *curr) s64 delta; int cpu; u64 wallclock; + bool account = true; if (!sched_clock_irqtime) return; @@ -68,16 +69,18 @@ void irqtime_account_irq(struct task_struct *curr) * in that case, so as not to confuse scheduler with a special task * that do not consume any time, but still wants to run. */ - if (hardirq_count()) { + if (hardirq_count()) __this_cpu_add(cpu_hardirq_time, delta); - sched_account_irqtime(cpu, curr, delta, wallclock); - } else if (in_serving_softirq() && curr != this_cpu_ksoftirqd()) { + else if (in_serving_softirq() && curr != this_cpu_ksoftirqd()) __this_cpu_add(cpu_softirq_time, delta); - sched_account_irqtime(cpu, curr, delta, wallclock); - } - + else + account = false; irq_time_write_end(); + + if (account) + sched_account_irqtime(cpu, curr, delta, wallclock); + local_irq_restore(flags); } EXPORT_SYMBOL_GPL(irqtime_account_irq); |