Re: Kernel segmentation fault unbinding eMMC on AML-S905X-CC

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Jan 09, 2019 at 10:48:50PM +0000, Elie Roudninski wrote:
...

> [  444.060161] Call trace:
> [  444.062580]  queued_spin_lock_slowpath+0x228/0x2d0
> [  444.067322]  meson_mmc_irq+0x290/0x2a0
> [  444.071032]  __free_irq+0x184/0x318
> [  444.074480]  free_irq+0x40/0x80
> [  444.077586]  devm_irq_release+0x24/0x30
> [  444.081382]  release_nodes+0x1e0/0x2e0
> [  444.085089]  devres_release_all+0x60/0x88
> [  444.089057]  device_release_driver_internal+0x1c8/0x248
> [  444.094231]  device_release_driver+0x28/0x38
> [  444.098459]  unbind_store+0xdc/0x148
> [  444.101994]  drv_attr_store+0x40/0x58
> [  444.105627]  sysfs_kf_write+0x5c/0x78
> [  444.109240]  kernfs_fop_write+0xe8/0x1e0
> [  444.113126]  __vfs_write+0x60/0x190
> [  444.116570]  vfs_write+0xac/0x1b0
> [  444.119848]  ksys_write+0x6c/0xd0
> [  444.123125]  __arm64_sys_write+0x24/0x30
> [  444.127015]  el0_svc_common+0x94/0xe8
> [  444.130629]  el0_svc_handler+0x38/0x80
> [  444.134340]  el0_svc+0x8/0xc
> [  444.137187] Code: d37c0401 910020c0 8b010041 f865d8e5 (f8256826)
> [  444.143223] ---[ end trace 62541ec2ffe020f2 ]---
> Segmentation fault

...

Here are my two cents on this.

The irq that is being freed was allocated through device management
(i.e. with devm_request_threaded_irq()). So this irq will be released
after meson_mmc_remove() completion, thus after that mmc_free_host()
has been called. Because this irq has been registered with IRQF_SHARED
and if you have CONFIG_DEBUG_SHIRQ (do you ?) the irq handler will be
called while the irq is freed.

So meson_mmc_irq could be called after mmc_free_host() has freed the
meson_host pointer causing it to dereference an invalid pointer.

So if you have CONFIG_DEBUG_SHIRQ could you please test the following
patch:

------------------------------- 8< ----------------------------------
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index c2690c1a50ff..3a9679531520 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -179,6 +179,8 @@ struct meson_host {
 	struct sd_emmc_desc *descs;
 	dma_addr_t descs_dma_addr;
 
+	int irq;
+
 	bool vqmmc_enabled;
 };
 
@@ -1231,7 +1233,7 @@ static int meson_mmc_probe(struct platform_device *pdev)
 	struct resource *res;
 	struct meson_host *host;
 	struct mmc_host *mmc;
-	int ret, irq;
+	int ret;
 
 	mmc = mmc_alloc_host(sizeof(struct meson_host), &pdev->dev);
 	if (!mmc)
@@ -1276,8 +1278,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
 		goto free_host;
 	}
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq <= 0) {
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq <= 0) {
 		dev_err(&pdev->dev, "failed to get interrupt resource.\n");
 		ret = -EINVAL;
 		goto free_host;
@@ -1331,9 +1333,8 @@ static int meson_mmc_probe(struct platform_device *pdev)
 	writel(IRQ_CRC_ERR | IRQ_TIMEOUTS | IRQ_END_OF_CHAIN,
 	       host->regs + SD_EMMC_IRQ_EN);
 
-	ret = devm_request_threaded_irq(&pdev->dev, irq, meson_mmc_irq,
-					meson_mmc_irq_thread, IRQF_SHARED,
-					NULL, host);
+	ret = request_threaded_irq(host->irq, meson_mmc_irq,
+			meson_mmc_irq_thread, IRQF_SHARED, NULL, host);
 	if (ret)
 		goto err_init_clk;
 
@@ -1387,6 +1388,7 @@ static int meson_mmc_remove(struct platform_device *pdev)
 
 	/* disable interrupts */
 	writel(0, host->regs + SD_EMMC_IRQ_EN);
+	free_irq(host->irq, host);
 
 	dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN,
 			  host->descs, host->descs_dma_addr);
------------------------------- 8< ----------------------------------

This basically freed the irq in the meson_mmc_remove() so the
meson_mmc_irq() is called before mmc_free_host().

-- 
Rémi Pommarel



[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux