From: Daniel Thompson <daniel.thompson@linaro.org>
To: Russell King - ARM Linux <linux@arm.linux.org.uk>,
Stephen Boyd <sboyd@codeaurora.org>,
Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>,
linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
Nicolas Pitre <nico@linaro.org>
Subject: Re: [PATCH v4] irqchip: gic: Allow gic_arch_extn hooks to call into scheduler
Date: Wed, 13 Aug 2014 15:53:43 +0100 [thread overview]
Message-ID: <53EB7BF7.1080702@linaro.org> (raw)
In-Reply-To: <20140813142257.GK30401@n2100.arm.linux.org.uk>
On 13/08/14 15:22, Russell King - ARM Linux wrote:
> On Wed, Aug 13, 2014 at 06:57:18AM -0700, Stephen Boyd wrote:
>> Commit 1a6b69b6548c (ARM: gic: add CPU migration support,
>> 2012-04-12) introduced an acquisition of the irq_controller_lock
>> in gic_raise_softirq() which can lead to a spinlock recursion if
>> the gic_arch_extn hooks call into the scheduler (via complete()
>> or wake_up(), etc.). This happens because gic_arch_extn hooks are
>> normally called with the irq_controller_lock held and calling
>> into the scheduler may cause us to call smp_send_reschedule()
>> which will grab the irq_controller_lock again. Here's an example
>> from a vendor kernel (note that the gic_arch_extn hook code here
>> isn't actually in mainline):
>
> Here's a question: why would you want to call into the scheduler from
> the gic_arch_extn code?
>
> Oh. My. God. Thomas, what have you done to the generic IRQ layer?
> This is /totally/ unsafe:
>
> void disable_irq(unsigned int irq)
> {
> if (!__disable_irq_nosync(irq))
> synchronize_irq(irq);
> }
>
> static int __disable_irq_nosync(unsigned int irq)
> {
> unsigned long flags;
> struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
irq_get_desc_buslock() results in us owning the descriptor's lock
(raw_spinlock_t).
>
> if (!desc)
> return -EINVAL;
> __disable_irq(desc, irq, false);
> irq_put_desc_busunlock(desc, flags);
> return 0;
> }
>
> void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
> {
> if (suspend) {
> if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND))
> return;
> desc->istate |= IRQS_SUSPENDED;
> }
>
> if (!desc->depth++)
> irq_disable(desc);
> }
>
> You realise that disable_irq() and enable_irq() can be called by
> concurrently by different drivers for the /same/ interrupt. For
> starters, that post-increment there is completely unprotected against
> races. Secondly, the above is completely racy against a concurrent
> enable_irq() - what if we're in disable_irq(), we've incremented
> depth, but have yet to call irq_disable(). The count now has a
> value of 1.
>
> We then preempt, and run another thread which calls enable_irq()
> on it. This results in the depth being decremented, and the IRQ
> is now enabled.
We shouldn't get that far due to the spinlock taken during the disable.
> We resume the original thread, and continue to call irq_disable(),
> resulting in the interrupt being disabled.
>
> That's not nice (the right answer is that it's strictly an unbalanced
> enable_irq(), but that's no excuse here.)
>
WARNING: multiple messages have this Message-ID (diff)
From: daniel.thompson@linaro.org (Daniel Thompson)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v4] irqchip: gic: Allow gic_arch_extn hooks to call into scheduler
Date: Wed, 13 Aug 2014 15:53:43 +0100 [thread overview]
Message-ID: <53EB7BF7.1080702@linaro.org> (raw)
In-Reply-To: <20140813142257.GK30401@n2100.arm.linux.org.uk>
On 13/08/14 15:22, Russell King - ARM Linux wrote:
> On Wed, Aug 13, 2014 at 06:57:18AM -0700, Stephen Boyd wrote:
>> Commit 1a6b69b6548c (ARM: gic: add CPU migration support,
>> 2012-04-12) introduced an acquisition of the irq_controller_lock
>> in gic_raise_softirq() which can lead to a spinlock recursion if
>> the gic_arch_extn hooks call into the scheduler (via complete()
>> or wake_up(), etc.). This happens because gic_arch_extn hooks are
>> normally called with the irq_controller_lock held and calling
>> into the scheduler may cause us to call smp_send_reschedule()
>> which will grab the irq_controller_lock again. Here's an example
>> from a vendor kernel (note that the gic_arch_extn hook code here
>> isn't actually in mainline):
>
> Here's a question: why would you want to call into the scheduler from
> the gic_arch_extn code?
>
> Oh. My. God. Thomas, what have you done to the generic IRQ layer?
> This is /totally/ unsafe:
>
> void disable_irq(unsigned int irq)
> {
> if (!__disable_irq_nosync(irq))
> synchronize_irq(irq);
> }
>
> static int __disable_irq_nosync(unsigned int irq)
> {
> unsigned long flags;
> struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL);
irq_get_desc_buslock() results in us owning the descriptor's lock
(raw_spinlock_t).
>
> if (!desc)
> return -EINVAL;
> __disable_irq(desc, irq, false);
> irq_put_desc_busunlock(desc, flags);
> return 0;
> }
>
> void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
> {
> if (suspend) {
> if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND))
> return;
> desc->istate |= IRQS_SUSPENDED;
> }
>
> if (!desc->depth++)
> irq_disable(desc);
> }
>
> You realise that disable_irq() and enable_irq() can be called by
> concurrently by different drivers for the /same/ interrupt. For
> starters, that post-increment there is completely unprotected against
> races. Secondly, the above is completely racy against a concurrent
> enable_irq() - what if we're in disable_irq(), we've incremented
> depth, but have yet to call irq_disable(). The count now has a
> value of 1.
>
> We then preempt, and run another thread which calls enable_irq()
> on it. This results in the depth being decremented, and the IRQ
> is now enabled.
We shouldn't get that far due to the spinlock taken during the disable.
> We resume the original thread, and continue to call irq_disable(),
> resulting in the interrupt being disabled.
>
> That's not nice (the right answer is that it's strictly an unbalanced
> enable_irq(), but that's no excuse here.)
>
next prev parent reply other threads:[~2014-08-13 14:53 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-13 13:57 [PATCH v4] irqchip: gic: Allow gic_arch_extn hooks to call into scheduler Stephen Boyd
2014-08-13 13:57 ` Stephen Boyd
2014-08-13 14:22 ` Russell King - ARM Linux
2014-08-13 14:22 ` Russell King - ARM Linux
2014-08-13 14:53 ` Daniel Thompson [this message]
2014-08-13 14:53 ` Daniel Thompson
2014-08-13 14:55 ` Stephen Boyd
2014-08-13 14:55 ` Stephen Boyd
2014-08-13 15:05 ` Russell King - ARM Linux
2014-08-13 15:05 ` Russell King - ARM Linux
2014-08-13 15:31 ` Stephen Boyd
2014-08-13 15:31 ` Stephen Boyd
2014-08-13 15:44 ` Nicolas Pitre
2014-08-13 15:44 ` Nicolas Pitre
2014-08-17 17:32 ` Jason Cooper
2014-08-17 17:32 ` Jason Cooper
2014-08-17 18:55 ` Russell King - ARM Linux
2014-08-17 18:55 ` Russell King - ARM Linux
2014-08-17 19:04 ` Jason Cooper
2014-08-17 19:04 ` Jason Cooper
2014-08-17 21:41 ` Russell King - ARM Linux
2014-08-17 21:41 ` Russell King - ARM Linux
2014-08-18 0:17 ` Nicolas Pitre
2014-08-18 0:17 ` Nicolas Pitre
2014-08-20 19:11 ` Stephen Boyd
2014-08-20 19:11 ` Stephen Boyd
2014-08-18 1:32 ` Jason Cooper
2014-08-18 1:32 ` Jason Cooper
2014-08-18 0:04 ` Nicolas Pitre
2014-08-18 0:04 ` Nicolas Pitre
2014-08-18 1:25 ` Jason Cooper
2014-08-18 1:25 ` Jason Cooper
2014-08-18 1:35 ` Nicolas Pitre
2014-08-18 1:35 ` Nicolas Pitre
2014-08-18 1:54 ` Jason Cooper
2014-08-18 1:54 ` Jason Cooper
2014-08-18 2:18 ` Nicolas Pitre
2014-08-18 2:18 ` Nicolas Pitre
2014-08-20 19:16 ` Stephen Boyd
2014-08-20 19:16 ` Stephen Boyd
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53EB7BF7.1080702@linaro.org \
--to=daniel.thompson@linaro.org \
--cc=jason@lakedaemon.net \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@arm.linux.org.uk \
--cc=nico@linaro.org \
--cc=sboyd@codeaurora.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.