[[PATCH staging] 3/7] staging: wfx: fix init/remove vs IRQ race
Michał Mirosław
mirq-linux at rere.qmqm.pl
Tue Feb 11 08:46:54 UTC 2020
Move interrupt request and free so to avoid following WARN on probe
and possible use-after-free on remove.
WARNING: CPU: 0 PID: 827 at drivers/staging/wfx/bus_spi.c:142 wfx_spi_irq_handler+0x5c/0x64 [wfx]
race condition in driver init/deinit
Cc: stable at vger.kernel.org
Signed-off-by: Michał Mirosław <mirq-linux at rere.qmqm.pl>
---
drivers/staging/wfx/bus_sdio.c | 16 ++++++++--------
drivers/staging/wfx/bus_spi.c | 16 +++++++++-------
2 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c
index 29688b324b33..2bfaf61e8f62 100644
--- a/drivers/staging/wfx/bus_sdio.c
+++ b/drivers/staging/wfx/bus_sdio.c
@@ -200,16 +200,16 @@ static int wfx_sdio_probe(struct sdio_func *func,
if (ret)
goto err0;
- ret = wfx_sdio_irq_subscribe(bus);
- if (ret)
- goto err1;
-
bus->core = wfx_init_common(&func->dev, &wfx_sdio_pdata,
&wfx_sdio_hwbus_ops, bus);
if (!bus->core) {
ret = -EIO;
+ goto err1;
+ }
+
+ ret = wfx_sdio_irq_subscribe(bus);
+ if (ret)
goto err2;
- }
ret = wfx_probe(bus->core);
if (ret)
@@ -218,9 +218,9 @@ static int wfx_sdio_probe(struct sdio_func *func,
return 0;
err3:
- wfx_free_common(bus->core);
+ wfx_sdio_irq_unsubscribe(bus);
err2:
- wfx_sdio_irq_unsubscribe(bus);
+ wfx_free_common(bus->core);
err1:
sdio_claim_host(func);
sdio_disable_func(func);
@@ -234,8 +234,8 @@ static void wfx_sdio_remove(struct sdio_func *func)
struct wfx_sdio_priv *bus = sdio_get_drvdata(func);
wfx_release(bus->core);
- wfx_free_common(bus->core);
wfx_sdio_irq_unsubscribe(bus);
+ wfx_free_common(bus->core);
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c
index 3ba705477ca8..2b108a9fa5ae 100644
--- a/drivers/staging/wfx/bus_spi.c
+++ b/drivers/staging/wfx/bus_spi.c
@@ -211,20 +211,22 @@ static int wfx_spi_probe(struct spi_device *func)
udelay(2000);
}
- ret = devm_request_irq(&func->dev, func->irq, wfx_spi_irq_handler,
- IRQF_TRIGGER_RISING, "wfx", bus);
- if (ret)
- return ret;
-
INIT_WORK(&bus->request_rx, wfx_spi_request_rx);
bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata,
&wfx_spi_hwbus_ops, bus);
if (!bus->core)
return -EIO;
+ ret = devm_request_irq(&func->dev, func->irq, wfx_spi_irq_handler,
+ IRQF_TRIGGER_RISING, "wfx", bus);
+ if (ret)
+ return ret;
+
ret = wfx_probe(bus->core);
- if (ret)
+ if (ret) {
+ devm_free_irq(&func->dev, func->irq, bus);
wfx_free_common(bus->core);
+ }
return ret;
}
@@ -234,11 +236,11 @@ static int wfx_spi_remove(struct spi_device *func)
struct wfx_spi_priv *bus = spi_get_drvdata(func);
wfx_release(bus->core);
- wfx_free_common(bus->core);
// A few IRQ will be sent during device release. Hopefully, no IRQ
// should happen after wdev/wvif are released.
devm_free_irq(&func->dev, func->irq, bus);
flush_work(&bus->request_rx);
+ wfx_free_common(bus->core);
return 0;
}
--
2.20.1
More information about the devel
mailing list