Hi!
From: Jia-Ju Bai baijiaju1990@gmail.com
[ Upstream commit e36eaf94be8f7bc4e686246eed3cf92d845e2ef8 ]
The driver may sleep while holding a spinlock.
True.
But you can't fix the bug by simply removing the locking, as now nothing prevents grgpio_irq_unmap() from running while grgpio_irq_map() is proceeding.
grgpio_irq_map() lirq->irq = irq; (drops the lock)
grgpio_irq_unmap() (gets the lock) if (lirq->irq == irq) { ... (proceeds to work with half-initialized structure)
Best regards, Pavel
index 60a1556c570a4..c1be299e5567b 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -258,17 +258,16 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, lirq->irq = irq; uirq = &priv->uirqs[lirq->index]; if (uirq->refcnt == 0) {
ret = request_irq(uirq->uirq, grgpio_irq_handler, 0, dev_name(priv->dev), priv); if (ret) { dev_err(priv->dev, "Could not request underlying irq %d\n", uirq->uirq);spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);
}return ret;
} uirq->refcnt++;spin_lock_irqsave(&priv->gc.bgpio_lock, flags);
@@ -314,8 +313,11 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) if (index >= 0) { uirq = &priv->uirqs[lirq->index]; uirq->refcnt--;
if (uirq->refcnt == 0)
if (uirq->refcnt == 0) {
spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); free_irq(uirq->uirq, priv);
return;
}}
spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags);