Message ID | 1667983694-15040-3-git-send-email-wangyufen@huawei.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp216387wru; Wed, 9 Nov 2022 00:30:20 -0800 (PST) X-Google-Smtp-Source: AMsMyM7Oi6exK0fWsrDZcW/0U7EnUsG+8OQKBUis/dwNU66i/T89XW1keaQhYdQD69nVFn+siUam X-Received: by 2002:a05:6a00:e0f:b0:56d:6e51:3060 with SMTP id bq15-20020a056a000e0f00b0056d6e513060mr52297210pfb.55.1667982620144; Wed, 09 Nov 2022 00:30:20 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1667982620; cv=none; d=google.com; s=arc-20160816; b=Vj4V7Try06mb0XAfGfAJFbiBfVPdBCuf9gOkC+Zk9ytQcRJUGDjXCX190MiveDKO0f MFZLRe79JdOqrag2o7xC57DDG12WIXkdbs4XXVfW4qGPQDa7x6H+sDJsFjfTIbXXvOiG DwgKQb85mnBSQZZE9NotKUWHdMKJ5H2md1hS8gauRSoma8eJS9CODIKqrKoS+R8nyJ8Q XZS7ABhxkiZDBdCih1HpHsdRbp4j9PpIbeUOElZEzkDgbsWffRRLTf97UEMk+PdHG1aN USGl9/ZFsISi6l/PFldWIR2UckDoHBIfxN5YOemL1XqJSm+q9E/Ty0k9vE2xAEksRy4U FnFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from; bh=Kb5BkBYy8ci2bJIJMiiTYKBxgHF2bz6yyYBdoWjP8E4=; b=vLeGPJ5Uz8SlVv8Em3kvK9bXh6X03XVHTt9fBIN9ARwJ3KpDkvz5Rxw4zBm0KKz3qE MxtmF54QLDd4M9RQHkKnkgAoj7EJG0X1/0xRe2Qksypwk7b/kqkzzc05miG+7GYBsTXg 2vEqNeKNumFSa8oTzOwYH0QQ94XeYJDyCwp9SFHfzISE+cpT9CRX8TuK4T3iQY9vzvJk 9iG8uyA6cv2qV0ljxqputAuBE1CaVjp7qM39u7p1WNJ/HTOx5y2h8vBogqyvFSQ6XpEP MsyW+F0BbyoIBcrLO0xYMDlq1Y60z83E+D4cM+iBWKAJUwzjadtPArzBq3cKaapGOH4H CxDg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=huawei.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id x14-20020a63170e000000b004615836deeasi17214540pgl.860.2022.11.09.00.30.06; Wed, 09 Nov 2022 00:30:20 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=huawei.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229930AbiKII2F (ORCPT <rfc822;dexuan.linux@gmail.com> + 99 others); Wed, 9 Nov 2022 03:28:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40108 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229825AbiKII1w (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Wed, 9 Nov 2022 03:27:52 -0500 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 176FE13D5E; Wed, 9 Nov 2022 00:27:51 -0800 (PST) Received: from canpemm500010.china.huawei.com (unknown [172.30.72.53]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4N6dPh2thDzmVjq; Wed, 9 Nov 2022 16:27:36 +0800 (CST) Received: from localhost.localdomain (10.175.112.70) by canpemm500010.china.huawei.com (7.192.105.118) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.31; Wed, 9 Nov 2022 16:27:49 +0800 From: Wang Yufen <wangyufen@huawei.com> To: <linux-leds@vger.kernel.org>, <linux-kernel@vger.kernel.org> CC: <pavel@ucw.cz>, Wang Yufen <wangyufen@huawei.com>, Oleh Kravchenko <oleg@kaa.org.ua> Subject: [PATCH 02/13] leds: el15203000: Fix devm vs. non-devm ordering Date: Wed, 9 Nov 2022 16:48:03 +0800 Message-ID: <1667983694-15040-3-git-send-email-wangyufen@huawei.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1667983694-15040-1-git-send-email-wangyufen@huawei.com> References: <1667983694-15040-1-git-send-email-wangyufen@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.175.112.70] X-ClientProxiedBy: dggems701-chm.china.huawei.com (10.3.19.178) To canpemm500010.china.huawei.com (7.192.105.118) X-CFilter-Loop: Reflected X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_MED, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1749006543650109135?= X-GMAIL-MSGID: =?utf-8?q?1749006543650109135?= |
Series |
leds: Fix devm vs. non-devm ordering
|
|
Commit Message
wangyufen
Nov. 9, 2022, 8:48 a.m. UTC
When non-devm resources are allocated they mustn't be followed by devm
allocations, otherwise it will break the tear down ordering and might
lead to crashes or other bugs during ->remove() stage. Fix this by
wrapping mutex_destroy() call with devm_add_action_or_reset().
Fixes: fc19967bcb8f ("leds: add LED driver for EL15203000 board")
Signed-off-by: Wang Yufen <wangyufen@huawei.com>
Cc: Oleh Kravchenko <oleg@kaa.org.ua>
---
drivers/leds/leds-el15203000.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
Comments
Hello all! > 9 лист. 2022 р. о 10:48 Wang Yufen <wangyufen@huawei.com> написав(ла): > > When non-devm resources are allocated they mustn't be followed by devm > allocations, otherwise it will break the tear down ordering and might > lead to crashes or other bugs during ->remove() stage. Fix this by > wrapping mutex_destroy() call with devm_add_action_or_reset(). > > Fixes: fc19967bcb8f ("leds: add LED driver for EL15203000 board") > Signed-off-by: Wang Yufen <wangyufen@huawei.com> > Cc: Oleh Kravchenko <oleg@kaa.org.ua> > --- > drivers/leds/leds-el15203000.c | 18 +++++++++++------- > 1 file changed, 11 insertions(+), 7 deletions(-) > > diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c > index 7e7b617..9be934e 100644 > --- a/drivers/leds/leds-el15203000.c > +++ b/drivers/leds/leds-el15203000.c > @@ -287,10 +287,16 @@ static int el15203000_probe_dt(struct el15203000 *priv) > return ret; > } > > +static void el15203000_mutex_destroy(void *lock) > +{ > + mutex_destroy(lock); > +} > + > static int el15203000_probe(struct spi_device *spi) > { > struct el15203000 *priv; > size_t count; > + int ret; > > count = device_get_child_node_count(&spi->dev); > if (!count) { > @@ -312,15 +318,14 @@ static int el15203000_probe(struct spi_device *spi) > > spi_set_drvdata(spi, priv); > > + ret = devm_add_action_or_reset(&spi->dev, el15203000_mutex_destroy, > + &priv->lock); > + if (ret) > + return ret; > + > return el15203000_probe_dt(priv); > } > > -static void el15203000_remove(struct spi_device *spi) Is remove() callback from struct spi_driver deprecated? > -{ > - struct el15203000 *priv = spi_get_drvdata(spi); > - > - mutex_destroy(&priv->lock); > -} > > static const struct of_device_id el15203000_dt_ids[] = { > { .compatible = "crane,el15203000", }, > @@ -331,7 +336,6 @@ static void el15203000_remove(struct spi_device *spi) > > static struct spi_driver el15203000_driver = { > .probe = el15203000_probe, > - .remove = el15203000_remove, > .driver = { > .name = KBUILD_MODNAME, > .of_match_table = el15203000_dt_ids, > -- > 1.8.3.1 >
在 2022/11/9 17:39, Oleh Kravchenko 写道: > Hello all! > >> 9 лист. 2022 р. о 10:48 Wang Yufen <wangyufen@huawei.com> написав(ла): >> >> When non-devm resources are allocated they mustn't be followed by devm >> allocations, otherwise it will break the tear down ordering and might >> lead to crashes or other bugs during ->remove() stage. Fix this by >> wrapping mutex_destroy() call with devm_add_action_or_reset(). >> >> Fixes: fc19967bcb8f ("leds: add LED driver for EL15203000 board") >> Signed-off-by: Wang Yufen <wangyufen@huawei.com> >> Cc: Oleh Kravchenko <oleg@kaa.org.ua> >> --- >> drivers/leds/leds-el15203000.c | 18 +++++++++++------- >> 1 file changed, 11 insertions(+), 7 deletions(-) >> >> diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c >> index 7e7b617..9be934e 100644 >> --- a/drivers/leds/leds-el15203000.c >> +++ b/drivers/leds/leds-el15203000.c >> @@ -287,10 +287,16 @@ static int el15203000_probe_dt(struct el15203000 *priv) >> return ret; >> } >> >> +static void el15203000_mutex_destroy(void *lock) >> +{ >> + mutex_destroy(lock); >> +} >> + >> static int el15203000_probe(struct spi_device *spi) >> { >> struct el15203000 *priv; >> size_t count; >> + int ret; >> >> count = device_get_child_node_count(&spi->dev); >> if (!count) { >> @@ -312,15 +318,14 @@ static int el15203000_probe(struct spi_device *spi) >> >> spi_set_drvdata(spi, priv); >> >> + ret = devm_add_action_or_reset(&spi->dev, el15203000_mutex_destroy, >> + &priv->lock); >> + if (ret) >> + return ret; >> + >> return el15203000_probe_dt(priv); >> } >> >> -static void el15203000_remove(struct spi_device *spi) > Is remove() callback from struct spi_driver deprecated? It is not that remove() callback is deprecated, it's that after wrapping mutex_destroy() call with devm_add_action_or_reset(), remove() callback is unnecessary here. > >> -{ >> - struct el15203000 *priv = spi_get_drvdata(spi); >> - >> - mutex_destroy(&priv->lock); >> -} >> >> static const struct of_device_id el15203000_dt_ids[] = { >> { .compatible = "crane,el15203000", }, >> @@ -331,7 +336,6 @@ static void el15203000_remove(struct spi_device *spi) >> >> static struct spi_driver el15203000_driver = { >> .probe = el15203000_probe, >> - .remove = el15203000_remove, >> .driver = { >> .name = KBUILD_MODNAME, >> .of_match_table = el15203000_dt_ids, >> -- >> 1.8.3.1 >> >
> 9 лист. 2022 р. о 12:25 wangyufen <wangyufen@huawei.com> написав(ла): > > > 在 2022/11/9 17:39, Oleh Kravchenko 写道: >> Hello all! >> >>> 9 лист. 2022 р. о 10:48 Wang Yufen <wangyufen@huawei.com> написав(ла): >>> >>> return el15203000_probe_dt(priv); >>> } >>> >>> -static void el15203000_remove(struct spi_device *spi) >> Is remove() callback from struct spi_driver deprecated? > > It is not that remove() callback is deprecated, > it's that after wrapping mutex_destroy() call with devm_add_action_or_reset(), > remove() callback is unnecessary here. When remove() is called, the memory allocated by devm_*() is valid. So what you try to fix here? > >> >>> -{ >>> - struct el15203000 *priv = spi_get_drvdata(spi); >>> - >>> - mutex_destroy(&priv->lock); >>> -} >>> >>> static const struct of_device_id el15203000_dt_ids[] = { >>> { .compatible = "crane,el15203000", }, >>> @@ -331,7 +336,6 @@ static void el15203000_remove(struct spi_device *spi) >>> >>> static struct spi_driver el15203000_driver = { >>> .probe = el15203000_probe, >>> - .remove = el15203000_remove, >>> .driver = { >>> .name = KBUILD_MODNAME, >>> .of_match_table = el15203000_dt_ids, >>> -- >>> 1.8.3.1 >>> >>
Hello Wang, > 11 лист. 2022 р. о 11:21 wangyufen <wangyufen@huawei.com> написав(ла): > > > 在 2022/11/9 18:43, Oleh Kravchenko 写道: >> >> >>> 9 лист. 2022 р. о 12:25 wangyufen <wangyufen@huawei.com> написав(ла): >>> >>> >>> 在 2022/11/9 17:39, Oleh Kravchenko 写道: >>> >>>>> -static void el15203000_remove(struct spi_device *spi) >>>>> >>>> Is remove() callback from struct spi_driver deprecated? >>>> >>> It is not that remove() callback is deprecated, >>> it's that after wrapping mutex_destroy() call with devm_add_action_or_reset(), >>> remove() callback is unnecessary here. >>> >> When remove() is called, the memory allocated by devm_*() is valid. >> So what you try to fix here? > > Fix the &priv->lock used after destroy, for details, please see patch #0 > LKML: Wang Yufen: [PATCH 00/13] leds: Fix devm vs. non-devm ordering It doesn’t make any sense for me. You saying that remove() called before devm_* allocation if it true then set_brightness_delayed() will crash the system in anyway. LED device has a parent SPI device; LED device can’t exist without SPI device. So deallocation order should be next: 1. LED device devm_*() 2. SPI device remove()
Hi Oleh, On 2022/11/11 18:39, Oleh Kravchenko wrote: > Hello Wang, > >> 11 лист. 2022 р. о 11:21 wangyufen <wangyufen@huawei.com> написав(ла): >> >> >> 在 2022/11/9 18:43, Oleh Kravchenko 写道: >>> >>> >>>> 9 лист. 2022 р. о 12:25 wangyufen <wangyufen@huawei.com> написав(ла): >>>> >>>> >>>> 在 2022/11/9 17:39, Oleh Kravchenko 写道: >>>> >>>>>> -static void el15203000_remove(struct spi_device *spi) >>>>>> >>>>> Is remove() callback from struct spi_driver deprecated? >>>>> >>>> It is not that remove() callback is deprecated, >>>> it's that after wrapping mutex_destroy() call with devm_add_action_or_reset(), >>>> remove() callback is unnecessary here. >>>> >>> When remove() is called, the memory allocated by devm_*() is valid. >>> So what you try to fix here? >> >> Fix the &priv->lock used after destroy, for details, please see patch #0 >> LKML: Wang Yufen: [PATCH 00/13] leds: Fix devm vs. non-devm ordering > > It doesn’t make any sense for me. > You saying that remove() called before devm_* allocation > if it true then set_brightness_delayed() will crash the system in anyway. > > LED device has a parent SPI device; LED device can’t exist without SPI device. > > So deallocation order should be next: > 1. LED device devm_*() > 2. SPI device remove() The allocation order is as follows: el15203000_probe() mutex_init(&priv->lock); el15203000_probe_dt(priv) device_for_each_child_node(priv->dev, child) { ... led->ldev.brightness_set_blocking = el15203000_set_blocking; ... devm_led_classdev_register_ext(priv->dev, &led->ldev, &init_data); dr = devres_alloc(devm_led_classdev_release, sizeof(*dr), GFP_KERNEL); <-- dr->node.release = devm_led_classdev_release() ... devres_add(parent, dr); <-- add dr->node to &priv->dev->devres_head And the full deallocation order should be this: 1. SPI device .remove callback 2. LED device devm_*() 3. SPI device deallocation spi_unregister_device() device_del() bus_remove_device() device_release_driver_internal() __device_release_driver() ... device_remove() spi_remove() <-- call el15203000_remove() here, mutex_destroy(&priv->lock), lock destroy ... device_unbind_cleanup() devres_release_all() release_nodes() <-- traverse spi->dev->devres_head list and call dr->node.release in sequence. devm_led_classdev_release() led_classdev_unregister() <-- flush set_brightness_work here, before the work flush, set_brightness_work may be sched. <-- that is el15203000_set_blocking()..-> mutex_lock(&led->priv->lock) is called, <-- this leads to the priv->lock use after destroy. put_device(&spi->dev) <-- spi device is deallocation in here Regards, Wei Yongjun
在 2022/11/15 10:06, Wei Yongjun 写道: > Hi Oleh, > > On 2022/11/11 18:39, Oleh Kravchenko wrote: >> Hello Wang, >> >>> 11 лист. 2022 р. о 11:21 wangyufen <wangyufen@huawei.com> написав(ла): >>> >>> >>> 在 2022/11/9 18:43, Oleh Kravchenko 写道: >>>> >>>> >>>>> 9 лист. 2022 р. о 12:25 wangyufen <wangyufen@huawei.com> написав(ла): >>>>> >>>>> >>>>> 在 2022/11/9 17:39, Oleh Kravchenko 写道: >>>>> >>>>>>> -static void el15203000_remove(struct spi_device *spi) >>>>>>> >>>>>> Is remove() callback from struct spi_driver deprecated? >>>>>> >>>>> It is not that remove() callback is deprecated, >>>>> it's that after wrapping mutex_destroy() call with devm_add_action_or_reset(), >>>>> remove() callback is unnecessary here. >>>>> >>>> When remove() is called, the memory allocated by devm_*() is valid. >>>> So what you try to fix here? >>> >>> Fix the &priv->lock used after destroy, for details, please see patch #0 >>> LKML: Wang Yufen: [PATCH 00/13] leds: Fix devm vs. non-devm ordering >> >> It doesn’t make any sense for me. >> You saying that remove() called before devm_* allocation >> if it true then set_brightness_delayed() will crash the system in anyway. >> >> LED device has a parent SPI device; LED device can’t exist without SPI device. >> >> So deallocation order should be next: >> 1. LED device devm_*() >> 2. SPI device remove() > > The allocation order is as follows: > > el15203000_probe() > mutex_init(&priv->lock); > el15203000_probe_dt(priv) > device_for_each_child_node(priv->dev, child) { > ... > led->ldev.brightness_set_blocking = el15203000_set_blocking; > ... > devm_led_classdev_register_ext(priv->dev, &led->ldev, &init_data); > dr = devres_alloc(devm_led_classdev_release, sizeof(*dr), GFP_KERNEL); > <-- dr->node.release = devm_led_classdev_release() > ... > devres_add(parent, dr); > <-- add dr->node to &priv->dev->devres_head > > And the full deallocation order should be this: > > 1. SPI device .remove callback > 2. LED device devm_*() > 3. SPI device deallocation > > spi_unregister_device() > device_del() > bus_remove_device() > device_release_driver_internal() > __device_release_driver() > ... > device_remove() > spi_remove() <-- call el15203000_remove() here, mutex_destroy(&priv->lock), lock destroy > ... > device_unbind_cleanup() > devres_release_all() > release_nodes() > <-- traverse spi->dev->devres_head list and call dr->node.release in sequence. > devm_led_classdev_release() > led_classdev_unregister() > <-- flush set_brightness_work here, before the work flush, set_brightness_work may be sched. > <-- that is el15203000_set_blocking()..-> mutex_lock(&led->priv->lock) is called, > <-- this leads to the priv->lock use after destroy. > put_device(&spi->dev) <-- spi device is deallocation in here > > Hi Oleh, Judging from the deallocation order above, there is a issue that the &priv->lock used after destroy, right? And thanks Wei for the detailed explanation. Thanks, Wang > Regards, > Wei Yongjun >
Hello Wang, 22.11.22 03:10, Wang Yufen пише: > > Hi Oleh, > > Judging from the deallocation order above, there is a issue that the &priv->lock used after destroy, right? > > And thanks Wei for the detailed explanation. > > Thanks, > Wang Sorry, guys. The last russian missile attack made my work impossible. I will try to verify all when I have the ability.
diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c index 7e7b617..9be934e 100644 --- a/drivers/leds/leds-el15203000.c +++ b/drivers/leds/leds-el15203000.c @@ -287,10 +287,16 @@ static int el15203000_probe_dt(struct el15203000 *priv) return ret; } +static void el15203000_mutex_destroy(void *lock) +{ + mutex_destroy(lock); +} + static int el15203000_probe(struct spi_device *spi) { struct el15203000 *priv; size_t count; + int ret; count = device_get_child_node_count(&spi->dev); if (!count) { @@ -312,15 +318,14 @@ static int el15203000_probe(struct spi_device *spi) spi_set_drvdata(spi, priv); + ret = devm_add_action_or_reset(&spi->dev, el15203000_mutex_destroy, + &priv->lock); + if (ret) + return ret; + return el15203000_probe_dt(priv); } -static void el15203000_remove(struct spi_device *spi) -{ - struct el15203000 *priv = spi_get_drvdata(spi); - - mutex_destroy(&priv->lock); -} static const struct of_device_id el15203000_dt_ids[] = { { .compatible = "crane,el15203000", }, @@ -331,7 +336,6 @@ static void el15203000_remove(struct spi_device *spi) static struct spi_driver el15203000_driver = { .probe = el15203000_probe, - .remove = el15203000_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = el15203000_dt_ids,