eni_int() schedules eni_dev->task, but eni_remove_one() frees the device state without unregistering the IRQ or draining the tasklet. An interrupt during device unbind or hot unplug can therefore leave work that runs after eni_dev has been freed. Mask device interrupts, free the IRQ, and kill the tasklet before releasing its resources. Apply the same ordering to the initialization error path after the tasklet has been initialized. Fixes: 126a3fd251b2 ("eni: fix driver remove function and driver probe error path.") Signed-off-by: Jiale Yao --- drivers/atm/eni.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 3011cf1a84a9..44e6b3ceaf11 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -1881,7 +1881,11 @@ static int eni_start(struct atm_dev *dev) return 0; free_list: + eni_out(0, MID_IE); + free_irq(eni_dev->irq, dev); + tasklet_kill(&eni_dev->task); kfree(eni_dev->free_list); + goto out; free_irq: free_irq(eni_dev->irq, dev); @@ -2287,13 +2291,16 @@ MODULE_DEVICE_TABLE(pci,eni_pci_tbl); static void eni_remove_one(struct pci_dev *pdev) { struct atm_dev *dev = pci_get_drvdata(pdev); - struct eni_dev *ed = ENI_DEV(dev); - struct eni_zero *zero = &ed->zero; + struct eni_dev *eni_dev = ENI_DEV(dev); + struct eni_zero *zero = &eni_dev->zero; + eni_out(0, MID_IE); + free_irq(eni_dev->irq, dev); + tasklet_kill(&eni_dev->task); eni_do_release(dev); atm_dev_deregister(dev); dma_free_coherent(&pdev->dev, ENI_ZEROES_SIZE, zero->addr, zero->dma); - kfree(ed); + kfree(eni_dev); pci_disable_device(pdev); } -- 2.34.1