Skip to content

Commit 34cb275

Browse files
Vitalii Demianetsgregkh
Vitalii Demianets
authored andcommitted
UIO: Fix concurrency issue
In a SMP case there was a race condition issue between uio_pdrv_genirq_irqcontrol() running on one CPU and irq handler on another CPU. Fix it by spin_locking shared resources access inside irq handler. Also: - Change disable_irq to disable_irq_nosync to avoid deadlock, because disable_irq waits for the completion of the irq handler; - Change atomic bit-manipulation routines to their non-atomic counterparts as we already are guarding the code by spinlock. Signed-off-by: Vitalii Demianets <[email protected]> Reviewed-by: Pavel Machek <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0777971 commit 34cb275

File tree

1 file changed

+13
-5
lines changed

1 file changed

+13
-5
lines changed

drivers/uio/uio_pdrv_genirq.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ struct uio_pdrv_genirq_platdata {
3737
struct platform_device *pdev;
3838
};
3939

40+
/* Bits in uio_pdrv_genirq_platdata.flags */
41+
enum {
42+
UIO_IRQ_DISABLED = 0,
43+
};
44+
4045
static int uio_pdrv_genirq_open(struct uio_info *info, struct inode *inode)
4146
{
4247
struct uio_pdrv_genirq_platdata *priv = info->priv;
@@ -63,8 +68,10 @@ static irqreturn_t uio_pdrv_genirq_handler(int irq, struct uio_info *dev_info)
6368
* remember the state so we can allow user space to enable it later.
6469
*/
6570

66-
if (!test_and_set_bit(0, &priv->flags))
71+
spin_lock(&priv->lock);
72+
if (!__test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
6773
disable_irq_nosync(irq);
74+
spin_unlock(&priv->lock);
6875

6976
return IRQ_HANDLED;
7077
}
@@ -78,16 +85,17 @@ static int uio_pdrv_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
7885
* in the interrupt controller, but keep track of the
7986
* state to prevent per-irq depth damage.
8087
*
81-
* Serialize this operation to support multiple tasks.
88+
* Serialize this operation to support multiple tasks and concurrency
89+
* with irq handler on SMP systems.
8290
*/
8391

8492
spin_lock_irqsave(&priv->lock, flags);
8593
if (irq_on) {
86-
if (test_and_clear_bit(0, &priv->flags))
94+
if (__test_and_clear_bit(UIO_IRQ_DISABLED, &priv->flags))
8795
enable_irq(dev_info->irq);
8896
} else {
89-
if (!test_and_set_bit(0, &priv->flags))
90-
disable_irq(dev_info->irq);
97+
if (!__test_and_set_bit(UIO_IRQ_DISABLED, &priv->flags))
98+
disable_irq_nosync(dev_info->irq);
9199
}
92100
spin_unlock_irqrestore(&priv->lock, flags);
93101

0 commit comments

Comments
 (0)