From: Xin Xiong xiongx18@fudan.edu.cn
[ Upstream commit fecbd4a317c95d73c849648c406bcf1b6a0ec1cf ]
The reference counting issue happens in several error handling paths on a refcounted object "nc->dmac". In these paths, the function simply returns the error code, forgetting to balance the reference count of "nc->dmac", increased earlier by dma_request_channel(), which may cause refcount leaks.
Fix it by decrementing the refcount of specific object in those error paths.
Fixes: f88fc122cc34 ("mtd: nand: Cleanup/rework the atmel_nand driver") Co-developed-by: Xiyu Yang xiyuyang19@fudan.edu.cn Signed-off-by: Xiyu Yang xiyuyang19@fudan.edu.cn Co-developed-by: Xin Tan tanxin.ctf@gmail.com Signed-off-by: Xin Tan tanxin.ctf@gmail.com Signed-off-by: Xin Xiong xiongx18@fudan.edu.cn Reviewed-by: Claudiu Beznea claudiu.beznea@microchip.com Signed-off-by: Miquel Raynal miquel.raynal@bootlin.com Link: https://lore.kernel.org/linux-mtd/20220304085330.3610-1-xiongx18@fudan.edu.c... Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/mtd/nand/raw/atmel/nand-controller.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index 788762930487..b2ffd22fec31 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1984,13 +1984,15 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, nc->mck = of_clk_get(dev->parent->of_node, 0); if (IS_ERR(nc->mck)) { dev_err(dev, "Failed to retrieve MCK clk\n"); - return PTR_ERR(nc->mck); + ret = PTR_ERR(nc->mck); + goto out_release_dma; }
np = of_parse_phandle(dev->parent->of_node, "atmel,smc", 0); if (!np) { dev_err(dev, "Missing or invalid atmel,smc property\n"); - return -EINVAL; + ret = -EINVAL; + goto out_release_dma; }
nc->smc = syscon_node_to_regmap(np); @@ -1998,10 +2000,16 @@ static int atmel_nand_controller_init(struct atmel_nand_controller *nc, if (IS_ERR(nc->smc)) { ret = PTR_ERR(nc->smc); dev_err(dev, "Could not get SMC regmap (err = %d)\n", ret); - return ret; + goto out_release_dma; }
return 0; + +out_release_dma: + if (nc->dmac) + dma_release_channel(nc->dmac); + + return ret; }
static int