From patchwork Mon May 25 14:53:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomeu Vizoso X-Patchwork-Id: 6475031 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id ED9DF9F1CC for ; Mon, 25 May 2015 15:01:26 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 40043203B6 for ; Mon, 25 May 2015 15:01:23 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3ABC32012E for ; Mon, 25 May 2015 15:01:22 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Ywtpx-0004fY-Kp; Mon, 25 May 2015 14:58:41 +0000 Received: from mail-wi0-x236.google.com ([2a00:1450:400c:c05::236]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Ywtpg-0004YF-MK for linux-arm-kernel@lists.infradead.org; Mon, 25 May 2015 14:58:29 +0000 Received: by wichy4 with SMTP id hy4so51356335wic.1 for ; Mon, 25 May 2015 07:58:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=uBcHJbMZkwS9nR5wQ/hrSX0jWLBPMUlXe2KM5G4GuvY=; b=GlGH/0IdGY/EqxrW7OgjKuUuP7Sn3WyIJ98cQrUJlZL+uLO3hErBisLgkmpLrUE4h6 61r23Kb68EvzWHH1e9uMXW8QzcfKulpU4f50TEmavzV+tawEYbPYtysATzT1u+zP8PN/ NS1L+q86XHj9dhyPRE+PCUl2CZxkApD7bHOdvDL3sAZMZ0Rp2xnfay5/y5gkNkdpX0jo /i+xICg5YWyQK8eFpsiifAuDUk7Po+5VcAQyTteJNfZp9xylyvv1ebEPFodrZ7DiBqyI B9jqZ7NmBK/G/wITR6vZnHaL7oHR29pgtRVjOc1WSd0bogW1FGFoQjgq3emPJmp5OCkr URBQ== X-Received: by 10.194.57.11 with SMTP id e11mr38521829wjq.19.1432565881901; Mon, 25 May 2015 07:58:01 -0700 (PDT) Received: from cizrna.lan ([109.72.12.80]) by mx.google.com with ESMTPSA id ez19sm12258917wid.19.2015.05.25.07.57.59 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 25 May 2015 07:58:01 -0700 (PDT) From: Tomeu Vizoso To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 01/21] regulator: core: Reduce critical area in _regulator_get Date: Mon, 25 May 2015 16:53:05 +0200 Message-Id: <1432565608-26036-2-git-send-email-tomeu.vizoso@collabora.com> X-Mailer: git-send-email 2.4.1 In-Reply-To: <1432565608-26036-1-git-send-email-tomeu.vizoso@collabora.com> References: <1432565608-26036-1-git-send-email-tomeu.vizoso@collabora.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150525_075825_032213_E738F471 X-CRM114-Status: GOOD ( 15.27 ) X-Spam-Score: -0.7 (/) Cc: Mark Rutland , Tomeu Vizoso , Mark Brown , Dmitry Torokhov , Liam Girdwood , Rob Herring , linux-kernel@vger.kernel.org, =?UTF-8?q?St=C3=A9phane=20Marchesin?= , Thierry Reding , Grant Likely , Alexander Holler X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP ...by moving the locking to regulator_dev_lookup. In _regulator_get() the regulator_list_mutex mutex is held for most of the function, but is only strictly needed to protect the list lookups. This change would be useful if for example regulator devices could be registered on demand when a driver requests them. regulator_register() could end up being called from within _regulator_get while the lock on regulator_list_mutex is being held, causing a deadlock. This backtrace illustrates the situation described above: (regulator_register) from [] (devm_regulator_register+0x48/0x84) (devm_regulator_register) from [] (reg_fixed_voltage_probe+0x214/0x35c) (reg_fixed_voltage_probe) from [] (platform_drv_probe+0x54/0xbc) (platform_drv_probe) from [] (driver_probe_device+0x184/0x2c4) (driver_probe_device) from [] (__device_attach+0x50/0x54) (__device_attach) from [] (bus_for_each_drv+0x70/0xa4) (bus_for_each_drv) from [] (device_attach+0x90/0xa4) (device_attach) from [] (bus_probe_device+0x94/0xb8) (bus_probe_device) from [] (device_add+0x384/0x580) (device_add) from [] (of_device_add+0x44/0x4c) (of_device_add) from [] (of_platform_device_create_pdata+0x88/0xbc) (of_platform_device_create_pdata) from [] (of_platform_bus_create+0xec/0x30c) (of_platform_bus_create) from [] (of_platform_bus_create+0x148/0x30c) (of_platform_bus_create) from [] (of_platform_device_ensure+0xbc/0xe0) (of_platform_device_ensure) from [] (regulator_dev_lookup+0x80/0x1e8) (regulator_dev_lookup) from [] (_regulator_get+0x8c/0x26c) (_regulator_get) from [] (regulator_get+0x20/0x24) (regulator_get) from [] (_devm_regulator_get+0xa4/0xc8) (_devm_regulator_get) from [] (devm_regulator_get+0x1c/0x20) (devm_regulator_get) from [] (tegra_hdmi_probe+0xe0/0x278) (tegra_hdmi_probe) from [] (platform_drv_probe+0x54/0xbc) Signed-off-by: Tomeu Vizoso --- drivers/regulator/core.c | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 443eaab..50f4404 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1286,10 +1286,14 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, if (dev && dev->of_node) { node = of_get_regulator(dev, supply); if (node) { + mutex_lock(®ulator_list_mutex); list_for_each_entry(r, ®ulator_list, list) if (r->dev.parent && - node == r->dev.of_node) + node == r->dev.of_node) { + mutex_unlock(®ulator_list_mutex); return r; + } + mutex_unlock(®ulator_list_mutex); *ret = -EPROBE_DEFER; return NULL; } else { @@ -1307,9 +1311,13 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, if (dev) devname = dev_name(dev); + mutex_lock(®ulator_list_mutex); list_for_each_entry(r, ®ulator_list, list) - if (strcmp(rdev_get_name(r), supply) == 0) + if (strcmp(rdev_get_name(r), supply) == 0) { + mutex_unlock(®ulator_list_mutex); return r; + } + mutex_unlock(®ulator_list_mutex); list_for_each_entry(map, ®ulator_map_list, list) { /* If the mapping has a device set up it must match */ @@ -1395,8 +1403,6 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, else ret = -EPROBE_DEFER; - mutex_lock(®ulator_list_mutex); - rdev = regulator_dev_lookup(dev, id, &ret); if (rdev) goto found; @@ -1408,7 +1414,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, * succeed, so, quit with appropriate error value */ if (ret && ret != -ENODEV) - goto out; + return regulator; if (!devname) devname = "deviceless"; @@ -1428,34 +1434,26 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, dev_warn(dev, "dummy supplies not allowed\n"); } - mutex_unlock(®ulator_list_mutex); return regulator; found: - if (rdev->exclusive) { - regulator = ERR_PTR(-EPERM); - goto out; - } + if (rdev->exclusive) + return ERR_PTR(-EPERM); - if (exclusive && rdev->open_count) { - regulator = ERR_PTR(-EBUSY); - goto out; - } + if (exclusive && rdev->open_count) + return ERR_PTR(-EBUSY); ret = regulator_resolve_supply(rdev); - if (ret < 0) { - regulator = ERR_PTR(ret); - goto out; - } + if (ret < 0) + return ERR_PTR(ret); if (!try_module_get(rdev->owner)) - goto out; + return regulator; regulator = create_regulator(rdev, dev, id); if (regulator == NULL) { - regulator = ERR_PTR(-ENOMEM); module_put(rdev->owner); - goto out; + return ERR_PTR(-ENOMEM); } rdev->open_count++; @@ -1469,9 +1467,6 @@ found: rdev->use_count = 0; } -out: - mutex_unlock(®ulator_list_mutex); - return regulator; }