Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751645AbbFNLAW (ORCPT ); Sun, 14 Jun 2015 07:00:22 -0400 Received: from mail-pd0-f169.google.com ([209.85.192.169]:34528 "EHLO mail-pd0-f169.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750845AbbFNLAQ (ORCPT ); Sun, 14 Jun 2015 07:00:16 -0400 From: Takeshi Yoshimura To: Daniel Lezcano , Thomas Gleixner Cc: linux-kernel@vger.kernel.org, Takeshi Yoshimura Subject: [PATCH 1/1] clocksource: sh_mtu2: Fix irq leaks when sh_mtu2_setup() fails Date: Sun, 14 Jun 2015 19:57:07 +0900 Message-Id: <1434279427-6775-1-git-send-email-yos@sslab.ics.keio.ac.jp> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3559 Lines: 122 My static checker detected irq leaks in sh_mtu2_setup(). The problem happens when the first request_irq() succeeds but the later ones fail. This situation also results that the clockevent for the first channel is registered although the driver fails. So I introduce sh_mtu2_setup_channels() to ensure the consistency of all the clockevent and irqs even if the error occurs. Signed-off-by: Takeshi Yoshimura --- drivers/clocksource/sh_mtu2.c | 65 ++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 3d88698..5ddc433 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -344,38 +344,54 @@ static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name) return 0; } -static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, unsigned int index, - struct sh_mtu2_device *mtu) +static int sh_mtu2_setup_channels(struct sh_mtu2_device *mtu) { static const unsigned int channel_offsets[] = { 0x300, 0x380, 0x000, }; char name[6]; - int irq; + int irq[3]; int ret; + int i; - ch->mtu = mtu; - - sprintf(name, "tgi%ua", index); - irq = platform_get_irq_byname(mtu->pdev, name); - if (irq < 0) { - /* Skip channels with no declared interrupt. */ - return 0; + for (i = 0; i < mtu->num_channels; ++i) { + struct sh_mtu2_channel *ch = &mtu->channels[i]; + + ch->mtu = mtu; + sprintf(name, "tgi%ua", i); + irq[i] = platform_get_irq_byname(mtu->pdev, name); + if (irq[i] < 0) { + /* Skip channels with no declared interrupt. */ + continue; + } + + ret = request_irq(irq[i], sh_mtu2_interrupt, + IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, + dev_name(&ch->mtu->pdev->dev), ch); + if (ret) { + dev_err(&ch->mtu->pdev->dev, "ch%u: failed to request irq %d\n", + i, irq[i]); + goto err; + } } - ret = request_irq(irq, sh_mtu2_interrupt, - IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, - dev_name(&ch->mtu->pdev->dev), ch); - if (ret) { - dev_err(&ch->mtu->pdev->dev, "ch%u: failed to request irq %d\n", - index, irq); - return ret; + for (i = 0; i < mtu->num_channels; ++i) { + struct sh_mtu2_channel *ch = &mtu->channels[i]; + + ch->base = mtu->mapbase + channel_offsets[i]; + ch->index = i; + sh_mtu2_register(ch, dev_name(&mtu->pdev->dev)); } - ch->base = mtu->mapbase + channel_offsets[index]; - ch->index = index; + return 0; - return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev)); +err: + --i; + for (; i >= 0; --i) { + if (irq[i] >= 0) + free_irq(irq[i], &mtu->channels[i]); + } + return ret; } static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu) @@ -398,7 +414,6 @@ static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu) static int sh_mtu2_setup(struct sh_mtu2_device *mtu, struct platform_device *pdev) { - unsigned int i; int ret; mtu->pdev = pdev; @@ -433,11 +448,9 @@ static int sh_mtu2_setup(struct sh_mtu2_device *mtu, goto err_unmap; } - for (i = 0; i < mtu->num_channels; ++i) { - ret = sh_mtu2_setup_channel(&mtu->channels[i], i, mtu); - if (ret < 0) - goto err_unmap; - } + ret = sh_mtu2_setup_channels(mtu); + if (ret < 0) + goto err_unmap; platform_set_drvdata(pdev, mtu); -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/